don't discard iframe children.
[kdelibs.git] / khtml / khtml_part.cpp
blob747210a1385c8575f29bde7617bf896952da6687
1 /* This file is part of the KDE project
3 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4 * 1999 Lars Knoll <knoll@kde.org>
5 * 1999 Antti Koivisto <koivisto@kde.org>
6 * 2000 Simon Hausmann <hausmann@kde.org>
7 * 2000 Stefan Schimanski <1Stein@gmx.de>
8 * 2001-2005 George Staikos <staikos@kde.org>
9 * 2001-2003 Dirk Mueller <mueller@kde.org>
10 * 2000-2005 David Faure <faure@kde.org>
11 * 2002 Apple Computer, Inc.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public License
24 * along with this library; see the file COPYING.LIB. If not, write to
25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
29 //#define SPEED_DEBUG
30 #include "khtml_part.h"
32 #include "ui_htmlpageinfo.h"
34 #include "khtmlviewbar.h"
35 #include "khtml_pagecache.h"
37 #include "dom/dom_string.h"
38 #include "dom/dom_element.h"
39 #include "dom/dom_exception.h"
40 #include "dom/html_document.h"
41 #include "dom/dom2_range.h"
42 #include "dom/html_document.h"
43 #include "editing/editor.h"
44 #include "editing/htmlediting.h"
45 #include "html/html_documentimpl.h"
46 #include "html/html_baseimpl.h"
47 #include "html/html_objectimpl.h"
48 #include "html/html_miscimpl.h"
49 #include "html/html_imageimpl.h"
50 #include "rendering/render_text.h"
51 #include "rendering/render_frames.h"
52 #include "rendering/render_layer.h"
53 #include "misc/htmlhashes.h"
54 #include "misc/loader.h"
55 #include "misc/khtml_partaccessor.h"
56 #include "xml/dom2_eventsimpl.h"
57 #include "xml/dom2_rangeimpl.h"
58 #include "xml/xml_tokenizer.h"
59 #include "css/cssstyleselector.h"
60 #include "css/csshelper.h"
61 using namespace DOM;
63 #include "khtmlview.h"
64 #include <kparts/partmanager.h>
65 #include "ecma/kjs_proxy.h"
66 #include "ecma/kjs_window.h"
67 #include "khtml_settings.h"
68 #include "kjserrordlg.h"
70 #include <kjs/function.h>
71 #include <kjs/interpreter.h>
73 #include <sys/types.h>
74 #include <assert.h>
75 #include <unistd.h>
77 #include <config.h>
79 #include <kstandarddirs.h>
80 #include <kstringhandler.h>
81 #include <kio/job.h>
82 #include <kio/jobuidelegate.h>
83 #include <kio/global.h>
84 #include <kio/netaccess.h>
85 #include <kio/hostinfo_p.h>
86 #include <kprotocolmanager.h>
87 #include <kdebug.h>
88 #include <kicon.h>
89 #include <kiconloader.h>
90 #include <klocale.h>
91 #include <kmessagebox.h>
92 #include <kstandardaction.h>
93 #include <kstandardguiitem.h>
94 #include <kactioncollection.h>
95 #include <kfiledialog.h>
96 #include <kmimetypetrader.h>
97 #include <ktemporaryfile.h>
98 #include <kglobalsettings.h>
99 #include <ktoolinvocation.h>
100 #include <kauthorized.h>
101 #include <kparts/browserinterface.h>
102 #include <kde_file.h>
103 #include <kactionmenu.h>
104 #include <ktoggleaction.h>
105 #include <kcodecaction.h>
106 #include <kselectaction.h>
108 #include <ksslinfodialog.h>
110 #include <kfileitem.h>
111 #include <kurifilter.h>
112 #include <kstatusbar.h>
113 #include <kurllabel.h>
115 #include <QtGui/QClipboard>
116 #include <QtCore/QFile>
117 #include <QtCore/QMetaEnum>
118 #include <QtGui/QTextDocument>
119 #include <QtCore/QDate>
120 #include <QtNetwork/QSslCertificate>
122 #include "khtmlpart_p.h"
123 #include "khtml_iface.h"
124 #include "kpassivepopup.h"
125 #include "kmenu.h"
126 #include "rendering/render_form.h"
127 #include <kwindowsystem.h>
128 #include <kconfiggroup.h>
130 #include "ecma/debugger/debugwindow.h"
132 // SVG
133 #include <svg/SVGDocument.h>
135 bool KHTMLPartPrivate::s_dnsInitialised = false;
137 // DNS prefetch settings
138 static const int sMaxDNSPrefetchPerPage = 42;
139 static const int sDNSPrefetchTimerDelay = 200;
140 static const int sDNSTTLSeconds = 400;
141 static const int sDNSCacheSize = 500;
144 namespace khtml {
146 class PartStyleSheetLoader : public CachedObjectClient
148 public:
149 PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
151 m_part = part;
152 m_cachedSheet = dl->requestStyleSheet(url, QString(), "text/css",
153 true /* "user sheet" */);
154 if (m_cachedSheet)
155 m_cachedSheet->ref( this );
157 virtual ~PartStyleSheetLoader()
159 if ( m_cachedSheet ) m_cachedSheet->deref(this);
161 virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet, const DOM::DOMString &, const DOM::DOMString &/*mimetype*/)
163 if ( m_part )
164 m_part->setUserStyleSheet( sheet.string() );
166 delete this;
168 virtual void error( int, const QString& ) {
169 delete this;
171 QPointer<KHTMLPart> m_part;
172 khtml::CachedCSSStyleSheet *m_cachedSheet;
176 void khtml::ChildFrame::liveConnectEvent(const unsigned long, const QString & event, const KParts::LiveConnectExtension::ArgList & args)
178 if (!m_part || !m_partContainerElement || !m_liveconnect)
179 // hmmm
180 return;
182 QString script;
183 script.sprintf("%s(", event.toLatin1().constData());
185 KParts::LiveConnectExtension::ArgList::const_iterator i = args.begin();
186 const KParts::LiveConnectExtension::ArgList::const_iterator argsBegin = i;
187 const KParts::LiveConnectExtension::ArgList::const_iterator argsEnd = args.end();
189 for ( ; i != argsEnd; ++i) {
190 if (i != argsBegin)
191 script += ",";
192 if ((*i).first == KParts::LiveConnectExtension::TypeString) {
193 script += "\"";
194 script += QString((*i).second).replace('\\', "\\\\").replace('"', "\\\"");
195 script += "\"";
196 } else
197 script += (*i).second;
199 script += ")";
200 kDebug(6050) << script;
202 KHTMLPart * part = qobject_cast<KHTMLPart*>(m_part->parent());
203 if (!part)
204 return;
205 if (!m_jscript)
206 part->framejScript(m_part);
207 if (m_jscript) {
208 // we have a jscript => a part in an iframe
209 KJS::Completion cmp;
210 m_jscript->evaluate(QString(), 1, script, 0L, &cmp);
211 } else
212 part->executeScript(DOM::Node(m_partContainerElement), script);
215 KHTMLFrameList::Iterator KHTMLFrameList::find( const QString &name )
217 Iterator it = begin();
218 const Iterator e = end();
220 for (; it!=e; ++it )
221 if ( (*it)->m_name==name )
222 break;
224 return it;
227 KHTMLPart::KHTMLPart( QWidget *parentWidget, QObject *parent, GUIProfile prof )
228 : KParts::ReadOnlyPart( parent )
230 d = 0;
231 KHTMLGlobal::registerPart( this );
232 setComponentData( KHTMLGlobal::componentData(), false );
233 init( new KHTMLView( this, parentWidget ), prof );
236 KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, GUIProfile prof )
237 : KParts::ReadOnlyPart( parent )
239 d = 0;
240 KHTMLGlobal::registerPart( this );
241 setComponentData( KHTMLGlobal::componentData(), false );
242 assert( view );
243 if (!view->part())
244 view->setPart( this );
245 init( view, prof );
248 void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
250 if ( prof == DefaultGUI )
251 setXMLFile( "khtml.rc" );
252 else if ( prof == BrowserViewGUI )
253 setXMLFile( "khtml_browser.rc" );
255 d = new KHTMLPartPrivate(this, parent());
257 d->m_view = view;
259 if (!parentPart()) {
260 QWidget *widget = new QWidget( view->parentWidget() );
261 widget->setObjectName("khtml_part_widget");
262 QVBoxLayout *layout = new QVBoxLayout( widget );
263 layout->setContentsMargins( 0, 0, 0, 0 );
264 layout->setSpacing( 0 );
265 widget->setLayout( layout );
267 d->m_topViewBar = new KHTMLViewBar( KHTMLViewBar::Top, d->m_view, widget );
268 d->m_bottomViewBar = new KHTMLViewBar( KHTMLViewBar::Bottom, d->m_view, widget );
270 layout->addWidget( d->m_topViewBar );
271 layout->addWidget( d->m_view );
272 layout->addWidget( d->m_bottomViewBar );
273 setWidget( widget );
274 widget->setFocusProxy( d->m_view );
275 } else {
276 setWidget( view );
279 d->m_guiProfile = prof;
280 d->m_extension = new KHTMLPartBrowserExtension( this );
281 d->m_extension->setObjectName( "KHTMLBrowserExtension" );
282 d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
283 d->m_statusBarExtension = new KParts::StatusBarExtension( this );
284 d->m_statusBarPopupLabel = 0L;
285 d->m_openableSuppressedPopups = 0;
287 d->m_paLoadImages = 0;
288 d->m_paDebugScript = 0;
289 d->m_bMousePressed = false;
290 d->m_bRightMousePressed = false;
291 d->m_bCleared = false;
293 if ( prof == BrowserViewGUI ) {
294 d->m_paViewDocument = new KAction( i18n( "View Do&cument Source" ), this );
295 actionCollection()->addAction( "viewDocumentSource", d->m_paViewDocument );
296 connect( d->m_paViewDocument, SIGNAL( triggered( bool ) ), this, SLOT( slotViewDocumentSource() ) );
297 if (!parentPart()) {
298 d->m_paViewDocument->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_U) );
299 d->m_paViewDocument->setShortcutContext( Qt::WidgetWithChildrenShortcut );
302 d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), this );
303 actionCollection()->addAction( "viewFrameSource", d->m_paViewFrame );
304 connect( d->m_paViewFrame, SIGNAL( triggered( bool ) ), this, SLOT( slotViewFrameSource() ) );
305 if (!parentPart()) {
306 d->m_paViewFrame->setShortcut( QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_U) );
307 d->m_paViewFrame->setShortcutContext( Qt::WidgetWithChildrenShortcut );
310 d->m_paViewInfo = new KAction( i18n( "View Document Information" ), this );
311 actionCollection()->addAction( "viewPageInfo", d->m_paViewInfo );
312 if (!parentPart()) {
313 d->m_paViewInfo->setShortcut( QKeySequence(Qt::CTRL+Qt::Key_I) );
314 d->m_paViewInfo->setShortcutContext( Qt::WidgetWithChildrenShortcut );
316 connect( d->m_paViewInfo, SIGNAL( triggered( bool ) ), this, SLOT( slotViewPageInfo() ) );
318 d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), this );
319 actionCollection()->addAction( "saveBackground", d->m_paSaveBackground );
320 connect( d->m_paSaveBackground, SIGNAL( triggered( bool ) ), this, SLOT( slotSaveBackground() ) );
322 d->m_paSaveDocument = actionCollection()->addAction( KStandardAction::SaveAs, "saveDocument",
323 this, SLOT( slotSaveDocument() ) );
324 if ( parentPart() )
325 d->m_paSaveDocument->setShortcuts( KShortcut() ); // avoid clashes
327 d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), this );
328 actionCollection()->addAction( "saveFrame", d->m_paSaveFrame );
329 connect( d->m_paSaveFrame, SIGNAL( triggered( bool ) ), this, SLOT( slotSaveFrame() ) );
330 } else {
331 d->m_paViewDocument = 0;
332 d->m_paViewFrame = 0;
333 d->m_paViewInfo = 0;
334 d->m_paSaveBackground = 0;
335 d->m_paSaveDocument = 0;
336 d->m_paSaveFrame = 0;
339 d->m_paSecurity = new KAction( i18n( "SSL" ), this );
340 actionCollection()->addAction( "security", d->m_paSecurity );
341 connect( d->m_paSecurity, SIGNAL( triggered( bool ) ), this, SLOT( slotSecurity() ) );
343 d->m_paDebugRenderTree = new KAction( i18n( "Print Rendering Tree to STDOUT" ), this );
344 actionCollection()->addAction( "debugRenderTree", d->m_paDebugRenderTree );
345 connect( d->m_paDebugRenderTree, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugRenderTree() ) );
347 d->m_paDebugDOMTree = new KAction( i18n( "Print DOM Tree to STDOUT" ), this );
348 actionCollection()->addAction( "debugDOMTree", d->m_paDebugDOMTree );
349 connect( d->m_paDebugDOMTree, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugDOMTree() ) );
351 d->m_paStopAnimations = new KAction( i18n( "Stop Animated Images" ), this );
352 actionCollection()->addAction( "stopAnimations", d->m_paStopAnimations );
353 connect( d->m_paStopAnimations, SIGNAL( triggered( bool ) ), this, SLOT( slotStopAnimations() ) );
355 d->m_paSetEncoding = new KCodecAction( KIcon("character-set"), i18n( "Set &Encoding" ), this, true );
356 actionCollection()->addAction( "setEncoding", d->m_paSetEncoding );
357 // d->m_paSetEncoding->setDelayed( false );
359 connect( d->m_paSetEncoding, SIGNAL(triggered(const QString&)), this, SLOT( slotSetEncoding(const QString &)));
360 connect( d->m_paSetEncoding, SIGNAL(triggered(KEncodingDetector::AutoDetectScript)), this, SLOT( slotAutomaticDetectionLanguage(KEncodingDetector::AutoDetectScript)));
362 if ( KGlobal::config()->hasGroup( "HTML Settings" ) ) {
363 KConfigGroup config( KGlobal::config(), "HTML Settings" );
365 d->m_autoDetectLanguage = static_cast<KEncodingDetector::AutoDetectScript>(config.readEntry( "AutomaticDetectionLanguage", /*static_cast<int>(language) */0));
366 if (d->m_autoDetectLanguage==KEncodingDetector::None) {
367 const QByteArray name = KGlobal::locale()->encoding().toLower();
368 // kWarning() << "00000000 ";
369 if (name.endsWith("1251")||name.startsWith("koi")||name=="iso-8859-5")
370 d->m_autoDetectLanguage=KEncodingDetector::Cyrillic;
371 else if (name.endsWith("1256")||name=="iso-8859-6")
372 d->m_autoDetectLanguage=KEncodingDetector::Arabic;
373 else if (name.endsWith("1257")||name=="iso-8859-13"||name=="iso-8859-4")
374 d->m_autoDetectLanguage=KEncodingDetector::Baltic;
375 else if (name.endsWith("1250")|| name=="ibm852" || name=="iso-8859-2" || name=="iso-8859-3" )
376 d->m_autoDetectLanguage=KEncodingDetector::CentralEuropean;
377 else if (name.endsWith("1253")|| name=="iso-8859-7" )
378 d->m_autoDetectLanguage=KEncodingDetector::Greek;
379 else if (name.endsWith("1255")|| name=="iso-8859-8" || name=="iso-8859-8-i" )
380 d->m_autoDetectLanguage=KEncodingDetector::Hebrew;
381 else if (name=="jis7" || name=="eucjp" || name=="sjis" )
382 d->m_autoDetectLanguage=KEncodingDetector::Japanese;
383 else if (name.endsWith("1254")|| name=="iso-8859-9" )
384 d->m_autoDetectLanguage=KEncodingDetector::Turkish;
385 else if (name.endsWith("1252")|| name=="iso-8859-1" || name=="iso-8859-15" )
386 d->m_autoDetectLanguage=KEncodingDetector::WesternEuropean;
387 else
388 d->m_autoDetectLanguage=KEncodingDetector::SemiautomaticDetection;
389 // kWarning() << "0000000end " << d->m_autoDetectLanguage << " " << KGlobal::locale()->encodingMib();
391 d->m_paSetEncoding->setCurrentAutoDetectScript(d->m_autoDetectLanguage);
394 d->m_paUseStylesheet = new KSelectAction( i18n( "Use S&tylesheet"), this );
395 actionCollection()->addAction( "useStylesheet", d->m_paUseStylesheet );
396 connect( d->m_paUseStylesheet, SIGNAL( triggered( int ) ), this, SLOT( slotUseStylesheet() ) );
398 if ( prof == BrowserViewGUI ) {
399 d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, "format-font-size-more", i18n( "Enlarge Font" ), this );
400 actionCollection()->addAction( "incFontSizes", d->m_paIncZoomFactor );
401 connect(d->m_paIncZoomFactor, SIGNAL(triggered(bool)), SLOT( slotIncFontSizeFast() ));
402 d->m_paIncZoomFactor->setWhatsThis( i18n( "Enlarge Font<br /><br />"
403 "Make the font in this window bigger. "
404 "Click and hold down the mouse button for a menu with all available font sizes." ) );
406 d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, "format-font-size-less", i18n( "Shrink Font" ), this );
407 actionCollection()->addAction( "decFontSizes", d->m_paDecZoomFactor );
408 connect(d->m_paDecZoomFactor, SIGNAL(triggered(bool)), SLOT( slotDecFontSizeFast() ));
409 d->m_paDecZoomFactor->setWhatsThis( i18n( "Shrink Font<br /><br />"
410 "Make the font in this window smaller. "
411 "Click and hold down the mouse button for a menu with all available font sizes." ) );
412 if (!parentPart()) {
413 // For framesets, this action also affects frames, so only
414 // the frameset needs to define a shortcut for the action.
416 // TODO: Why also CTRL+=? Because of http://trolltech.com/developer/knowledgebase/524/?
417 // Nobody else does it...
418 d->m_paIncZoomFactor->setShortcut( KShortcut("CTRL++; CTRL+=") );
419 d->m_paDecZoomFactor->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_Minus) );
420 d->m_paIncZoomFactor->setShortcutContext( Qt::WidgetWithChildrenShortcut );
421 d->m_paDecZoomFactor->setShortcutContext( Qt::WidgetWithChildrenShortcut );
425 d->m_paFind = actionCollection()->addAction( KStandardAction::Find, "find", this, SLOT( slotFind() ) );
426 d->m_paFind->setShortcutContext( Qt::WidgetWithChildrenShortcut ); // default context conflicts when splitting konqueror
427 d->m_paFind->setWhatsThis( i18n( "Find text<br /><br />"
428 "Shows a dialog that allows you to find text on the displayed page." ) );
430 d->m_paFindNext = actionCollection()->addAction( KStandardAction::FindNext, "findNext", this, SLOT( slotFindNext() ) );
431 d->m_paFindNext->setShortcutContext( Qt::WidgetWithChildrenShortcut );
432 d->m_paFindNext->setWhatsThis( i18n( "Find next<br /><br />"
433 "Find the next occurrence of the text that you "
434 "have found using the <b>Find Text</b> function" ) );
436 d->m_paFindPrev = actionCollection()->addAction( KStandardAction::FindPrev, "findPrevious",
437 this, SLOT( slotFindPrev() ) );
438 d->m_paFindPrev->setWhatsThis( i18n( "Find previous<br /><br />"
439 "Find the previous occurrence of the text that you "
440 "have found using the <b>Find Text</b> function" ) );
442 d->m_paFindAheadText = new KAction( i18n("Find Text as You Type"), this );
443 actionCollection()->addAction( "findAheadText", d->m_paFindAheadText );
444 d->m_paFindAheadText->setShortcuts( KShortcut( '/' ) );
445 connect( d->m_paFindAheadText, SIGNAL( triggered( bool ) ), this, SLOT( slotFindAheadText()) );
447 d->m_paFindAheadLinks = new KAction( i18n("Find Links as You Type"), this );
448 actionCollection()->addAction( "findAheadLink", d->m_paFindAheadLinks );
449 d->m_paFindAheadLinks->setShortcuts( KShortcut( '\'' ) );
450 connect( d->m_paFindAheadLinks, SIGNAL( triggered( bool ) ), this, SLOT( slotFindAheadLink() ) );
452 d->m_paFindAheadText->setEnabled( false );
453 d->m_paFindAheadLinks->setEnabled( false );
455 if ( parentPart() )
457 d->m_paFind->setShortcuts( KShortcut() ); // avoid clashes
458 d->m_paFindNext->setShortcuts( KShortcut() ); // avoid clashes
459 d->m_paFindPrev->setShortcuts( KShortcut() ); // avoid clashes
460 d->m_paFindAheadText->setShortcuts( KShortcut());
461 d->m_paFindAheadLinks->setShortcuts( KShortcut());
464 d->m_paPrintFrame = new KAction( i18n( "Print Frame..." ), this );
465 actionCollection()->addAction( "printFrame", d->m_paPrintFrame );
466 d->m_paPrintFrame->setIcon( KIcon( "document-print-frame" ) );
467 connect( d->m_paPrintFrame, SIGNAL( triggered( bool ) ), this, SLOT( slotPrintFrame() ) );
468 d->m_paPrintFrame->setWhatsThis( i18n( "Print Frame<br /><br />"
469 "Some pages have several frames. To print only a single frame, click "
470 "on it and then use this function." ) );
472 // Warning: The name selectAll is used hardcoded by some 3rd parties to remove the
473 // shortcut for selectAll so they do not get ambigous shortcuts. Renaming it
474 // will either crash or render useless that workaround. It would be better
475 // to use the name KStandardAction::name(KStandardAction::SelectAll) but we
476 // can't for the same reason.
477 d->m_paSelectAll = actionCollection()->addAction( KStandardAction::SelectAll, "selectAll",
478 this, SLOT( slotSelectAll() ) );
479 d->m_paSelectAll->setShortcutContext( Qt::WidgetWithChildrenShortcut );
480 if ( parentPart() ) // Only the frameset has the shortcut, but the slot uses the current frame.
481 d->m_paSelectAll->setShortcuts( KShortcut() ); // avoid clashes
483 d->m_paToggleCaretMode = new KToggleAction(i18n("Toggle Caret Mode"), this );
484 actionCollection()->addAction( "caretMode", d->m_paToggleCaretMode );
485 d->m_paToggleCaretMode->setShortcut( QKeySequence(Qt::Key_F7) );
486 d->m_paToggleCaretMode->setShortcutContext( Qt::WidgetWithChildrenShortcut );
487 connect( d->m_paToggleCaretMode, SIGNAL( triggered( bool ) ), this, SLOT(slotToggleCaretMode()) );
488 d->m_paToggleCaretMode->setChecked(isCaretMode());
489 if (parentPart())
490 d->m_paToggleCaretMode->setShortcut(KShortcut()); // avoid clashes
492 // set the default java(script) flags according to the current host.
493 d->m_bOpenMiddleClick = d->m_settings->isOpenMiddleClickEnabled();
494 d->m_bBackRightClick = d->m_settings->isBackRightClickEnabled();
495 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
496 setDebugScript( d->m_settings->isJavaScriptDebugEnabled() );
497 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
498 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
500 // Set the meta-refresh flag...
501 d->m_metaRefreshEnabled = d->m_settings->isAutoDelayedActionsEnabled ();
503 KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling();
504 if (ssm == KHTMLSettings::KSmoothScrollingDisabled)
505 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled);
506 else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient)
507 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient);
508 else
509 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled);
511 if (d->m_bDNSPrefetchIsDefault && !onlyLocalReferences()) {
512 KHTMLSettings::KDNSPrefetch dpm = d->m_settings->dnsPrefetch();
513 if (dpm == KHTMLSettings::KDNSPrefetchDisabled)
514 d->m_bDNSPrefetch = DNSPrefetchDisabled;
515 else if (dpm == KHTMLSettings::KDNSPrefetchOnlyWWWAndSLD)
516 d->m_bDNSPrefetch = DNSPrefetchOnlyWWWAndSLD;
517 else
518 d->m_bDNSPrefetch = DNSPrefetchEnabled;
521 if (!KHTMLPartPrivate::s_dnsInitialised && d->m_bDNSPrefetch != DNSPrefetchDisabled) {
522 KIO::HostInfo::setCacheSize( sDNSCacheSize );
523 KIO::HostInfo::setTTL( sDNSTTLSeconds );
524 KHTMLPartPrivate::s_dnsInitialised = true;
527 actionCollection()->associateWidget(view);
529 connect( view, SIGNAL( zoomView( int ) ), SLOT( slotZoomView( int ) ) );
531 connect( this, SIGNAL( completed() ),
532 this, SLOT( updateActions() ) );
533 connect( this, SIGNAL( completed( bool ) ),
534 this, SLOT( updateActions() ) );
535 connect( this, SIGNAL( started( KIO::Job * ) ),
536 this, SLOT( updateActions() ) );
538 connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
539 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
540 connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
541 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
542 connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
543 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
545 connect ( &d->m_progressUpdateTimer, SIGNAL( timeout() ), this, SLOT( slotProgressUpdate() ) );
547 findTextBegin(); //reset find variables
549 connect( &d->m_redirectionTimer, SIGNAL( timeout() ),
550 this, SLOT( slotRedirect() ) );
552 if (QDBusConnection::sessionBus().isConnected()) {
553 new KHTMLPartIface(this); // our "adaptor"
554 for (int i = 1; ; ++i)
555 if (QDBusConnection::sessionBus().registerObject(QString("/KHTML/%1/widget").arg(i), this))
556 break;
557 else if (i == 0xffff)
558 kFatal() << "Something is very wrong in KHTMLPart!";
561 if (prof == BrowserViewGUI && !parentPart())
562 loadPlugins();
564 // "khtml" catalog does not exist, our translations are in kdelibs.
565 // removing this catalog from KGlobal::locale() prevents problems
566 // with changing the language in applications at runtime -Thomas Reitelbach
567 // DF: a better fix would be to set the right catalog name in the KComponentData!
568 KGlobal::locale()->removeCatalog("khtml");
571 KHTMLPart::~KHTMLPart()
573 kDebug(6050) << this;
574 KConfigGroup config( KGlobal::config(), "HTML Settings" );
575 config.writeEntry( "AutomaticDetectionLanguage", int(d->m_autoDetectLanguage) );
577 slotWalletClosed();
578 if (!parentPart()) { // only delete it if the top khtml_part closes
579 removeJSErrorExtension();
580 delete d->m_statusBarPopupLabel;
583 if ( d->m_manager )
585 d->m_manager->setActivePart( 0 );
586 // We specify "this" as parent qobject for d->manager, so no need to delete it.
589 stopAutoScroll();
590 d->m_redirectionTimer.stop();
592 if (!d->m_bComplete)
593 closeUrl();
595 disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
596 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
597 disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
598 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
599 disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
600 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
602 clear();
604 if ( d->m_view )
606 d->m_view->hide();
607 d->m_view->viewport()->hide();
608 d->m_view->m_part = 0;
611 // Have to delete this here since we forward declare it in khtmlpart_p and
612 // at least some compilers won't call the destructor in this case.
613 delete d->m_jsedlg;
614 d->m_jsedlg = 0;
616 if (!parentPart()) // only delete d->m_frame if the top khtml_part closes
617 delete d->m_frame;
618 delete d; d = 0;
619 KHTMLGlobal::deregisterPart( this );
622 bool KHTMLPart::restoreURL( const KUrl &url )
624 kDebug( 6050 ) << url;
626 d->m_redirectionTimer.stop();
629 * That's not a good idea as it will call closeUrl() on all
630 * child frames, preventing them from further loading. This
631 * method gets called from restoreState() in case of a full frameset
632 * restoral, and restoreState() calls closeUrl() before restoring
633 * anyway.
634 kDebug( 6050 ) << "closing old URL";
635 closeUrl();
638 d->m_bComplete = false;
639 d->m_bLoadEventEmitted = false;
640 d->m_workingURL = url;
642 // set the java(script) flags according to the current host.
643 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
644 setDebugScript( KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
645 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host());
646 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host());
648 setUrl(url);
650 d->m_restoreScrollPosition = true;
651 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
652 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
654 KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &)));
656 emit started( 0L );
658 return true;
661 bool KHTMLPartPrivate::isLocalAnchorJump( const KUrl& url )
663 return url.hasRef() && urlcmp( url.url(), q->url().url(),
664 KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment );
667 void KHTMLPartPrivate::executeAnchorJump( const KUrl& url, bool lockHistory )
669 // Note: we want to emit openUrlNotify first thing, to make the history capture the old state.
670 if (!lockHistory)
671 emit m_extension->openUrlNotify();
673 if ( !q->gotoAnchor( url.encodedHtmlRef()) )
674 q->gotoAnchor( url.htmlRef() );
676 q->setUrl(url);
677 emit m_extension->setLocationBarUrl( url.prettyUrl() );
680 bool KHTMLPart::openUrl( const KUrl &url )
682 kDebug( 6050 ) << this << "opening" << url;
684 d->m_redirectionTimer.stop();
686 // check to see if this is an "error://" URL. This is caused when an error
687 // occurs before this part was loaded (e.g. KonqRun), and is passed to
688 // khtmlpart so that it can display the error.
689 if ( url.protocol() == "error" && url.hasSubUrl() ) {
690 closeUrl();
692 if( d->m_bJScriptEnabled ) {
693 d->m_statusBarText[BarOverrideText].clear();
694 d->m_statusBarText[BarDefaultText].clear();
698 * The format of the error url is that two variables are passed in the query:
699 * error = int kio error code, errText = QString error text from kio
700 * and the URL where the error happened is passed as a sub URL.
702 KUrl::List urls = KUrl::split( url );
703 //kDebug(6050) << "Handling error URL. URL count:" << urls.count();
705 if ( urls.count() > 1 ) {
706 KUrl mainURL = urls.first();
707 int error = mainURL.queryItem( "error" ).toInt();
708 // error=0 isn't a valid error code, so 0 means it's missing from the URL
709 if ( error == 0 ) error = KIO::ERR_UNKNOWN;
710 QString errorText = mainURL.queryItem( "errText" );
711 urls.pop_front();
712 d->m_workingURL = KUrl::join( urls );
713 //kDebug(6050) << "Emitting fixed URL " << d->m_workingURL.prettyUrl();
714 emit d->m_extension->setLocationBarUrl( d->m_workingURL.prettyUrl() );
715 htmlError( error, errorText, d->m_workingURL );
716 return true;
720 if (!parentPart()) { // only do it for toplevel part
721 QString host = url.isLocalFile() ? "localhost" : url.host();
722 QString userAgent = KProtocolManager::userAgentForHost(host);
723 if (userAgent != KProtocolManager::userAgentForHost(QString())) {
724 if (!d->m_statusBarUALabel) {
725 d->m_statusBarUALabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
726 d->m_statusBarUALabel->setFixedHeight(KHTMLGlobal::iconLoader()->currentSize(KIconLoader::Small));
727 d->m_statusBarUALabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
728 d->m_statusBarUALabel->setUseCursor(false);
729 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarUALabel, 0, false);
730 d->m_statusBarUALabel->setPixmap(SmallIcon("preferences-web-browser-identification"));
732 d->m_statusBarUALabel->setToolTip(i18n("The fake user-agent '%1' is in use.", userAgent));
733 } else if (d->m_statusBarUALabel) {
734 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarUALabel);
735 delete d->m_statusBarUALabel;
736 d->m_statusBarUALabel = 0L;
740 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
741 KParts::OpenUrlArguments args( arguments() );
743 // in case
744 // a) we have no frameset (don't test m_frames.count(), iframes get in there)
745 // b) the url is identical with the currently displayed one (except for the htmlref!)
746 // c) the url request is not a POST operation and
747 // d) the caller did not request to reload the page
748 // e) there was no HTTP redirection meanwhile (testcase: webmin's software/tree.cgi)
749 // => we don't reload the whole document and
750 // we just jump to the requested html anchor
751 bool isFrameSet = false;
752 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
753 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
754 isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET);
757 if (isFrameSet && d->isLocalAnchorJump(url) && browserArgs.softReload)
759 QList<khtml::ChildFrame*>::Iterator it = d->m_frames.begin();
760 const QList<khtml::ChildFrame*>::Iterator end = d->m_frames.end();
761 for (; it != end; ++it) {
762 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part );
763 if (part)
765 // We are reloading frames to make them jump into offsets.
766 KParts::OpenUrlArguments partargs( part->arguments() );
767 partargs.setReload( true );
768 part->setArguments( partargs );
770 part->openUrl( part->url() );
772 }/*next it*/
773 return true;
776 if ( url.hasRef() && !isFrameSet )
778 bool noReloadForced = !args.reload() && !browserArgs.redirectedRequest() && !browserArgs.doPost();
779 if ( noReloadForced && d->isLocalAnchorJump(url) )
781 kDebug( 6050 ) << "jumping to anchor. m_url = " << url;
782 setUrl(url);
783 emit started( 0 );
785 if ( !gotoAnchor( url.encodedHtmlRef()) )
786 gotoAnchor( url.htmlRef() );
788 d->m_bComplete = true;
789 if (d->m_doc)
790 d->m_doc->setParsing(false);
792 kDebug( 6050 ) << "completed...";
793 emit completed();
794 return true;
798 // Save offset of viewport when page is reloaded to be compliant
799 // to every other capable browser out there.
800 if (args.reload()) {
801 args.setXOffset( d->m_view->contentsX() );
802 args.setYOffset( d->m_view->contentsY() );
803 setArguments(args);
806 if (!d->m_restored)
807 closeUrl();
809 d->m_restoreScrollPosition = d->m_restored;
810 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
811 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
813 // initializing m_url to the new url breaks relative links when opening such a link after this call and _before_ begin() is called (when the first
814 // data arrives) (Simon)
815 d->m_workingURL = url;
816 if(url.protocol().startsWith( "http" ) && !url.host().isEmpty() &&
817 url.path().isEmpty()) {
818 d->m_workingURL.setPath("/");
819 emit d->m_extension->setLocationBarUrl( d->m_workingURL.prettyUrl() );
821 setUrl(d->m_workingURL);
823 QMap<QString,QString>& metaData = args.metaData();
824 metaData.insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" );
825 metaData.insert("ssl_parent_ip", d->m_ssl_parent_ip);
826 metaData.insert("ssl_parent_cert", d->m_ssl_parent_cert);
827 metaData.insert("PropagateHttpHeader", "true");
828 metaData.insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" );
829 metaData.insert("ssl_activate_warnings", "TRUE" );
830 metaData.insert("cross-domain", toplevelURL().url());
832 if (d->m_restored)
834 metaData.insert("referrer", d->m_pageReferrer);
835 d->m_cachePolicy = KIO::CC_Cache;
837 else if (args.reload())
838 d->m_cachePolicy = KIO::CC_Reload;
839 else
840 d->m_cachePolicy = KProtocolManager::cacheControl();
842 if ( browserArgs.doPost() && (url.protocol().startsWith("http")) )
844 d->m_job = KIO::http_post( url, browserArgs.postData, KIO::HideProgressInfo );
845 d->m_job->addMetaData("content-type", browserArgs.contentType() );
847 else
849 d->m_job = KIO::get( url, KIO::NoReload, KIO::HideProgressInfo );
850 d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
853 if (widget())
854 d->m_job->ui()->setWindow(widget()->topLevelWidget());
855 d->m_job->addMetaData(metaData);
857 connect( d->m_job, SIGNAL( result( KJob* ) ),
858 SLOT( slotFinished( KJob* ) ) );
859 connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
860 SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
861 connect ( d->m_job, SIGNAL( infoMessage( KJob*, const QString&, const QString& ) ),
862 SLOT( slotInfoMessage(KJob*, const QString& ) ) );
863 connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KUrl& ) ),
864 SLOT( slotRedirection(KIO::Job*, const KUrl&) ) );
866 d->m_bComplete = false;
867 d->m_bLoadEventEmitted = false;
869 // delete old status bar msg's from kjs (if it _was_ activated on last URL)
870 if( d->m_bJScriptEnabled ) {
871 d->m_statusBarText[BarOverrideText].clear();
872 d->m_statusBarText[BarDefaultText].clear();
875 // set the javascript flags according to the current url
876 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
877 setDebugScript( KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
878 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host());
879 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host());
882 connect( d->m_job, SIGNAL( speed( KJob*, unsigned long ) ),
883 this, SLOT( slotJobSpeed( KJob*, unsigned long ) ) );
885 connect( d->m_job, SIGNAL( percent( KJob*, unsigned long ) ),
886 this, SLOT( slotJobPercent( KJob*, unsigned long ) ) );
888 connect( d->m_job, SIGNAL( result( KJob* ) ),
889 this, SLOT( slotJobDone( KJob* ) ) );
891 d->m_jobspeed = 0;
893 // If this was an explicit reload and the user style sheet should be used,
894 // do a stat to see whether the stylesheet was changed in the meanwhile.
895 if ( args.reload() && !settings()->userStyleSheet().isEmpty() ) {
896 KUrl url( settings()->userStyleSheet() );
897 KIO::StatJob *job = KIO::stat( url, KIO::HideProgressInfo );
898 connect( job, SIGNAL( result( KJob * ) ),
899 this, SLOT( slotUserSheetStatDone( KJob * ) ) );
901 startingJob( d->m_job );
902 emit started( 0L );
904 return true;
907 bool KHTMLPart::closeUrl()
909 if ( d->m_job )
911 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
912 d->m_job->kill();
913 d->m_job = 0;
916 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
917 HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
919 if ( hdoc->body() && d->m_bLoadEventEmitted ) {
920 hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false );
921 if ( d->m_doc )
922 d->m_doc->updateRendering();
923 d->m_bLoadEventEmitted = false;
927 d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
928 d->m_bLoadEventEmitted = true; // don't want that one either
929 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
931 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
933 KHTMLPageCache::self()->cancelFetch(this);
934 if ( d->m_doc && d->m_doc->parsing() )
936 kDebug( 6050 ) << " was still parsing... calling end ";
937 slotFinishedParsing();
938 d->m_doc->setParsing(false);
941 if ( !d->m_workingURL.isEmpty() )
943 // Aborted before starting to render
944 kDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << url().prettyUrl();
945 emit d->m_extension->setLocationBarUrl( url().prettyUrl() );
948 d->m_workingURL = KUrl();
950 if ( d->m_doc && d->m_doc->docLoader() )
951 khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() );
953 // tell all subframes to stop as well
955 ConstFrameIt it = d->m_frames.constBegin();
956 const ConstFrameIt end = d->m_frames.constEnd();
957 for (; it != end; ++it )
959 if ( (*it)->m_run )
960 (*it)->m_run->abort();
961 if ( !( *it )->m_part.isNull() )
962 ( *it )->m_part->closeUrl();
965 // tell all objects to stop as well
967 ConstFrameIt it = d->m_objects.constBegin();
968 const ConstFrameIt end = d->m_objects.constEnd();
969 for (; it != end; ++it)
971 if ( !( *it )->m_part.isNull() )
972 ( *it )->m_part->closeUrl();
975 // Stop any started redirections as well!! (DA)
976 if ( d && d->m_redirectionTimer.isActive() )
977 d->m_redirectionTimer.stop();
979 // null node activated.
980 emit nodeActivated(Node());
982 // make sure before clear() runs, we pop out of a dialog's message loop
983 if ( d->m_view )
984 d->m_view->closeChildDialogs();
986 return true;
989 DOM::HTMLDocument KHTMLPart::htmlDocument() const
991 if (d->m_doc && d->m_doc->isHTMLDocument())
992 return static_cast<HTMLDocumentImpl*>(d->m_doc);
993 else
994 return static_cast<HTMLDocumentImpl*>(0);
997 DOM::Document KHTMLPart::document() const
999 return d->m_doc;
1002 QString KHTMLPart::documentSource() const
1004 QString sourceStr;
1005 if ( !( url().isLocalFile() ) && KHTMLPageCache::self()->isComplete( d->m_cacheId ) )
1007 QByteArray sourceArray;
1008 QDataStream dataStream( &sourceArray, QIODevice::WriteOnly );
1009 KHTMLPageCache::self()->saveData( d->m_cacheId, &dataStream );
1010 QTextStream stream( sourceArray, QIODevice::ReadOnly );
1011 stream.setCodec( QTextCodec::codecForName( encoding().toLatin1().constData() ) );
1012 sourceStr = stream.readAll();
1013 } else
1015 QString tmpFile;
1016 if( KIO::NetAccess::download( url(), tmpFile, NULL ) )
1018 QFile f( tmpFile );
1019 if ( f.open( QIODevice::ReadOnly ) )
1021 QTextStream stream( &f );
1022 stream.setCodec( QTextCodec::codecForName( encoding().toLatin1().constData() ) );
1023 sourceStr = stream.readAll();
1024 f.close();
1026 KIO::NetAccess::removeTempFile( tmpFile );
1030 return sourceStr;
1034 KParts::BrowserExtension *KHTMLPart::browserExtension() const
1036 return d->m_extension;
1039 KParts::BrowserHostExtension *KHTMLPart::browserHostExtension() const
1041 return d->m_hostExtension;
1044 KHTMLView *KHTMLPart::view() const
1046 return d->m_view;
1049 KHTMLViewBar *KHTMLPart::pTopViewBar() const
1051 if (const_cast<KHTMLPart*>(this)->parentPart())
1052 return const_cast<KHTMLPart*>(this)->parentPart()->pTopViewBar();
1053 return d->m_topViewBar;
1056 KHTMLViewBar *KHTMLPart::pBottomViewBar() const
1058 if (const_cast<KHTMLPart*>(this)->parentPart())
1059 return const_cast<KHTMLPart*>(this)->parentPart()->pBottomViewBar();
1060 return d->m_bottomViewBar;
1063 void KHTMLPart::setStatusMessagesEnabled( bool enable )
1065 d->m_statusMessagesEnabled = enable;
1068 KJS::Interpreter *KHTMLPart::jScriptInterpreter()
1070 KJSProxy *proxy = jScript();
1071 if (!proxy || proxy->paused())
1072 return 0;
1074 return proxy->interpreter();
1077 bool KHTMLPart::statusMessagesEnabled() const
1079 return d->m_statusMessagesEnabled;
1082 void KHTMLPart::setJScriptEnabled( bool enable )
1084 if ( !enable && jScriptEnabled() && d->m_frame && d->m_frame->m_jscript ) {
1085 d->m_frame->m_jscript->clear();
1087 d->m_bJScriptForce = enable;
1088 d->m_bJScriptOverride = true;
1091 bool KHTMLPart::jScriptEnabled() const
1093 if(onlyLocalReferences()) return false;
1095 if ( d->m_bJScriptOverride )
1096 return d->m_bJScriptForce;
1097 return d->m_bJScriptEnabled;
1100 void KHTMLPart::setDNSPrefetch( DNSPrefetch pmode )
1102 d->m_bDNSPrefetch = pmode;
1103 d->m_bDNSPrefetchIsDefault = false;
1106 KHTMLPart::DNSPrefetch KHTMLPart::dnsPrefetch() const
1108 if (onlyLocalReferences())
1109 return DNSPrefetchDisabled;
1110 return d->m_bDNSPrefetch;
1113 void KHTMLPart::setMetaRefreshEnabled( bool enable )
1115 d->m_metaRefreshEnabled = enable;
1118 bool KHTMLPart::metaRefreshEnabled() const
1120 return d->m_metaRefreshEnabled;
1123 // Define this to disable dlopening kjs_html, when directly linking to it.
1124 // You need to edit khtml/Makefile.am to add ./ecma/libkjs_html.la to LIBADD
1125 // and to edit khtml/ecma/Makefile.am to s/kjs_html/libkjs_html/, remove libkhtml from LIBADD,
1126 // remove LDFLAGS line, and replace kde_module with either lib (shared) or noinst (static)
1127 // Also, change the order of "ecma" and "." in khtml's SUBDIRS line.
1128 // OK - that's the default now, use the opposite of the above instructions to go back
1129 // to "dlopening it" - but it breaks exception catching in kjs_binding.cpp
1130 #define DIRECT_LINKAGE_TO_ECMA
1132 #ifdef DIRECT_LINKAGE_TO_ECMA
1133 extern "C" { KJSProxy *kjs_html_init(khtml::ChildFrame * childframe); }
1134 #endif
1136 static bool createJScript(khtml::ChildFrame *frame)
1138 #ifndef DIRECT_LINKAGE_TO_ECMA
1139 KLibrary *lib = KLibLoader::self()->library(QLatin1String("kjs_html"));
1140 if ( !lib ) {
1141 setJScriptEnabled( false );
1142 return false;
1144 // look for plain C init function
1145 void *sym = lib->symbol("kjs_html_init");
1146 if ( !sym ) {
1147 lib->unload();
1148 setJScriptEnabled( false );
1149 return false;
1151 typedef KJSProxy* (*initFunction)(khtml::ChildFrame *);
1152 initFunction initSym = (initFunction) sym;
1153 frame->m_jscript = (*initSym)(d->m_frame);
1154 frame->m_kjs_lib = lib;
1155 #else
1156 frame->m_jscript = kjs_html_init(frame);
1157 #endif
1158 return true;
1161 KJSProxy *KHTMLPart::jScript()
1163 if (!jScriptEnabled()) return 0;
1165 if ( !d->m_frame ) {
1166 KHTMLPart * p = parentPart();
1167 if (!p) {
1168 d->m_frame = new khtml::ChildFrame;
1169 d->m_frame->m_part = this;
1170 } else {
1171 ConstFrameIt it = p->d->m_frames.constBegin();
1172 const ConstFrameIt end = p->d->m_frames.constEnd();
1173 for (; it != end; ++it)
1174 if ((*it)->m_part.operator->() == this) {
1175 d->m_frame = *it;
1176 break;
1179 if ( !d->m_frame )
1180 return 0;
1182 if ( !d->m_frame->m_jscript )
1183 if (!createJScript(d->m_frame))
1184 return 0;
1185 d->m_frame->m_jscript->setDebugEnabled(d->m_bJScriptDebugEnabled);
1187 return d->m_frame->m_jscript;
1190 QVariant KHTMLPart::crossFrameExecuteScript(const QString& target, const QString& script)
1192 KHTMLPart* destpart = this;
1194 QString trg = target.toLower();
1196 if (target == "_top") {
1197 while (destpart->parentPart())
1198 destpart = destpart->parentPart();
1200 else if (target == "_parent") {
1201 if (parentPart())
1202 destpart = parentPart();
1204 else if (target == "_self" || target == "_blank") {
1205 // we always allow these
1207 else {
1208 destpart = findFrame(target);
1209 if (!destpart)
1210 destpart = this;
1213 // easy way out?
1214 if (destpart == this)
1215 return executeScript(DOM::Node(), script);
1217 // now compare the domains
1218 if (destpart->checkFrameAccess(this))
1219 return destpart->executeScript(DOM::Node(), script);
1221 // eww, something went wrong. better execute it in our frame
1222 return executeScript(DOM::Node(), script);
1225 //Enable this to see all JS scripts being executed
1226 //#define KJS_VERBOSE
1228 KJSErrorDlg *KHTMLPart::jsErrorExtension() {
1229 if (!d->m_settings->jsErrorsEnabled()) {
1230 return 0L;
1233 if (parentPart()) {
1234 return parentPart()->jsErrorExtension();
1237 if (!d->m_statusBarJSErrorLabel) {
1238 d->m_statusBarJSErrorLabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
1239 d->m_statusBarJSErrorLabel->setFixedHeight(KIconLoader::global()->currentSize(KIconLoader::Small));
1240 d->m_statusBarJSErrorLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
1241 d->m_statusBarJSErrorLabel->setUseCursor(false);
1242 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarJSErrorLabel, 0, false);
1243 d->m_statusBarJSErrorLabel->setToolTip(i18n("This web page contains coding errors."));
1244 d->m_statusBarJSErrorLabel->setPixmap(SmallIcon("script-error"));
1245 connect(d->m_statusBarJSErrorLabel, SIGNAL(leftClickedUrl()), SLOT(launchJSErrorDialog()));
1246 connect(d->m_statusBarJSErrorLabel, SIGNAL(rightClickedUrl()), SLOT(jsErrorDialogContextMenu()));
1248 if (!d->m_jsedlg) {
1249 d->m_jsedlg = new KJSErrorDlg;
1250 d->m_jsedlg->setURL(url().prettyUrl());
1251 if (KGlobalSettings::showIconsOnPushButtons()) {
1252 d->m_jsedlg->_clear->setIcon(KIcon("edit-clear-locationbar-ltr"));
1253 d->m_jsedlg->_close->setIcon(KIcon("window-close"));
1256 return d->m_jsedlg;
1259 void KHTMLPart::removeJSErrorExtension() {
1260 if (parentPart()) {
1261 parentPart()->removeJSErrorExtension();
1262 return;
1264 if (d->m_statusBarJSErrorLabel != 0) {
1265 d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarJSErrorLabel );
1266 delete d->m_statusBarJSErrorLabel;
1267 d->m_statusBarJSErrorLabel = 0;
1269 delete d->m_jsedlg;
1270 d->m_jsedlg = 0;
1273 void KHTMLPart::disableJSErrorExtension() {
1274 removeJSErrorExtension();
1275 // These two lines are really kind of hacky, and it sucks to do this inside
1276 // KHTML but I don't know of anything that's reasonably easy as an alternative
1277 // right now. It makes me wonder if there should be a more clean way to
1278 // contact all running "KHTML" instance as opposed to Konqueror instances too.
1279 d->m_settings->setJSErrorsEnabled(false);
1280 emit configurationChanged();
1283 void KHTMLPart::jsErrorDialogContextMenu() {
1284 KMenu *m = new KMenu(0L);
1285 m->addAction(i18n("&Hide Errors"), this, SLOT(removeJSErrorExtension()));
1286 m->addAction(i18n("&Disable Error Reporting"), this, SLOT(disableJSErrorExtension()));
1287 m->popup(QCursor::pos());
1290 void KHTMLPart::launchJSErrorDialog() {
1291 KJSErrorDlg *dlg = jsErrorExtension();
1292 if (dlg) {
1293 dlg->show();
1294 dlg->raise();
1298 void KHTMLPart::launchJSConfigDialog() {
1299 QStringList args;
1300 args << "khtml_java_js";
1301 KToolInvocation::kdeinitExec( "kcmshell4", args );
1304 QVariant KHTMLPart::executeScript(const QString& filename, int baseLine, const DOM::Node& n, const QString& script)
1306 #ifdef KJS_VERBOSE
1307 // The script is now printed by KJS's Parser::parse
1308 kDebug(6070) << "executeScript: caller='" << objectName() << "' filename=" << filename << " baseLine=" << baseLine /*<< " script=" << script*/;
1309 #endif
1310 KJSProxy *proxy = jScript();
1312 if (!proxy || proxy->paused())
1313 return QVariant();
1315 //Make sure to initialize the interpreter before creating Completion
1316 (void)proxy->interpreter();
1318 KJS::Completion comp;
1320 QVariant ret = proxy->evaluate(filename, baseLine, script, n, &comp);
1323 * Error handling
1325 if (comp.complType() == KJS::Throw && comp.value()) {
1326 KJSErrorDlg *dlg = jsErrorExtension();
1327 if (dlg) {
1328 QString msg = KJSDebugger::DebugWindow::exceptionToString(
1329 proxy->interpreter()->globalExec(), comp.value());
1330 dlg->addError(i18n("<qt><b>Error</b>: %1: %2</qt>",
1331 Qt::escape(filename), Qt::escape(msg)));
1335 // Handle immediate redirects now (e.g. location='foo')
1336 if ( !d->m_redirectURL.isEmpty() && d->m_delayRedirect == -1 )
1338 kDebug(6070) << "executeScript done, handling immediate redirection NOW";
1339 // Must abort tokenizer, no further script must execute.
1340 khtml::Tokenizer* t = d->m_doc->tokenizer();
1341 if(t)
1342 t->abort();
1343 d->m_redirectionTimer.setSingleShot( true );
1344 d->m_redirectionTimer.start( 0 );
1347 return ret;
1350 QVariant KHTMLPart::executeScript( const QString &script )
1352 return executeScript( DOM::Node(), script );
1355 QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script )
1357 #ifdef KJS_VERBOSE
1358 kDebug(6070) << "caller=" << objectName() << "node=" << n.nodeName().string().toLatin1().constData() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " /* << script */;
1359 #endif
1360 KJSProxy *proxy = jScript();
1362 if (!proxy || proxy->paused())
1363 return QVariant();
1364 (void)proxy->interpreter();//Make sure stuff is initialized
1366 ++(d->m_runningScripts);
1367 KJS::Completion comp;
1368 const QVariant ret = proxy->evaluate( QString(), 1, script, n, &comp );
1369 --(d->m_runningScripts);
1372 * Error handling
1374 if (comp.complType() == KJS::Throw && comp.value()) {
1375 KJSErrorDlg *dlg = jsErrorExtension();
1376 if (dlg) {
1377 QString msg = KJSDebugger::DebugWindow::exceptionToString(
1378 proxy->interpreter()->globalExec(), comp.value());
1379 dlg->addError(i18n("<qt><b>Error</b>: node %1: %2</qt>",
1380 n.nodeName().string(), Qt::escape(msg)));
1384 if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
1385 submitFormAgain();
1387 #ifdef KJS_VERBOSE
1388 kDebug(6070) << "done";
1389 #endif
1390 return ret;
1393 void KHTMLPart::setJavaEnabled( bool enable )
1395 d->m_bJavaForce = enable;
1396 d->m_bJavaOverride = true;
1399 bool KHTMLPart::javaEnabled() const
1401 if (onlyLocalReferences()) return false;
1403 #ifndef Q_WS_QWS
1404 if( d->m_bJavaOverride )
1405 return d->m_bJavaForce;
1406 return d->m_bJavaEnabled;
1407 #else
1408 return false;
1409 #endif
1412 void KHTMLPart::setPluginsEnabled( bool enable )
1414 d->m_bPluginsForce = enable;
1415 d->m_bPluginsOverride = true;
1418 bool KHTMLPart::pluginsEnabled() const
1420 if (onlyLocalReferences()) return false;
1422 if ( d->m_bPluginsOverride )
1423 return d->m_bPluginsForce;
1424 return d->m_bPluginsEnabled;
1427 static int s_DOMTreeIndentLevel = 0;
1429 void KHTMLPart::slotDebugDOMTree()
1431 if ( d->m_doc )
1432 qDebug("%s", d->m_doc->toString().string().toLatin1().constData());
1434 // Now print the contents of the frames that contain HTML
1436 const int indentLevel = s_DOMTreeIndentLevel++;
1438 ConstFrameIt it = d->m_frames.constBegin();
1439 const ConstFrameIt end = d->m_frames.constEnd();
1440 for (; it != end; ++it )
1441 if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
1442 KParts::ReadOnlyPart* const p = ( *it )->m_part;
1443 kDebug(6050) << QString().leftJustified(s_DOMTreeIndentLevel*4,' ') << "FRAME " << p->objectName() << " ";
1444 static_cast<KHTMLPart*>( p )->slotDebugDOMTree();
1446 s_DOMTreeIndentLevel = indentLevel;
1449 void KHTMLPart::slotDebugScript()
1451 if (jScript())
1452 jScript()->showDebugWindow();
1455 void KHTMLPart::slotDebugRenderTree()
1457 #ifndef NDEBUG
1458 if ( d->m_doc ) {
1459 d->m_doc->renderer()->printTree();
1460 // dump out the contents of the rendering & DOM trees
1461 // QString dumps;
1462 // QTextStream outputStream(dumps,QIODevice::WriteOnly);
1463 // d->m_doc->renderer()->layer()->dump( outputStream );
1464 // kDebug() << "dump output:" << "\n" + dumps;
1466 #endif
1469 void KHTMLPart::slotStopAnimations()
1471 stopAnimations();
1474 void KHTMLPart::setAutoloadImages( bool enable )
1476 if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
1477 return;
1479 if ( d->m_doc )
1480 d->m_doc->docLoader()->setAutoloadImages( enable );
1482 unplugActionList( "loadImages" );
1484 if ( enable ) {
1485 delete d->m_paLoadImages;
1486 d->m_paLoadImages = 0;
1488 else if ( !d->m_paLoadImages ) {
1489 d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), this );
1490 actionCollection()->addAction( "loadImages", d->m_paLoadImages );
1491 d->m_paLoadImages->setIcon( KIcon( "image-loading" ) );
1492 connect( d->m_paLoadImages, SIGNAL( triggered( bool ) ), this, SLOT( slotLoadImages() ) );
1495 if ( d->m_paLoadImages ) {
1496 QList<QAction*> lst;
1497 lst.append( d->m_paLoadImages );
1498 plugActionList( "loadImages", lst );
1502 bool KHTMLPart::autoloadImages() const
1504 if ( d->m_doc )
1505 return d->m_doc->docLoader()->autoloadImages();
1507 return true;
1510 void KHTMLPart::clear()
1512 if ( d->m_bCleared )
1513 return;
1515 d->m_bCleared = true;
1517 d->m_bClearing = true;
1520 ConstFrameIt it = d->m_frames.constBegin();
1521 const ConstFrameIt end = d->m_frames.constEnd();
1522 for(; it != end; ++it )
1524 // Stop HTMLRun jobs for frames
1525 if ( (*it)->m_run )
1526 (*it)->m_run->abort();
1531 ConstFrameIt it = d->m_objects.constBegin();
1532 const ConstFrameIt end = d->m_objects.constEnd();
1533 for(; it != end; ++it )
1535 // Stop HTMLRun jobs for objects
1536 if ( (*it)->m_run )
1537 (*it)->m_run->abort();
1542 findTextBegin(); // resets d->m_findNode and d->m_findPos
1543 d->m_mousePressNode = DOM::Node();
1546 if ( d->m_doc )
1548 if (d->m_doc->attached()) //the view may have detached it already
1549 d->m_doc->detach();
1552 // Moving past doc so that onUnload works.
1553 if ( d->m_frame && d->m_frame->m_jscript )
1554 d->m_frame->m_jscript->clear();
1556 // stopping marquees
1557 if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->layer())
1558 d->m_doc->renderer()->layer()->suspendMarquees();
1560 if ( d->m_view )
1561 d->m_view->clear();
1563 // do not dereference the document before the jscript and view are cleared, as some destructors
1564 // might still try to access the document.
1565 if ( d->m_doc ) {
1566 d->m_doc->deref();
1568 d->m_doc = 0;
1570 delete d->m_decoder;
1571 d->m_decoder = 0;
1573 // We don't want to change between parts if we are going to delete all of them anyway
1574 disconnect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ),
1575 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
1577 if (d->m_frames.count())
1579 const KHTMLFrameList frames = d->m_frames;
1580 d->m_frames.clear();
1581 ConstFrameIt it = frames.begin();
1582 const ConstFrameIt end = frames.end();
1583 for(; it != end; ++it )
1585 if ( (*it)->m_part )
1587 partManager()->removePart( (*it)->m_part );
1588 delete (KParts::ReadOnlyPart *)(*it)->m_part;
1590 delete *it;
1593 d->m_suppressedPopupOriginParts.clear();
1595 if (d->m_objects.count())
1597 KHTMLFrameList objects = d->m_objects;
1598 d->m_objects.clear();
1599 ConstFrameIt oi = objects.constBegin();
1600 const ConstFrameIt oiEnd = objects.constEnd();
1602 for (; oi != oiEnd; ++oi )
1604 if ( (*oi)->m_part )
1605 delete (KParts::ReadOnlyPart *)(*oi)->m_part;
1606 delete *oi;
1610 // Listen to part changes again
1611 connect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ),
1612 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
1614 d->clearRedirection();
1615 d->m_redirectLockHistory = true;
1616 d->m_bClearing = false;
1617 d->m_frameNameId = 1;
1618 d->m_bFirstData = true;
1620 d->m_bMousePressed = false;
1622 if (d->editor_context.m_caretBlinkTimer >= 0)
1623 killTimer(d->editor_context.m_caretBlinkTimer);
1624 d->editor_context.reset();
1625 #ifndef QT_NO_CLIPBOARD
1626 connect( qApp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
1627 #endif
1629 d->m_jobPercent = 0;
1631 if ( !d->m_haveEncoding )
1632 d->m_encoding.clear();
1634 d->m_DNSPrefetchQueue.clear();
1635 if (d->m_DNSPrefetchTimer > 0)
1636 killTimer(d->m_DNSPrefetchTimer);
1637 d->m_DNSPrefetchTimer = -1;
1638 d->m_lookedupHosts.clear();
1639 if (d->m_DNSTTLTimer > 0)
1640 killTimer(d->m_DNSTTLTimer);
1641 d->m_DNSTTLTimer = -1;
1642 d->m_numDNSPrefetchedNames = 0;
1644 #ifdef SPEED_DEBUG
1645 d->m_parsetime.restart();
1646 #endif
1649 bool KHTMLPart::openFile()
1651 return true;
1654 DOM::HTMLDocumentImpl *KHTMLPart::docImpl() const
1656 if ( d && d->m_doc && d->m_doc->isHTMLDocument() )
1657 return static_cast<HTMLDocumentImpl*>(d->m_doc);
1658 return 0;
1661 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
1663 if ( d )
1664 return d->m_doc;
1665 return 0;
1668 void KHTMLPart::slotInfoMessage(KJob* kio_job, const QString& msg)
1670 assert(d->m_job == kio_job);
1672 if (!parentPart())
1673 setStatusBarText(msg, BarDefaultText);
1676 void KHTMLPart::setPageSecurity( PageSecurity sec )
1678 emit d->m_extension->setPageSecurity( sec );
1681 void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
1683 assert ( d->m_job == kio_job );
1685 //kDebug( 6050 ) << "slotData: " << data.size();
1686 // The first data ?
1687 if ( !d->m_workingURL.isEmpty() )
1689 //kDebug( 6050 ) << "begin!";
1691 // We must suspend KIO while we're inside begin() because it can cause
1692 // crashes if a window (such as kjsdebugger) goes back into the event loop,
1693 // more data arrives, and begin() gets called again (re-entered).
1694 d->m_job->suspend();
1695 begin( d->m_workingURL, arguments().xOffset(), arguments().yOffset() );
1696 d->m_job->resume();
1698 if (d->m_cachePolicy == KIO::CC_Refresh)
1699 d->m_doc->docLoader()->setCachePolicy(KIO::CC_Verify);
1700 else
1701 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
1703 d->m_workingURL = KUrl();
1705 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
1707 // When the first data arrives, the metadata has just been made available
1708 d->m_httpHeaders = d->m_job->queryMetaData("HTTP-Headers");
1709 time_t cacheCreationDate = d->m_job->queryMetaData("cache-creation-date").toLong();
1710 d->m_doc->docLoader()->setCacheCreationDate(cacheCreationDate);
1712 d->m_pageServices = d->m_job->queryMetaData("PageServices");
1713 d->m_pageReferrer = d->m_job->queryMetaData("referrer");
1714 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
1717 KHTMLPart *p = parentPart();
1718 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
1719 while (p->parentPart()) p = p->parentPart();
1721 p->setPageSecurity( NotCrypted );
1725 setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
1727 // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
1728 d->m_ssl_parent_ip = d->m_job->queryMetaData("ssl_parent_ip");
1729 d->m_ssl_parent_cert = d->m_job->queryMetaData("ssl_parent_cert");
1730 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
1731 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
1732 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
1733 d->m_ssl_protocol_version = d->m_job->queryMetaData("ssl_protocol_version");
1734 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
1735 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
1736 d->m_ssl_cert_errors = d->m_job->queryMetaData("ssl_cert_errors");
1738 // Check for charset meta-data
1739 QString qData = d->m_job->queryMetaData("charset");
1740 if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
1741 d->m_encoding = qData;
1744 // Support for http-refresh
1745 qData = d->m_job->queryMetaData("http-refresh");
1746 if( !qData.isEmpty())
1747 d->m_doc->processHttpEquiv("refresh", qData);
1749 // DISABLED: Support Content-Location per section 14.14 of RFC 2616.
1750 // See BR# 51185,BR# 82747
1752 QString baseURL = d->m_job->queryMetaData ("content-location");
1753 if (!baseURL.isEmpty())
1754 d->m_doc->setBaseURL(KUrl( d->m_doc->completeURL(baseURL) ));
1757 // Support for Content-Language
1758 QString language = d->m_job->queryMetaData("content-language");
1759 if (!language.isEmpty())
1760 d->m_doc->setContentLanguage(language);
1762 if ( !url().isLocalFile() )
1764 // Support for http last-modified
1765 d->m_lastModified = d->m_job->queryMetaData("modified");
1767 else
1768 d->m_lastModified.clear(); // done on-demand by lastModified()
1771 KHTMLPageCache::self()->addData(d->m_cacheId, data);
1772 write( data.data(), data.size() );
1774 if (d->m_frame && d->m_frame->m_jscript)
1775 d->m_frame->m_jscript->dataReceived();
1779 void KHTMLPart::slotRestoreData(const QByteArray &data )
1781 // The first data ?
1782 if ( !d->m_workingURL.isEmpty() )
1784 long saveCacheId = d->m_cacheId;
1785 QString savePageReferrer = d->m_pageReferrer;
1786 QString saveEncoding = d->m_encoding;
1787 begin( d->m_workingURL, arguments().xOffset(), arguments().yOffset() );
1788 d->m_encoding = saveEncoding;
1789 d->m_pageReferrer = savePageReferrer;
1790 d->m_cacheId = saveCacheId;
1791 d->m_workingURL = KUrl();
1794 //kDebug( 6050 ) << data.size();
1795 write( data.data(), data.size() );
1797 if (data.size() == 0)
1799 //kDebug( 6050 ) << "<<end of data>>";
1800 // End of data.
1801 if (d->m_doc && d->m_doc->parsing())
1802 end(); //will emit completed()
1806 void KHTMLPart::showError( KJob* job )
1808 kDebug(6050) << "d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
1809 << " d->m_bCleared=" << d->m_bCleared;
1811 if (job->error() == KIO::ERR_NO_CONTENT)
1812 return;
1814 if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
1815 job->uiDelegate()->showErrorMessage();
1816 else
1818 htmlError( job->error(), job->errorText(), d->m_workingURL );
1822 // This is a protected method, placed here because of it's relevance to showError
1823 void KHTMLPart::htmlError( int errorCode, const QString& text, const KUrl& reqUrl )
1825 kDebug(6050) << "errorCode" << errorCode << "text" << text;
1826 // make sure we're not executing any embedded JS
1827 bool bJSFO = d->m_bJScriptForce;
1828 bool bJSOO = d->m_bJScriptOverride;
1829 d->m_bJScriptForce = false;
1830 d->m_bJScriptOverride = true;
1831 begin();
1833 QString errorName, techName, description;
1834 QStringList causes, solutions;
1836 QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
1837 QDataStream stream(raw);
1839 stream >> errorName >> techName >> description >> causes >> solutions;
1841 QString url, protocol, datetime;
1842 url = Qt::escape( reqUrl.prettyUrl() );
1843 protocol = reqUrl.protocol();
1844 datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
1845 KLocale::LongDate );
1847 QString filename( KStandardDirs::locate( "data", "khtml/error.html" ) );
1848 QFile file( filename );
1849 bool isOpened = file.open( QIODevice::ReadOnly );
1850 if ( !isOpened )
1851 kWarning(6050) << "Could not open error html template:" << filename;
1853 QString html = QString( QLatin1String( file.readAll() ) );
1855 html.replace( QLatin1String( "TITLE" ), i18n( "Error: %1 - %2", errorName, url ) );
1856 html.replace( QLatin1String( "DIRECTION" ), QApplication::isRightToLeft() ? "rtl" : "ltr" );
1857 html.replace( QLatin1String( "ICON_PATH" ), KIconLoader::global()->iconPath( "dialog-warning", -KIconLoader::SizeHuge ) );
1859 QString doc = QLatin1String( "<h1>" );
1860 doc += i18n( "The requested operation could not be completed" );
1861 doc += QLatin1String( "</h1><h2>" );
1862 doc += errorName;
1863 doc += QLatin1String( "</h2>" );
1864 if ( !techName.isNull() ) {
1865 doc += QLatin1String( "<h2>" );
1866 doc += i18n( "Technical Reason: " );
1867 doc += techName;
1868 doc += QLatin1String( "</h2>" );
1870 doc += QLatin1String( "<h3>" );
1871 doc += i18n( "Details of the Request:" );
1872 doc += QLatin1String( "</h3><ul><li>" );
1873 doc += i18n( "URL: %1" , url );
1874 doc += QLatin1String( "</li><li>" );
1875 if ( !protocol.isNull() ) {
1876 doc += i18n( "Protocol: %1", protocol );
1877 doc += QLatin1String( "</li><li>" );
1879 doc += i18n( "Date and Time: %1" , datetime );
1880 doc += QLatin1String( "</li><li>" );
1881 doc += i18n( "Additional Information: %1" , text );
1882 doc += QLatin1String( "</li></ul><h3>" );
1883 doc += i18n( "Description:" );
1884 doc += QLatin1String( "</h3><p>" );
1885 doc += description;
1886 doc += QLatin1String( "</p>" );
1887 if ( causes.count() ) {
1888 doc += QLatin1String( "<h3>" );
1889 doc += i18n( "Possible Causes:" );
1890 doc += QLatin1String( "</h3><ul><li>" );
1891 doc += causes.join( "</li><li>" );
1892 doc += QLatin1String( "</li></ul>" );
1894 if ( solutions.count() ) {
1895 doc += QLatin1String( "<h3>" );
1896 doc += i18n( "Possible Solutions:" );
1897 doc += QLatin1String( "</h3><ul><li>" );
1898 doc += solutions.join( "</li><li>" );
1899 doc += QLatin1String( "</li></ul>" );
1902 html.replace( QLatin1String("TEXT"), doc );
1904 write( html );
1905 end();
1907 d->m_bJScriptForce = bJSFO;
1908 d->m_bJScriptOverride = bJSOO;
1910 // make the working url the current url, so that reload works and
1911 // emit the progress signals to advance one step in the history
1912 // (so that 'back' works)
1913 setUrl(reqUrl); // same as d->m_workingURL
1914 d->m_workingURL = KUrl();
1915 emit started( 0 );
1916 emit completed();
1919 void KHTMLPart::slotFinished( KJob * job )
1921 d->m_job = 0L;
1922 d->m_jobspeed = 0L;
1924 if (job->error())
1926 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
1928 // The following catches errors that occur as a result of HTTP
1929 // to FTP redirections where the FTP URL is a directory. Since
1930 // KIO cannot change a redirection request from GET to LISTDIR,
1931 // we have to take care of it here once we know for sure it is
1932 // a directory...
1933 if (job->error() == KIO::ERR_IS_DIRECTORY)
1935 emit canceled( job->errorString() );
1936 emit d->m_extension->openUrlRequest( d->m_workingURL );
1938 else
1940 emit canceled( job->errorString() );
1941 // TODO: what else ?
1942 checkCompleted();
1943 showError( job );
1946 return;
1948 KIO::TransferJob *tjob = ::qobject_cast<KIO::TransferJob*>(job);
1949 if (tjob && tjob->isErrorPage()) {
1950 HTMLPartContainerElementImpl *elt = d->m_frame ?
1951 (HTMLPartContainerElementImpl*)d->m_frame->m_partContainerElement : 0;
1953 if (!elt)
1954 return;
1956 elt->partLoadingErrorNotify();
1957 checkCompleted();
1958 if (d->m_bComplete) return;
1961 //kDebug( 6050 ) << "slotFinished";
1963 KHTMLPageCache::self()->endData(d->m_cacheId);
1964 if (d->m_frame && d->m_frame->m_jscript)
1965 d->m_frame->m_jscript->dataReceived();
1967 if ( d->m_doc && d->m_doc->docLoader()->expireDate() && url().protocol().toLower().startsWith("http"))
1968 KIO::http_update_cache(url(), false, d->m_doc->docLoader()->expireDate());
1970 d->m_workingURL = KUrl();
1972 if ( d->m_doc && d->m_doc->parsing())
1973 end(); //will emit completed()
1976 void KHTMLPart::begin( const KUrl &url, int xOffset, int yOffset )
1978 // No need to show this for a new page until an error is triggered
1979 if (!parentPart()) {
1980 removeJSErrorExtension();
1981 setSuppressedPopupIndicator( false );
1982 d->m_openableSuppressedPopups = 0;
1983 foreach ( KHTMLPart* part, d->m_suppressedPopupOriginParts ) {
1984 if (part) {
1985 KJS::Window *w = KJS::Window::retrieveWindow( part );
1986 if (w)
1987 w->forgetSuppressedWindows();
1992 d->m_bCleared = false;
1993 d->m_cacheId = 0;
1994 d->m_bComplete = false;
1995 d->m_bLoadEventEmitted = false;
1996 clear();
1997 d->m_bCleared = false;
1999 if(url.isValid()) {
2000 QString urlString = url.url();
2001 KHTMLGlobal::vLinks()->insert( urlString );
2002 QString urlString2 = url.prettyUrl();
2003 if ( urlString != urlString2 ) {
2004 KHTMLGlobal::vLinks()->insert( urlString2 );
2008 // ###
2009 //stopParser();
2011 KParts::OpenUrlArguments args = arguments();
2012 args.setXOffset(xOffset);
2013 args.setYOffset(yOffset);
2014 setArguments(args);
2016 d->m_pageReferrer.clear();
2018 KUrl ref(url);
2019 d->m_referrer = ref.protocol().startsWith("http") ? ref.url() : "";
2021 setUrl(url);
2023 bool servedAsXHTML = args.mimeType() == "application/xhtml+xml";
2024 bool servedAsSVG = !servedAsXHTML && args.mimeType() == "image/svg+xml";
2025 KMimeType::Ptr mime = KMimeType::mimeType( args.mimeType(), KMimeType::ResolveAliases );
2026 // We want to make sure text/xml and application/xml are both handled right...
2027 bool servedAsXML = mime && mime->is( "text/xml" );
2028 // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl
2029 if ( servedAsSVG ) {
2030 d->m_doc = DOMImplementationImpl::instance()->createSVGDocument( d->m_view );
2031 } else {
2032 if ( servedAsXML && !servedAsXHTML ) { // any XML derivative, except XHTML
2033 d->m_doc = DOMImplementationImpl::instance()->createXMLDocument( d->m_view );
2034 } else {
2035 d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
2036 // HTML or XHTML? (#86446)
2037 static_cast<HTMLDocumentImpl *>(d->m_doc)->setHTMLRequested( !servedAsXHTML );
2041 d->m_doc->ref();
2042 d->m_doc->setURL( url.url() );
2043 d->m_doc->open( );
2044 if (!d->m_doc->attached())
2045 d->m_doc->attach( );
2046 d->m_doc->setBaseURL( KUrl() );
2047 d->m_doc->docLoader()->setShowAnimations( KHTMLGlobal::defaultHTMLSettings()->showAnimations() );
2048 emit docCreated();
2050 d->m_paUseStylesheet->setItems(QStringList());
2051 d->m_paUseStylesheet->setEnabled( false );
2053 setAutoloadImages( KHTMLGlobal::defaultHTMLSettings()->autoLoadImages() );
2054 QString userStyleSheet = KHTMLGlobal::defaultHTMLSettings()->userStyleSheet();
2055 if ( !userStyleSheet.isEmpty() )
2056 setUserStyleSheet( KUrl( userStyleSheet ) );
2058 d->m_doc->setRestoreState(d->m_extension->browserArguments().docState);
2059 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2061 emit d->m_extension->enableAction( "print", true );
2063 d->m_doc->setParsing(true);
2066 void KHTMLPart::write( const char *data, int len )
2068 if ( !d->m_decoder )
2069 d->m_decoder = createDecoder();
2071 if ( len == -1 )
2072 len = strlen( data );
2074 if ( len == 0 )
2075 return;
2077 QString decoded=d->m_decoder->decodeWithBuffering(data,len);
2079 if(decoded.isEmpty())
2080 return;
2082 if(d->m_bFirstData)
2083 onFirstData();
2085 khtml::Tokenizer* t = d->m_doc->tokenizer();
2086 if(t)
2087 t->write( decoded, true );
2090 // ### KDE5: remove
2091 void KHTMLPart::setAlwaysHonourDoctype( bool b )
2093 d->m_bStrictModeQuirk = !b;
2096 void KHTMLPart::write( const QString &str )
2098 if ( str.isNull() )
2099 return;
2101 if(d->m_bFirstData) {
2102 // determine the parse mode
2103 if (d->m_bStrictModeQuirk) {
2104 d->m_doc->setParseMode( DocumentImpl::Strict );
2105 d->m_bFirstData = false;
2106 } else {
2107 onFirstData();
2110 khtml::Tokenizer* t = d->m_doc->tokenizer();
2111 if(t)
2112 t->write( str, true );
2115 void KHTMLPart::end()
2117 if (d->m_doc) {
2118 if (d->m_decoder)
2120 QString decoded=d->m_decoder->flush();
2121 if (d->m_bFirstData)
2122 onFirstData();
2123 if (!decoded.isEmpty())
2124 write(decoded);
2126 d->m_doc->finishParsing();
2130 void KHTMLPart::onFirstData()
2132 assert( d->m_bFirstData );
2134 // determine the parse mode
2135 d->m_doc->determineParseMode();
2136 d->m_bFirstData = false;
2138 // ### this is still quite hacky, but should work a lot better than the old solution
2139 if (d->m_decoder->visuallyOrdered())
2140 d->m_doc->setVisuallyOrdered();
2141 d->m_doc->recalcStyle( NodeImpl::Force );
2144 bool KHTMLPart::doOpenStream( const QString& mimeType )
2146 KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases);
2147 if ( mime && ( mime->is( "text/html" ) || mime->is( "text/xml" ) ) )
2149 begin( url() );
2150 return true;
2152 return false;
2155 bool KHTMLPart::doWriteStream( const QByteArray& data )
2157 write( data.data(), data.size() );
2158 return true;
2161 bool KHTMLPart::doCloseStream()
2163 end();
2164 return true;
2168 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
2170 if (!d->m_view) return;
2171 d->m_view->paint(p, rc, yOff, more);
2174 void KHTMLPart::stopAnimations()
2176 if ( d->m_doc )
2177 d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
2179 ConstFrameIt it = d->m_frames.constBegin();
2180 const ConstFrameIt end = d->m_frames.constEnd();
2181 for (; it != end; ++it )
2182 if ( !(*it)->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
2183 KParts::ReadOnlyPart* const p = ( *it )->m_part;
2184 static_cast<KHTMLPart*>( p )->stopAnimations();
2188 void KHTMLPart::resetFromScript()
2190 closeUrl();
2191 d->m_bComplete = false;
2192 d->m_bLoadEventEmitted = false;
2193 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2194 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2195 d->m_doc->setParsing(true);
2197 emit started( 0L );
2200 void KHTMLPart::slotFinishedParsing()
2202 d->m_doc->setParsing(false);
2203 d->m_doc->dispatchWindowEvent(EventImpl::KHTML_CONTENTLOADED_EVENT, false, false);
2204 checkEmitLoadEvent();
2205 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2207 if (!d->m_view)
2208 return; // We are probably being destructed.
2210 checkCompleted();
2213 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
2215 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
2216 KHTMLPart* p = this;
2217 while ( p ) {
2218 KHTMLPart* const op = p;
2219 ++(p->d->m_totalObjectCount);
2220 p = p->parentPart();
2221 if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount
2222 && !op->d->m_progressUpdateTimer.isActive()) {
2223 op->d->m_progressUpdateTimer.setSingleShot( true );
2224 op->d->m_progressUpdateTimer.start( 200 );
2230 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
2232 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
2233 KHTMLPart* p = this;
2234 while ( p ) {
2235 KHTMLPart* const op = p;
2236 ++(p->d->m_loadedObjects);
2237 p = p->parentPart();
2238 if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount && op->d->m_jobPercent <= 100
2239 && !op->d->m_progressUpdateTimer.isActive()) {
2240 op->d->m_progressUpdateTimer.setSingleShot( true );
2241 op->d->m_progressUpdateTimer.start( 200 );
2246 checkCompleted();
2249 void KHTMLPart::slotProgressUpdate()
2251 int percent;
2252 if ( d->m_loadedObjects < d->m_totalObjectCount )
2253 percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
2254 else
2255 percent = d->m_jobPercent;
2257 if( d->m_bComplete )
2258 percent = 100;
2260 if (d->m_statusMessagesEnabled) {
2261 if( d->m_bComplete )
2262 emit d->m_extension->infoMessage( i18n( "Page loaded." ));
2263 else if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
2264 emit d->m_extension->infoMessage( i18np( "%1 Image of %2 loaded.", "%1 Images of %2 loaded.", d->m_loadedObjects, d->m_totalObjectCount) );
2267 emit d->m_extension->loadingProgress( percent );
2270 void KHTMLPart::slotJobSpeed( KJob* /*job*/, unsigned long speed )
2272 d->m_jobspeed = speed;
2273 if (!parentPart())
2274 setStatusBarText(jsStatusBarText(), BarOverrideText);
2277 void KHTMLPart::slotJobPercent( KJob* /*job*/, unsigned long percent )
2279 d->m_jobPercent = percent;
2281 if ( !parentPart() ) {
2282 d->m_progressUpdateTimer.setSingleShot( true );
2283 d->m_progressUpdateTimer.start( 0 );
2287 void KHTMLPart::slotJobDone( KJob* /*job*/ )
2289 d->m_jobPercent = 100;
2291 if ( !parentPart() ) {
2292 d->m_progressUpdateTimer.setSingleShot( true );
2293 d->m_progressUpdateTimer.start( 0 );
2297 void KHTMLPart::slotUserSheetStatDone( KJob *_job )
2299 using namespace KIO;
2301 if ( _job->error() ) {
2302 showError( _job );
2303 return;
2306 const UDSEntry entry = dynamic_cast<KIO::StatJob *>( _job )->statResult();
2307 const time_t lastModified = entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, -1 );
2309 // If the filesystem supports modification times, only reload the
2310 // user-defined stylesheet if necessary - otherwise always reload.
2311 if ( lastModified != static_cast<time_t>(-1) ) {
2312 if ( d->m_userStyleSheetLastModified >= lastModified ) {
2313 return;
2315 d->m_userStyleSheetLastModified = lastModified;
2318 setUserStyleSheet( KUrl( settings()->userStyleSheet() ) );
2321 void KHTMLPart::checkCompleted()
2323 // kDebug( 6050 ) << this << name();
2324 // kDebug( 6050 ) << " parsing: " << (d->m_doc && d->m_doc->parsing());
2325 // kDebug( 6050 ) << " complete: " << d->m_bComplete;
2327 // restore the cursor position
2328 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
2330 if (d->m_focusNodeNumber >= 0)
2331 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
2333 d->m_focusNodeRestored = true;
2336 bool bPendingChildRedirection = false;
2337 // Any frame that hasn't completed yet ?
2338 ConstFrameIt it = d->m_frames.constBegin();
2339 const ConstFrameIt end = d->m_frames.constEnd();
2340 for (; it != end; ++it ) {
2341 if ( !(*it)->m_bCompleted )
2343 //kDebug( 6050 ) << this << " is waiting for " << (*it)->m_part;
2344 return;
2346 // Check for frames with pending redirections
2347 if ( (*it)->m_bPendingRedirection )
2348 bPendingChildRedirection = true;
2351 // Any object that hasn't completed yet ?
2353 ConstFrameIt oi = d->m_objects.constBegin();
2354 const ConstFrameIt oiEnd = d->m_objects.constEnd();
2356 for (; oi != oiEnd; ++oi )
2357 if ( !(*oi)->m_bCompleted )
2358 return;
2360 // Are we still parsing - or have we done the completed stuff already ?
2361 if ( d->m_bComplete || (d->m_doc && d->m_doc->parsing()) )
2362 return;
2364 // Still waiting for images/scripts from the loader ?
2365 int requests = 0;
2366 if ( d->m_doc && d->m_doc->docLoader() )
2367 requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
2369 if ( requests > 0 )
2371 //kDebug(6050) << "still waiting for images/scripts from the loader - requests:" << requests;
2372 return;
2375 // OK, completed.
2376 // Now do what should be done when we are really completed.
2377 d->m_bComplete = true;
2378 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
2379 d->m_totalObjectCount = 0;
2380 d->m_loadedObjects = 0;
2382 KHTMLPart* p = this;
2383 while ( p ) {
2384 KHTMLPart* op = p;
2385 p = p->parentPart();
2386 if ( !p && !op->d->m_progressUpdateTimer.isActive()) {
2387 op->d->m_progressUpdateTimer.setSingleShot( true );
2388 op->d->m_progressUpdateTimer.start( 0 );
2392 checkEmitLoadEvent(); // if we didn't do it before
2394 bool pendingAction = false;
2396 if ( !d->m_redirectURL.isEmpty() )
2398 // DA: Do not start redirection for frames here! That action is
2399 // deferred until the parent emits a completed signal.
2400 if ( parentPart() == 0 ) {
2401 //kDebug(6050) << this << " starting redirection timer";
2402 d->m_redirectionTimer.setSingleShot( true );
2403 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
2404 } else {
2405 //kDebug(6050) << this << " not toplevel -> not starting redirection timer. Waiting for slotParentCompleted.";
2408 pendingAction = true;
2410 else if ( bPendingChildRedirection )
2412 pendingAction = true;
2415 // the view will emit completed on our behalf,
2416 // either now or at next repaint if one is pending
2418 //kDebug(6050) << this << " asks the view to emit completed. pendingAction=" << pendingAction;
2419 d->m_view->complete( pendingAction );
2421 // find the alternate stylesheets
2422 QStringList sheets;
2423 if (d->m_doc)
2424 sheets = d->m_doc->availableStyleSheets();
2425 sheets.prepend( i18n( "Automatic Detection" ) );
2426 d->m_paUseStylesheet->setItems( sheets );
2428 d->m_paUseStylesheet->setEnabled( sheets.count() > 2);
2429 if (sheets.count() > 2)
2431 d->m_paUseStylesheet->setCurrentItem(qMax(sheets.indexOf(d->m_sheetUsed), 0));
2432 slotUseStylesheet();
2435 setJSDefaultStatusBarText(QString());
2437 #ifdef SPEED_DEBUG
2438 kDebug(6050) << "DONE: " <<d->m_parsetime.elapsed();
2439 #endif
2442 void KHTMLPart::checkEmitLoadEvent()
2444 if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
2446 ConstFrameIt it = d->m_frames.constBegin();
2447 const ConstFrameIt end = d->m_frames.constEnd();
2448 for (; it != end; ++it )
2449 if ( !(*it)->m_bCompleted ) // still got a frame running -> too early
2450 return;
2452 ConstFrameIt oi = d->m_objects.constBegin();
2453 const ConstFrameIt oiEnd = d->m_objects.constEnd();
2455 for (; oi != oiEnd; ++oi )
2456 if ( !(*oi)->m_bCompleted ) // still got a object running -> too early
2457 return;
2459 // Still waiting for images/scripts from the loader ?
2460 // (onload must happen afterwards, #45607)
2461 // ## This makes this method very similar to checkCompleted. A brave soul should try merging them.
2462 int requests = 0;
2463 if ( d->m_doc && d->m_doc->docLoader() )
2464 requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
2466 if ( requests > 0 )
2467 return;
2469 d->m_bLoadEventEmitted = true;
2470 if (d->m_doc)
2471 d->m_doc->close();
2474 const KHTMLSettings *KHTMLPart::settings() const
2476 return d->m_settings;
2479 #ifndef KDE_NO_COMPAT
2480 KUrl KHTMLPart::baseURL() const
2482 if ( !d->m_doc ) return KUrl();
2484 return d->m_doc->baseURL();
2486 #endif
2488 KUrl KHTMLPart::completeURL( const QString &url )
2490 if ( !d->m_doc ) return KUrl( url );
2492 #if 0
2493 if (d->m_decoder)
2494 return KUrl(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
2495 #endif
2497 return KUrl( d->m_doc->completeURL( url ) );
2500 QString KHTMLPartPrivate::codeForJavaScriptURL(const QString &u)
2502 return KUrl::fromPercentEncoding( u.right( u.length() - 11 ).toUtf8() );
2505 void KHTMLPartPrivate::executeJavascriptURL(const QString &u)
2507 QString script = codeForJavaScriptURL(u);
2508 kDebug( 6050 ) << "script=" << script;
2509 QVariant res = q->executeScript( DOM::Node(), script );
2510 if ( res.type() == QVariant::String ) {
2511 q->begin( q->url() );
2512 q->write( res.toString() );
2513 q->end();
2515 emit q->completed();
2518 bool KHTMLPartPrivate::isJavaScriptURL(const QString& url)
2520 return url.indexOf( QLatin1String( "javascript:" ), 0, Qt::CaseInsensitive ) == 0;
2523 // Called by ecma/kjs_window in case of redirections from Javascript,
2524 // and by xml/dom_docimpl.cpp in case of http-equiv meta refresh.
2525 void KHTMLPart::scheduleRedirection( int delay, const QString &url, bool doLockHistory )
2527 kDebug(6050) << "delay=" << delay << " url=" << url;
2528 kDebug(6050) << "current redirectURL=" << d->m_redirectURL << " with delay " << d->m_delayRedirect;
2530 // In case of JS redirections, some, such as jump to anchors, and javascript:
2531 // evaluation should actually be handled immediately, and not waiting until
2532 // the end of the script. (Besides, we don't want to abort the tokenizer for those)
2533 if ( delay == -1 && d->isInPageURL(url) ) {
2534 d->executeInPageURL(url, doLockHistory);
2535 return;
2538 if( delay < 24*60*60 &&
2539 ( d->m_redirectURL.isEmpty() || delay <= d->m_delayRedirect) ) {
2540 d->m_delayRedirect = delay;
2541 d->m_redirectURL = url;
2542 d->m_redirectLockHistory = doLockHistory;
2543 kDebug(6050) << " d->m_bComplete=" << d->m_bComplete;
2545 if ( d->m_bComplete ) {
2546 d->m_redirectionTimer.stop();
2547 d->m_redirectionTimer.setSingleShot( true );
2548 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
2553 void KHTMLPartPrivate::clearRedirection()
2555 m_delayRedirect = 0;
2556 m_redirectURL.clear();
2557 m_redirectionTimer.stop();
2560 void KHTMLPart::slotRedirect()
2562 kDebug(6050) << this;
2563 QString u = d->m_redirectURL;
2564 KUrl url( u );
2565 d->clearRedirection();
2567 if ( d->isInPageURL(u) )
2569 d->executeInPageURL(u, d->m_redirectLockHistory);
2570 return;
2573 KParts::OpenUrlArguments args;
2574 KUrl cUrl( this->url() );
2576 // handle windows opened by JS
2577 if ( openedByJS() && d->m_opener )
2578 cUrl = d->m_opener->url();
2580 if (!KAuthorized::authorizeUrlAction("redirect", cUrl, url))
2582 kWarning(6050) << "KHTMLPart::scheduleRedirection: Redirection from " << cUrl << " to " << url << " REJECTED!";
2583 emit completed();
2584 return;
2587 if ( urlcmp( u, this->url().url(), KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment) )
2589 args.metaData().insert("referrer", d->m_pageReferrer);
2592 // For javascript and META-tag based redirections:
2593 // - We don't take cross-domain-ness in consideration if we are the
2594 // toplevel frame because the new URL may be in a different domain as the current URL
2595 // but that's ok.
2596 // - If we are not the toplevel frame then we check against the toplevelURL()
2597 if (parentPart())
2598 args.metaData().insert("cross-domain", toplevelURL().url());
2600 KParts::BrowserArguments browserArgs;
2601 browserArgs.setLockHistory( d->m_redirectLockHistory );
2602 // _self: make sure we don't use any <base target=>'s
2604 if ( !urlSelected( u, 0, 0, "_self", args, browserArgs ) ) {
2605 // urlSelected didn't open a url, so emit completed ourselves
2606 emit completed();
2610 void KHTMLPart::slotRedirection(KIO::Job*, const KUrl& url)
2612 // the slave told us that we got redirected
2613 //kDebug( 6050 ) << "redirection by KIO to" << url;
2614 emit d->m_extension->setLocationBarUrl( url.prettyUrl() );
2615 d->m_workingURL = url;
2618 bool KHTMLPart::setEncoding( const QString &name, bool override )
2620 d->m_encoding = name;
2621 d->m_haveEncoding = override;
2623 if( !url().isEmpty() ) {
2624 // reload document
2625 closeUrl();
2626 KUrl oldUrl = url();
2627 setUrl(KUrl());
2628 d->m_restored = true;
2629 openUrl(oldUrl);
2630 d->m_restored = false;
2633 return true;
2636 QString KHTMLPart::encoding() const
2638 if(d->m_haveEncoding && !d->m_encoding.isEmpty())
2639 return d->m_encoding;
2641 if(d->m_decoder && d->m_decoder->encoding())
2642 return QString(d->m_decoder->encoding());
2644 return defaultEncoding();
2647 QString KHTMLPart::defaultEncoding() const
2649 QString encoding = settings()->encoding();
2650 if ( !encoding.isEmpty() )
2651 return encoding;
2652 // HTTP requires the default encoding to be latin1, when neither
2653 // the user nor the page requested a particular encoding.
2654 if ( url().protocol().startsWith( "http" ) )
2655 return "iso-8859-1";
2656 else
2657 return KGlobal::locale()->encoding();
2660 void KHTMLPart::setUserStyleSheet(const KUrl &url)
2662 if ( d->m_doc && d->m_doc->docLoader() )
2663 (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
2666 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
2668 if ( d->m_doc )
2669 d->m_doc->setUserStyleSheet( styleSheet );
2672 bool KHTMLPart::gotoAnchor( const QString &name )
2674 if (!d->m_doc)
2675 return false;
2677 HTMLCollectionImpl *anchors =
2678 new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
2679 anchors->ref();
2680 NodeImpl *n = anchors->namedItem(name);
2681 anchors->deref();
2683 if(!n) {
2684 n = d->m_doc->getElementById( name );
2687 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
2689 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2690 bool quirkyName = !n && !d->m_doc->inStrictMode() && (name.isEmpty() || name.toLower() == "top");
2692 if (quirkyName) {
2693 d->m_view->setContentsPos( d->m_view->contentsX(), 0);
2694 return true;
2695 } else if (!n) {
2696 kDebug(6050) << name << "not found";
2697 return false;
2700 int x = 0, y = 0;
2701 int gox, dummy;
2702 HTMLElementImpl *a = static_cast<HTMLElementImpl *>(n);
2704 a->getUpperLeftCorner(x, y);
2705 if (x <= d->m_view->contentsX())
2706 gox = x - 10;
2707 else {
2708 gox = d->m_view->contentsX();
2709 if ( x + 10 > d->m_view->contentsX()+d->m_view->visibleWidth()) {
2710 a->getLowerRightCorner(x, dummy);
2711 gox = x - d->m_view->visibleWidth() + 10;
2715 d->m_view->setContentsPos(gox, y);
2717 return true;
2720 bool KHTMLPart::nextAnchor()
2722 if (!d->m_doc)
2723 return false;
2724 d->m_view->focusNextPrevNode ( true );
2726 return true;
2729 bool KHTMLPart::prevAnchor()
2731 if (!d->m_doc)
2732 return false;
2733 d->m_view->focusNextPrevNode ( false );
2735 return true;
2738 void KHTMLPart::setStandardFont( const QString &name )
2740 d->m_settings->setStdFontName(name);
2743 void KHTMLPart::setFixedFont( const QString &name )
2745 d->m_settings->setFixedFontName(name);
2748 void KHTMLPart::setURLCursor( const QCursor &c )
2750 d->m_linkCursor = c;
2753 QCursor KHTMLPart::urlCursor() const
2755 return d->m_linkCursor;
2758 bool KHTMLPart::onlyLocalReferences() const
2760 return d->m_onlyLocalReferences;
2763 void KHTMLPart::setOnlyLocalReferences(bool enable)
2765 d->m_onlyLocalReferences = enable;
2768 void KHTMLPartPrivate::setFlagRecursively(
2769 bool KHTMLPartPrivate::*flag, bool value)
2771 // first set it on the current one
2772 this->*flag = value;
2774 // descend into child frames recursively
2776 QList<khtml::ChildFrame*>::Iterator it = m_frames.begin();
2777 const QList<khtml::ChildFrame*>::Iterator itEnd = m_frames.end();
2778 for (; it != itEnd; ++it) {
2779 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part );
2780 if (part)
2781 part->d->setFlagRecursively(flag, value);
2782 }/*next it*/
2784 // do the same again for objects
2786 QList<khtml::ChildFrame*>::Iterator it = m_objects.begin();
2787 const QList<khtml::ChildFrame*>::Iterator itEnd = m_objects.end();
2788 for (; it != itEnd; ++it) {
2789 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part );
2790 if (part)
2791 part->d->setFlagRecursively(flag, value);
2792 }/*next it*/
2796 void KHTMLPart::initCaret()
2798 // initialize caret if not used yet
2799 if (d->editor_context.m_selection.state() == Selection::NONE) {
2800 if (d->m_doc) {
2801 NodeImpl *node;
2802 if (d->m_doc->isHTMLDocument()) {
2803 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
2804 node = htmlDoc->body();
2805 } else
2806 node = d->m_doc;
2807 if (!node) return;
2808 d->editor_context.m_selection.moveTo(Position(node, 0));
2809 d->editor_context.m_selection.setNeedsLayout();
2810 d->editor_context.m_selection.needsCaretRepaint();
2815 static void setCaretInvisibleIfNeeded(KHTMLPart *part)
2817 // On contenteditable nodes, don't hide the caret
2818 if (!khtml::KHTMLPartAccessor::caret(part).caretPos().node()->isContentEditable())
2819 part->setCaretVisible(false);
2822 void KHTMLPart::setCaretMode(bool enable)
2824 kDebug(6200) << enable;
2825 if (isCaretMode() == enable) return;
2826 d->setFlagRecursively(&KHTMLPartPrivate::m_caretMode, enable);
2827 // FIXME: this won't work on frames as expected
2828 if (!isEditable()) {
2829 if (enable) {
2830 initCaret();
2831 setCaretVisible(true);
2832 // view()->ensureCaretVisible();
2833 } else {
2834 setCaretInvisibleIfNeeded(this);
2839 bool KHTMLPart::isCaretMode() const
2841 return d->m_caretMode;
2844 void KHTMLPart::setEditable(bool enable)
2846 if (isEditable() == enable) return;
2847 d->setFlagRecursively(&KHTMLPartPrivate::m_designMode, enable);
2848 // FIXME: this won't work on frames as expected
2849 if (!isCaretMode()) {
2850 if (enable) {
2851 initCaret();
2852 setCaretVisible(true);
2853 // view()->ensureCaretVisible();
2854 } else
2855 setCaretInvisibleIfNeeded(this);
2859 bool KHTMLPart::isEditable() const
2861 return d->m_designMode;
2864 khtml::EditorContext *KHTMLPart::editorContext() const {
2865 return &d->editor_context;
2868 void KHTMLPart::setCaretPosition(DOM::Node node, long offset, bool extendSelection)
2870 #ifndef KHTML_NO_CARET
2871 #if 0
2872 kDebug(6200) << "node: " << node.handle() << " nodeName: "
2873 << node.nodeName().string() << " offset: " << offset
2874 << " extendSelection " << extendSelection;
2875 if (view()->moveCaretTo(node.handle(), offset, !extendSelection))
2876 emitSelectionChanged();
2877 view()->ensureCaretVisible();
2878 #endif
2879 #endif // KHTML_NO_CARET
2882 KHTMLPart::CaretDisplayPolicy KHTMLPart::caretDisplayPolicyNonFocused() const
2884 #if 0
2885 #ifndef KHTML_NO_CARET
2886 return (CaretDisplayPolicy)view()->caretDisplayPolicyNonFocused();
2887 #else // KHTML_NO_CARET
2888 return CaretInvisible;
2889 #endif // KHTML_NO_CARET
2890 #endif
2891 return CaretInvisible;
2894 void KHTMLPart::setCaretDisplayPolicyNonFocused(CaretDisplayPolicy policy)
2896 #if 0
2897 #ifndef KHTML_NO_CARET
2898 view()->setCaretDisplayPolicyNonFocused(policy);
2899 #endif // KHTML_NO_CARET
2900 #endif
2903 void KHTMLPart::setCaretVisible(bool show)
2905 if (show) {
2906 NodeImpl *caretNode = d->editor_context.m_selection.caretPos().node();
2907 if (isCaretMode() || (caretNode && caretNode->isContentEditable())) {
2908 invalidateSelection();
2909 enableFindAheadActions(false);
2911 } else {
2913 if (d->editor_context.m_caretBlinkTimer >= 0)
2914 killTimer(d->editor_context.m_caretBlinkTimer);
2915 clearCaretRectIfNeeded();
2920 void KHTMLPart::findTextBegin()
2922 d->m_find.findTextBegin();
2925 bool KHTMLPart::initFindNode( bool selection, bool reverse, bool fromCursor )
2927 return d->m_find.initFindNode(selection, reverse, fromCursor);
2930 void KHTMLPart::slotFind()
2932 KParts::ReadOnlyPart *part = currentFrame();
2933 if (!part)
2934 return;
2935 if (!part->inherits("KHTMLPart") )
2937 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2938 return;
2940 static_cast<KHTMLPart *>( part )->findText();
2943 void KHTMLPart::slotFindNext()
2945 KParts::ReadOnlyPart *part = currentFrame();
2946 if (!part)
2947 return;
2948 if (!part->inherits("KHTMLPart") )
2950 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2951 return;
2953 static_cast<KHTMLPart *>( part )->findTextNext();
2956 void KHTMLPart::slotFindPrev()
2958 KParts::ReadOnlyPart *part = currentFrame();
2959 if (!part)
2960 return;
2961 if (!part->inherits("KHTMLPart") )
2963 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2964 return;
2966 static_cast<KHTMLPart *>( part )->findTextNext( true ); // reverse
2969 void KHTMLPart::slotFindDone()
2971 // ### remove me
2974 void KHTMLPart::slotFindAheadText()
2976 #ifndef KHTML_NO_TYPE_AHEAD_FIND
2977 KParts::ReadOnlyPart *part = currentFrame();
2978 if (!part)
2979 return;
2980 if (!part->inherits("KHTMLPart") )
2982 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2983 return;
2985 static_cast<KHTMLPart *>( part )->view()->startFindAhead( false );
2986 #endif // KHTML_NO_TYPE_AHEAD_FIND
2989 void KHTMLPart::slotFindAheadLink()
2991 #ifndef KHTML_NO_TYPE_AHEAD_FIND
2992 KParts::ReadOnlyPart *part = currentFrame();
2993 if (!part)
2994 return;
2995 if (!part->inherits("KHTMLPart") )
2997 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2998 return;
3000 static_cast<KHTMLPart *>( part )->view()->startFindAhead( true );
3001 #endif // KHTML_NO_TYPE_AHEAD_FIND
3004 void KHTMLPart::enableFindAheadActions( bool enable )
3006 // only the topmost one has shortcuts
3007 KHTMLPart* p = this;
3008 while( p->parentPart())
3009 p = p->parentPart();
3010 p->d->m_paFindAheadText->setEnabled( enable );
3011 p->d->m_paFindAheadLinks->setEnabled( enable );
3014 void KHTMLPart::slotFindDialogDestroyed()
3016 // ### remove me
3019 void KHTMLPart::findText()
3021 if (parentPart())
3022 return parentPart()->findText();
3023 d->m_find.activate();
3026 void KHTMLPart::findText( const QString &str, long options, QWidget *parent, KFindDialog *findDialog )
3028 if (parentPart())
3029 return parentPart()->findText(str, options, parent, findDialog);
3030 d->m_find.createNewKFind(str, options, parent, findDialog );
3033 // New method
3034 bool KHTMLPart::findTextNext( bool reverse )
3036 if (parentPart())
3037 return parentPart()->findTextNext( reverse );
3038 return d->m_find.findTextNext( reverse );
3041 QString KHTMLPart::selectedTextAsHTML() const
3043 const Selection &sel = d->editor_context.m_selection;
3044 if(!hasSelection()) {
3045 kDebug() << "Selection is not valid. Returning empty selection";
3046 return QString();
3048 if(sel.start().offset() < 0 || sel.end().offset() < 0) {
3049 kDebug() << "invalid values for end/startOffset " << sel.start().offset() << " " << sel.end().offset();
3050 return QString();
3052 DOM::Range r = selection();
3053 if(r.isNull() || r.isDetached())
3054 return QString();
3055 int exceptioncode = 0; //ignore the result
3056 return r.handle()->toHTML(exceptioncode).string();
3059 QString KHTMLPart::selectedText() const
3061 bool hasNewLine = true;
3062 bool seenTDTag = false;
3063 QString text;
3064 const Selection &sel = d->editor_context.m_selection;
3065 DOM::Node n = sel.start().node();
3066 while(!n.isNull()) {
3067 if(n.nodeType() == DOM::Node::TEXT_NODE && n.handle()->renderer()) {
3068 DOM::DOMStringImpl *dstr = static_cast<DOM::TextImpl*>(n.handle())->renderString();
3069 QString str(dstr->s, dstr->l);
3070 if(!str.isEmpty()) {
3071 if(seenTDTag) {
3072 text += " ";
3073 seenTDTag = false;
3075 hasNewLine = false;
3076 if(n == sel.start().node() && n == sel.end().node())
3077 text = str.mid(sel.start().offset(), sel.end().offset() - sel.start().offset());
3078 else if(n == sel.start().node())
3079 text = str.mid(sel.start().offset());
3080 else if(n == sel.end().node())
3081 text += str.left(sel.end().offset());
3082 else
3083 text += str;
3086 else {
3087 // This is our simple HTML -> ASCII transformation:
3088 unsigned short id = n.elementId();
3089 switch(id) {
3090 case ID_TEXTAREA:
3091 text += static_cast<HTMLTextAreaElementImpl*>(n.handle())->value().string();
3092 break;
3093 case ID_INPUT:
3094 if (static_cast<HTMLInputElementImpl*>(n.handle())->inputType() != HTMLInputElementImpl::PASSWORD)
3095 text += static_cast<HTMLInputElementImpl*>(n.handle())->value().string();
3096 break;
3097 case ID_SELECT:
3098 text += static_cast<HTMLSelectElementImpl*>(n.handle())->value().string();
3099 break;
3100 case ID_BR:
3101 text += "\n";
3102 hasNewLine = true;
3103 break;
3104 case ID_IMG:
3105 text += static_cast<HTMLImageElementImpl*>(n.handle())->altText().string();
3106 break;
3107 case ID_TD:
3108 break;
3109 case ID_TH:
3110 case ID_HR:
3111 case ID_OL:
3112 case ID_UL:
3113 case ID_LI:
3114 case ID_DD:
3115 case ID_DL:
3116 case ID_DT:
3117 case ID_PRE:
3118 case ID_LISTING:
3119 case ID_BLOCKQUOTE:
3120 case ID_DIV:
3121 if (!hasNewLine)
3122 text += "\n";
3123 hasNewLine = true;
3124 break;
3125 case ID_P:
3126 case ID_TR:
3127 case ID_H1:
3128 case ID_H2:
3129 case ID_H3:
3130 case ID_H4:
3131 case ID_H5:
3132 case ID_H6:
3133 if (!hasNewLine)
3134 text += "\n";
3135 hasNewLine = true;
3136 break;
3139 if(n == sel.end().node()) break;
3140 DOM::Node next = n.firstChild();
3141 if(next.isNull()) next = n.nextSibling();
3142 while( next.isNull() && !n.parentNode().isNull() ) {
3143 n = n.parentNode();
3144 next = n.nextSibling();
3145 unsigned short id = n.elementId();
3146 switch(id) {
3147 case ID_TD:
3148 seenTDTag = true; //Add two spaces after a td if then followed by text.
3149 break;
3150 case ID_TH:
3151 case ID_HR:
3152 case ID_OL:
3153 case ID_UL:
3154 case ID_LI:
3155 case ID_DD:
3156 case ID_DL:
3157 case ID_DT:
3158 case ID_PRE:
3159 case ID_LISTING:
3160 case ID_BLOCKQUOTE:
3161 case ID_DIV:
3162 seenTDTag = false;
3163 if (!hasNewLine)
3164 text += "\n";
3165 hasNewLine = true;
3166 break;
3167 case ID_P:
3168 case ID_TR:
3169 case ID_H1:
3170 case ID_H2:
3171 case ID_H3:
3172 case ID_H4:
3173 case ID_H5:
3174 case ID_H6:
3175 if (!hasNewLine)
3176 text += "\n";
3177 // text += "\n";
3178 hasNewLine = true;
3179 break;
3183 n = next;
3186 if(text.isEmpty())
3187 return QString();
3189 int start = 0;
3190 int end = text.length();
3192 // Strip leading LFs
3193 while ((start < end) && (text[start] == '\n'))
3194 ++start;
3196 // Strip excessive trailing LFs
3197 while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n'))
3198 --end;
3200 return text.mid(start, end-start);
3203 QString KHTMLPart::simplifiedSelectedText() const
3205 QString text = selectedText();
3206 text.replace(QChar(0xa0), ' ');
3207 // remove leading and trailing whitespace
3208 while (!text.isEmpty() && text[0].isSpace())
3209 text = text.mid(1);
3210 while (!text.isEmpty() && text[text.length()-1].isSpace())
3211 text.truncate(text.length()-1);
3212 return text;
3215 bool KHTMLPart::hasSelection() const
3217 return !d->editor_context.m_selection.isEmpty() && !d->editor_context.m_selection.isCollapsed();
3220 DOM::Range KHTMLPart::selection() const
3222 return d->editor_context.m_selection.toRange();
3225 void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const
3227 DOM::Range r = d->editor_context.m_selection.toRange();
3228 s = r.startContainer();
3229 so = r.startOffset();
3230 e = r.endContainer();
3231 eo = r.endOffset();
3234 void KHTMLPart::setSelection( const DOM::Range &r )
3236 setCaret(r);
3239 const Selection &KHTMLPart::caret() const
3241 return d->editor_context.m_selection;
3244 const Selection &KHTMLPart::dragCaret() const
3246 return d->editor_context.m_dragCaret;
3249 void KHTMLPart::setCaret(const Selection &s, bool closeTyping)
3251 if (d->editor_context.m_selection != s) {
3252 clearCaretRectIfNeeded();
3253 setFocusNodeIfNeeded(s);
3254 d->editor_context.m_selection = s;
3255 notifySelectionChanged(closeTyping);
3259 void KHTMLPart::setDragCaret(const DOM::Selection &dragCaret)
3261 if (d->editor_context.m_dragCaret != dragCaret) {
3262 d->editor_context.m_dragCaret.needsCaretRepaint();
3263 d->editor_context.m_dragCaret = dragCaret;
3264 d->editor_context.m_dragCaret.needsCaretRepaint();
3268 void KHTMLPart::clearSelection()
3270 clearCaretRectIfNeeded();
3271 setFocusNodeIfNeeded(d->editor_context.m_selection);
3272 #ifdef APPLE_CHANGES
3273 d->editor_context.m_selection.clear();
3274 #else
3275 d->editor_context.m_selection.collapse();
3276 #endif
3277 notifySelectionChanged();
3280 void KHTMLPart::invalidateSelection()
3282 clearCaretRectIfNeeded();
3283 d->editor_context.m_selection.setNeedsLayout();
3284 selectionLayoutChanged();
3287 void KHTMLPart::setSelectionVisible(bool flag)
3289 if (d->editor_context.m_caretVisible == flag)
3290 return;
3292 clearCaretRectIfNeeded();
3293 setFocusNodeIfNeeded(d->editor_context.m_selection);
3294 d->editor_context.m_caretVisible = flag;
3295 // notifySelectionChanged();
3298 #if 1
3299 void KHTMLPart::slotClearSelection()
3301 if (!isCaretMode()
3302 && d->editor_context.m_selection.state() != Selection::NONE
3303 && !d->editor_context.m_selection.caretPos().node()->isContentEditable())
3304 clearCaretRectIfNeeded();
3305 bool hadSelection = hasSelection();
3306 #ifdef APPLE_CHANGES
3307 d->editor_context.m_selection.clear();
3308 #else
3309 d->editor_context.m_selection.collapse();
3310 #endif
3311 if (hadSelection)
3312 notifySelectionChanged();
3314 #endif
3316 void KHTMLPart::clearCaretRectIfNeeded()
3318 if (d->editor_context.m_caretPaint) {
3319 d->editor_context.m_caretPaint = false;
3320 d->editor_context.m_selection.needsCaretRepaint();
3324 void KHTMLPart::setFocusNodeIfNeeded(const Selection &s)
3326 if (!xmlDocImpl() || s.state() == Selection::NONE)
3327 return;
3329 NodeImpl *n = s.start().node();
3330 NodeImpl *target = (n && n->isContentEditable()) ? n : 0;
3331 if (!target) {
3332 while (n && n != s.end().node()) {
3333 if (n->isContentEditable()) {
3334 target = n;
3335 break;
3337 n = n->traverseNextNode();
3340 assert(target == 0 || target->isContentEditable());
3342 if (target) {
3343 for ( ; target && !target->isFocusable(); target = target->parentNode())
3345 if (target && target->isMouseFocusable())
3346 xmlDocImpl()->setFocusNode(target);
3347 else if (!target || !target->focused())
3348 xmlDocImpl()->setFocusNode(0);
3352 void KHTMLPart::selectionLayoutChanged()
3354 // kill any caret blink timer now running
3355 if (d->editor_context.m_caretBlinkTimer >= 0) {
3356 killTimer(d->editor_context.m_caretBlinkTimer);
3357 d->editor_context.m_caretBlinkTimer = -1;
3360 // see if a new caret blink timer needs to be started
3361 if (d->editor_context.m_caretVisible
3362 && d->editor_context.m_selection.state() != Selection::NONE) {
3363 d->editor_context.m_caretPaint = isCaretMode()
3364 || d->editor_context.m_selection.caretPos().node()->isContentEditable();
3365 if (d->editor_context.m_caretBlinks && d->editor_context.m_caretPaint)
3366 d->editor_context.m_caretBlinkTimer = startTimer(qApp->cursorFlashTime() / 2);
3367 d->editor_context.m_selection.needsCaretRepaint();
3370 if (d->m_doc)
3371 d->m_doc->updateSelection();
3373 // Always clear the x position used for vertical arrow navigation.
3374 // It will be restored by the vertical arrow navigation code if necessary.
3375 d->editor_context.m_xPosForVerticalArrowNavigation = d->editor_context.NoXPosForVerticalArrowNavigation;
3378 void KHTMLPart::notifySelectionChanged(bool closeTyping)
3380 Editor *ed = d->editor_context.m_editor;
3381 selectionLayoutChanged();
3382 if (ed) {
3383 ed->clearTypingStyle();
3385 if (closeTyping)
3386 khtml::TypingCommand::closeTyping(ed->lastEditCommand());
3389 emitSelectionChanged();
3393 void KHTMLPart::timerEvent(QTimerEvent *e)
3395 if (e->timerId() == d->editor_context.m_caretBlinkTimer) {
3396 if (d->editor_context.m_caretBlinks &&
3397 d->editor_context.m_selection.state() != Selection::NONE) {
3398 d->editor_context.m_caretPaint = !d->editor_context.m_caretPaint;
3399 d->editor_context.m_selection.needsCaretRepaint();
3401 } else if (e->timerId() == d->m_DNSPrefetchTimer) {
3402 // kDebug( 6050 ) << "will lookup " << d->m_DNSPrefetchQueue.head() << d->m_numDNSPrefetchedNames;
3403 KIO::HostInfo::prefetchHost( d->m_DNSPrefetchQueue.dequeue() );
3404 if (d->m_DNSPrefetchQueue.isEmpty()) {
3405 killTimer( d->m_DNSPrefetchTimer );
3406 d->m_DNSPrefetchTimer = -1;
3408 } else if (e->timerId() == d->m_DNSTTLTimer) {
3409 foreach (QString name, d->m_lookedupHosts)
3410 d->m_DNSPrefetchQueue.enqueue(name);
3411 if (d->m_DNSPrefetchTimer <= 0)
3412 d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay );
3416 bool KHTMLPart::mayPrefetchHostname( const QString& name )
3418 if (d->m_bDNSPrefetch == DNSPrefetchDisabled)
3419 return false;
3421 if (d->m_numDNSPrefetchedNames >= sMaxDNSPrefetchPerPage)
3422 return false;
3424 if (d->m_bDNSPrefetch == DNSPrefetchOnlyWWWAndSLD) {
3425 int dots = name.count('.');
3426 if (dots > 2 || (dots == 2 && !name.startsWith("www.")))
3427 return false;
3430 if ( d->m_lookedupHosts.contains( name ) )
3431 return false;
3433 d->m_DNSPrefetchQueue.enqueue( name );
3434 d->m_lookedupHosts.insert( name );
3435 d->m_numDNSPrefetchedNames++;
3437 if (d->m_DNSPrefetchTimer < 1)
3438 d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay );
3439 if (d->m_DNSTTLTimer < 1)
3440 d->m_DNSTTLTimer = startTimer( sDNSTTLSeconds*1000 + 1 );
3442 return true;
3445 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
3447 if (d->editor_context.m_caretPaint)
3448 d->editor_context.m_selection.paintCaret(p, rect);
3451 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
3453 d->editor_context.m_dragCaret.paintCaret(p, rect);
3456 DOM::Editor *KHTMLPart::editor() const {
3457 if (!d->editor_context.m_editor)
3458 const_cast<KHTMLPart *>(this)->d->editor_context.m_editor = new DOM::Editor(const_cast<KHTMLPart *>(this));
3459 return d->editor_context.m_editor;
3462 void KHTMLPart::resetHoverText()
3464 if( !d->m_overURL.isEmpty() ) // Only if we were showing a link
3466 d->m_overURL.clear();
3467 d->m_overURLTarget.clear();
3468 emit onURL( QString() );
3469 // revert to default statusbar text
3470 setStatusBarText(QString(), BarHoverText);
3471 emit d->m_extension->mouseOverInfo(KFileItem());
3475 void KHTMLPart::overURL( const QString &url, const QString &target, bool /*shiftPressed*/ )
3477 KUrl u = completeURL(url);
3479 // special case for <a href="">
3480 if ( url.isEmpty() )
3481 u.setFileName( url );
3483 emit onURL( url );
3485 if ( url.isEmpty() ) {
3486 setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText);
3487 return;
3490 if ( d->isJavaScriptURL(url) ) {
3491 QString jscode = d->codeForJavaScriptURL( url );
3492 jscode = KStringHandler::rsqueeze( jscode, 80 ); // truncate if too long
3493 if (url.startsWith("javascript:window.open"))
3494 jscode += i18n(" (In new window)");
3495 setStatusBarText( Qt::escape( jscode ), BarHoverText );
3496 return;
3499 KFileItem item(u, QString(), KFileItem::Unknown);
3500 emit d->m_extension->mouseOverInfo(item);
3502 QString com;
3504 KMimeType::Ptr typ = KMimeType::findByUrl( u );
3506 if ( typ )
3507 com = typ->comment( u );
3509 if ( !u.isValid() ) {
3510 setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText);
3511 return;
3514 if ( u.isLocalFile() )
3516 // TODO : use KIO::stat() and create a KFileItem out of its result,
3517 // to use KFileItem::statusBarText()
3518 const QString path = QFile::encodeName( u.toLocalFile() );
3520 KDE_struct_stat buff;
3521 bool ok = !KDE::stat( path, &buff );
3523 KDE_struct_stat lbuff;
3524 if (ok) ok = !KDE::lstat( path, &lbuff );
3526 QString text = Qt::escape(u.prettyUrl());
3527 QString text2 = text;
3529 if (ok && S_ISLNK( lbuff.st_mode ) )
3531 QString tmp;
3532 if ( com.isNull() )
3533 tmp = i18n( "Symbolic Link");
3534 else
3535 tmp = i18n("%1 (Link)", com);
3536 char buff_two[1024];
3537 text += " -> ";
3538 int n = readlink ( path.toLocal8Bit().data(), buff_two, 1022);
3539 if (n == -1)
3541 text2 += " ";
3542 text2 += tmp;
3543 setStatusBarText(text2, BarHoverText);
3544 return;
3546 buff_two[n] = 0;
3548 text += buff_two;
3549 text += " ";
3550 text += tmp;
3552 else if ( ok && S_ISREG( buff.st_mode ) )
3554 if (buff.st_size < 1024)
3555 text = i18n("%2 (%1 bytes)", (long) buff.st_size, text2); // always put the URL last, in case it contains '%'
3556 else
3558 float d = (float) buff.st_size/1024.0;
3559 text = i18n("%2 (%1 K)", KGlobal::locale()->formatNumber(d, 2), text2); // was %.2f
3561 text += " ";
3562 text += com;
3564 else if ( ok && S_ISDIR( buff.st_mode ) )
3566 text += " ";
3567 text += com;
3569 else
3571 text += " ";
3572 text += com;
3574 setStatusBarText(text, BarHoverText);
3576 else
3578 QString extra;
3579 if (target.toLower() == "_blank")
3581 extra = i18n(" (In new window)");
3583 else if (!target.isEmpty() &&
3584 (target.toLower() != "_top") &&
3585 (target.toLower() != "_self") &&
3586 (target.toLower() != "_parent"))
3588 KHTMLPart *p = this;
3589 while (p->parentPart())
3590 p = p->parentPart();
3591 if (!p->frameExists(target))
3592 extra = i18n(" (In new window)");
3593 else
3594 extra = i18n(" (In other frame)");
3597 if (u.protocol() == QLatin1String("mailto")) {
3598 QString mailtoMsg /* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
3599 mailtoMsg += i18n("Email to: ") + KUrl::fromPercentEncoding(u.path().toLatin1());
3600 const QStringList queries = u.query().mid(1).split('&');
3601 QStringList::ConstIterator it = queries.begin();
3602 const QStringList::ConstIterator itEnd = queries.end();
3603 for (; it != itEnd; ++it)
3604 if ((*it).startsWith(QLatin1String("subject=")))
3605 mailtoMsg += i18n(" - Subject: ") + KUrl::fromPercentEncoding((*it).mid(8).toLatin1());
3606 else if ((*it).startsWith(QLatin1String("cc=")))
3607 mailtoMsg += i18n(" - CC: ") + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
3608 else if ((*it).startsWith(QLatin1String("bcc=")))
3609 mailtoMsg += i18n(" - BCC: ") + KUrl::fromPercentEncoding((*it).mid(4).toLatin1());
3610 mailtoMsg = Qt::escape(mailtoMsg);
3611 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), QString());
3612 setStatusBarText("<qt>"+mailtoMsg, BarHoverText);
3613 return;
3615 // Is this check necessary at all? (Frerich)
3616 #if 0
3617 else if (u.protocol() == QLatin1String("http")) {
3618 DOM::Node hrefNode = nodeUnderMouse().parentNode();
3619 while (hrefNode.nodeName().string() != QLatin1String("A") && !hrefNode.isNull())
3620 hrefNode = hrefNode.parentNode();
3622 if (!hrefNode.isNull()) {
3623 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
3624 if (!hreflangNode.isNull()) {
3625 QString countryCode = hreflangNode.nodeValue().string().toLower();
3626 // Map the language code to an appropriate country code.
3627 if (countryCode == QLatin1String("en"))
3628 countryCode = QLatin1String("gb");
3629 QString flagImg = QLatin1String("<img src=%1>").arg(
3630 locate("locale", QLatin1String("l10n/")
3631 + countryCode
3632 + QLatin1String("/flag.png")));
3633 emit setStatusBarText(flagImg + u.prettyUrl() + extra);
3637 #endif
3638 setStatusBarText(Qt::escape(u.prettyUrl()) + extra, BarHoverText);
3643 // This executes in the active part on a click or other url selection action in
3644 // that active part.
3646 bool KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target, const KParts::OpenUrlArguments& _args, const KParts::BrowserArguments& _browserArgs )
3648 KParts::OpenUrlArguments args = _args;
3649 KParts::BrowserArguments browserArgs = _browserArgs;
3650 bool hasTarget = false;
3652 QString target = _target;
3653 if ( target.isEmpty() && d->m_doc )
3654 target = d->m_doc->baseTarget();
3655 if ( !target.isEmpty() )
3656 hasTarget = true;
3658 if ( d->isJavaScriptURL(url) )
3660 crossFrameExecuteScript( target, d->codeForJavaScriptURL(url) );
3661 return false;
3664 KUrl cURL = completeURL(url);
3665 // special case for <a href=""> (IE removes filename, mozilla doesn't)
3666 if ( url.isEmpty() )
3667 cURL.setFileName( url ); // removes filename
3669 if ( !cURL.isValid() )
3670 // ### ERROR HANDLING
3671 return false;
3673 kDebug(6050) << this << "complete URL:" << cURL.url() << "target=" << target;
3675 if ( state & Qt::ControlModifier )
3677 browserArgs.setNewTab(true);
3678 emit d->m_extension->createNewWindow( cURL, args, browserArgs );
3679 return true;
3682 if ( button == Qt::LeftButton && ( state & Qt::ShiftModifier ) )
3684 KIO::MetaData metaData;
3685 metaData.insert( "referrer", d->m_referrer );
3686 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), cURL, metaData );
3687 return false;
3690 if (!checkLinkSecurity(cURL,
3691 ki18n( "<qt>This untrusted page links to<br /><b>%1</b>.<br />Do you want to follow the link?</qt>" ),
3692 i18n( "Follow" )))
3693 return false;
3695 browserArgs.frameName = target;
3697 args.metaData().insert("main_frame_request",
3698 parentPart() == 0 ? "TRUE":"FALSE");
3699 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
3700 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
3701 args.metaData().insert("PropagateHttpHeader", "true");
3702 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
3703 args.metaData().insert("ssl_activate_warnings", "TRUE");
3705 if ( hasTarget && target != "_self" && target != "_top" && target != "_blank" && target != "_parent" )
3707 // unknown frame names should open in a new window.
3708 khtml::ChildFrame *frame = recursiveFrameRequest( this, cURL, args, browserArgs, false );
3709 if ( frame )
3711 args.metaData()["referrer"] = d->m_referrer;
3712 requestObject( frame, cURL, args, browserArgs );
3713 return true;
3717 if (!d->m_referrer.isEmpty() && !args.metaData().contains("referrer"))
3718 args.metaData()["referrer"] = d->m_referrer;
3720 if ( button == Qt::NoButton && (state & Qt::ShiftModifier) && (state & Qt::ControlModifier) )
3722 emit d->m_extension->createNewWindow( cURL, args, browserArgs );
3723 return true;
3726 if ( state & Qt::ShiftModifier)
3728 KParts::WindowArgs winArgs;
3729 winArgs.setLowerWindow(true);
3730 emit d->m_extension->createNewWindow( cURL, args, browserArgs, winArgs );
3731 return true;
3734 //If we're asked to open up an anchor in the current URL, in current window,
3735 //merely gotoanchor, and do not reload the new page. Note that this does
3736 //not apply if the URL is the same page, but without a ref
3737 if (cURL.hasRef() && (!hasTarget || target == "_self"))
3739 if (d->isLocalAnchorJump(cURL))
3741 d->executeAnchorJump(cURL, browserArgs.lockHistory() );
3742 return false; // we jumped, but we didn't open a URL
3746 if ( !d->m_bComplete && !hasTarget )
3747 closeUrl();
3749 view()->viewport()->unsetCursor();
3750 emit d->m_extension->openUrlRequest( cURL, args, browserArgs );
3751 return true;
3754 void KHTMLPart::slotViewDocumentSource()
3756 KUrl currentUrl(this->url());
3757 bool isTempFile = false;
3758 if (!(currentUrl.isLocalFile()) && KHTMLPageCache::self()->isComplete(d->m_cacheId))
3760 KTemporaryFile sourceFile;
3761 sourceFile.setSuffix(defaultExtension());
3762 sourceFile.setAutoRemove(false);
3763 if (sourceFile.open())
3765 QDataStream stream ( &sourceFile );
3766 KHTMLPageCache::self()->saveData(d->m_cacheId, &stream);
3767 currentUrl = KUrl();
3768 currentUrl.setPath(sourceFile.fileName());
3769 isTempFile = true;
3773 (void) KRun::runUrl( currentUrl, QLatin1String("text/plain"), view(), isTempFile );
3776 void KHTMLPart::slotViewPageInfo()
3778 Ui_KHTMLInfoDlg ui;
3780 QDialog *dlg = new QDialog(0);
3781 dlg->setAttribute(Qt::WA_DeleteOnClose);
3782 dlg->setObjectName("KHTML Page Info Dialog");
3783 ui.setupUi(dlg);
3785 ui._close->setGuiItem(KStandardGuiItem::close());
3787 connect(ui._close, SIGNAL(clicked()), dlg, SLOT(accept()));
3788 if (d->m_doc)
3789 ui._title->setText(d->m_doc->title().string());
3791 // If it's a frame, set the caption to "Frame Information"
3792 if ( parentPart() && d->m_doc && d->m_doc->isHTMLDocument() ) {
3793 dlg->setWindowTitle(i18n("Frame Information"));
3796 QString editStr;
3798 if (!d->m_pageServices.isEmpty())
3799 editStr = i18n(" <a href=\"%1\">[Properties]</a>", d->m_pageServices);
3801 QString squeezedURL = KStringHandler::csqueeze( url().prettyUrl(), 80 );
3802 ui._url->setText("<a href=\"" + url().url() + "\">" + squeezedURL + "</a>" + editStr);
3803 if (lastModified().isEmpty())
3805 ui._lastModified->hide();
3806 ui._lmLabel->hide();
3808 else
3809 ui._lastModified->setText(lastModified());
3811 const QString& enc = encoding();
3812 if (enc.isEmpty()) {
3813 ui._eLabel->hide();
3814 ui._encoding->hide();
3815 } else {
3816 ui._encoding->setText(enc);
3818 /* populate the list view now */
3819 const QStringList headers = d->m_httpHeaders.split("\n");
3821 QStringList::ConstIterator it = headers.begin();
3822 const QStringList::ConstIterator itEnd = headers.end();
3824 for (; it != itEnd; ++it) {
3825 const QStringList header = (*it).split(QRegExp(":[ ]+"));
3826 if (header.count() != 2)
3827 continue;
3828 QTreeWidgetItem *item = new QTreeWidgetItem(ui._headers);
3829 item->setText(0, header[0]);
3830 item->setText(1, header[1]);
3833 dlg->show();
3834 /* put no code here */
3838 void KHTMLPart::slotViewFrameSource()
3840 KParts::ReadOnlyPart *frame = currentFrame();
3841 if ( !frame )
3842 return;
3844 KUrl url = frame->url();
3845 bool isTempFile = false;
3846 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
3848 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
3850 if (KHTMLPageCache::self()->isComplete(cacheId))
3852 KTemporaryFile sourceFile;
3853 sourceFile.setSuffix(defaultExtension());
3854 sourceFile.setAutoRemove(false);
3855 if (sourceFile.open())
3857 QDataStream stream ( &sourceFile );
3858 KHTMLPageCache::self()->saveData(cacheId, &stream);
3859 url = KUrl();
3860 url.setPath(sourceFile.fileName());
3861 isTempFile = true;
3866 (void) KRun::runUrl( url, QLatin1String("text/plain"), view(), isTempFile );
3869 KUrl KHTMLPart::backgroundURL() const
3871 // ### what about XML documents? get from CSS?
3872 if (!d->m_doc || !d->m_doc->isHTMLDocument())
3873 return KUrl();
3875 QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
3877 return KUrl( url(), relURL );
3880 void KHTMLPart::slotSaveBackground()
3882 KIO::MetaData metaData;
3883 metaData["referrer"] = d->m_referrer;
3884 KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save Background Image As"), backgroundURL(), metaData );
3887 void KHTMLPart::slotSaveDocument()
3889 KUrl srcURL( url() );
3891 if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() )
3892 srcURL.setFileName( "index" + defaultExtension() );
3894 KIO::MetaData metaData;
3895 // Referre unknown?
3896 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, "text/html", d->m_cacheId );
3899 void KHTMLPart::slotSecurity()
3901 // kDebug( 6050 ) << "Meta Data:" << endl
3902 // << d->m_ssl_peer_cert_subject
3903 // << endl
3904 // << d->m_ssl_peer_cert_issuer
3905 // << endl
3906 // << d->m_ssl_cipher
3907 // << endl
3908 // << d->m_ssl_cipher_desc
3909 // << endl
3910 // << d->m_ssl_cipher_version
3911 // << endl
3912 // << d->m_ssl_good_from
3913 // << endl
3914 // << d->m_ssl_good_until
3915 // << endl
3916 // << d->m_ssl_cert_state
3917 // << endl;
3919 //### reenable with new signature
3920 #if 0
3921 KSSLInfoDialog *kid = new KSSLInfoDialog(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
3923 const QStringList sl = d->m_ssl_peer_chain.split('\n', QString::SkipEmptyParts);
3924 QList<QSslCertificate> certChain;
3925 bool certChainOk = d->m_ssl_in_use;
3926 if (certChainOk) {
3927 foreach (const QString &s, sl) {
3928 certChain.append(QSslCertificate(s.toAscii())); //or is it toLocal8Bit or whatever?
3929 if (certChain.last().isNull()) {
3930 certChainOk = false;
3931 break;
3935 if (certChainOk) {
3936 kid->setup(certChain,
3937 d->m_ssl_peer_ip,
3938 url().url(),
3939 d->m_ssl_cipher,
3940 d->m_ssl_cipher_desc,
3941 d->m_ssl_cipher_version,
3942 d->m_ssl_cipher_used_bits.toInt(),
3943 d->m_ssl_cipher_bits.toInt(),
3944 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt());
3946 kid->exec();
3947 //the dialog deletes itself on close
3948 #endif
3950 KSSLInfoDialog *kid = new KSSLInfoDialog(0);
3951 //### This is boilerplate code and it's copied from SlaveInterface.
3952 QStringList sl = d->m_ssl_peer_chain.split('\x01', QString::SkipEmptyParts);
3953 QList<QSslCertificate> certChain;
3954 bool decodedOk = true;
3955 foreach (const QString &s, sl) {
3956 certChain.append(QSslCertificate(s.toAscii())); //or is it toLocal8Bit or whatever?
3957 if (certChain.last().isNull()) {
3958 decodedOk = false;
3959 break;
3963 if (decodedOk || true /*H4X*/) {
3964 kid->setSslInfo(certChain,
3965 d->m_ssl_peer_ip,
3966 url().url(),
3967 d->m_ssl_protocol_version,
3968 d->m_ssl_cipher,
3969 d->m_ssl_cipher_used_bits.toInt(),
3970 d->m_ssl_cipher_bits.toInt(),
3971 KSSLInfoDialog::errorsFromString(d->m_ssl_cert_errors));
3972 kDebug(7024) << "Showing SSL Info dialog";
3973 kid->exec();
3974 kDebug(7024) << "SSL Info dialog closed";
3975 } else {
3976 KMessageBox::information(0, i18n("The peer SSL certificate chain "
3977 "appears to be corrupt."),
3978 i18n("SSL"));
3982 void KHTMLPart::slotSaveFrame()
3984 KParts::ReadOnlyPart *frame = currentFrame();
3985 if ( !frame )
3986 return;
3988 KUrl srcURL( frame->url() );
3990 if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() )
3991 srcURL.setFileName( "index" + defaultExtension() );
3993 KIO::MetaData metaData;
3994 // Referrer unknown?
3995 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save Frame As" ), srcURL, metaData, "text/html" );
3998 void KHTMLPart::slotSetEncoding(const QString &enc)
4000 d->m_autoDetectLanguage=KEncodingDetector::None;
4001 setEncoding( enc, true);
4004 void KHTMLPart::slotAutomaticDetectionLanguage(KEncodingDetector::AutoDetectScript scri)
4006 d->m_autoDetectLanguage=scri;
4007 setEncoding( QString(), false );
4010 void KHTMLPart::slotUseStylesheet()
4012 if (d->m_doc)
4014 bool autoselect = (d->m_paUseStylesheet->currentItem() == 0);
4015 d->m_sheetUsed = autoselect ? QString() : d->m_paUseStylesheet->currentText();
4016 d->m_doc->updateStyleSelector();
4020 void KHTMLPart::updateActions()
4022 bool frames = false;
4024 QList<khtml::ChildFrame*>::ConstIterator it = d->m_frames.constBegin();
4025 const QList<khtml::ChildFrame*>::ConstIterator end = d->m_frames.constEnd();
4026 for (; it != end; ++it )
4027 if ( (*it)->m_type == khtml::ChildFrame::Frame )
4029 frames = true;
4030 break;
4033 if (d->m_paViewFrame)
4034 d->m_paViewFrame->setEnabled( frames );
4035 if (d->m_paSaveFrame)
4036 d->m_paSaveFrame->setEnabled( frames );
4038 if ( frames )
4039 d->m_paFind->setText( i18n( "&Find in Frame..." ) );
4040 else
4041 d->m_paFind->setText( i18n( "&Find..." ) );
4043 KParts::Part *frame = 0;
4045 if ( frames )
4046 frame = currentFrame();
4048 bool enableFindAndSelectAll = true;
4050 if ( frame )
4051 enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
4053 d->m_paFind->setEnabled( enableFindAndSelectAll );
4054 d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
4056 bool enablePrintFrame = false;
4058 if ( frame )
4060 QObject *ext = KParts::BrowserExtension::childObject( frame );
4061 if ( ext )
4062 enablePrintFrame = ext->metaObject()->indexOfSlot( "print()" ) != -1;
4065 d->m_paPrintFrame->setEnabled( enablePrintFrame );
4067 QString bgURL;
4069 // ### frames
4070 if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
4071 bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
4073 if (d->m_paSaveBackground)
4074 d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
4076 if ( d->m_paDebugScript )
4077 d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
4080 KParts::LiveConnectExtension *KHTMLPart::liveConnectExtension( const DOM::NodeImpl *frame) {
4081 const ConstFrameIt end = d->m_objects.constEnd();
4082 for(ConstFrameIt it = d->m_objects.constBegin(); it != end; ++it )
4083 if ((*it)->m_partContainerElement == frame)
4084 return (*it)->m_liveconnect;
4085 return 0L;
4088 bool KHTMLPart::requestFrame( DOM::HTMLPartContainerElementImpl *frame, const QString &url,
4089 const QString &frameName, const QStringList &params, bool isIFrame )
4091 //kDebug( 6050 ) << this << " requestFrame( ..., " << url << ", " << frameName << " )";
4092 FrameIt it = d->m_frames.find( frameName );
4093 if ( it == d->m_frames.end() )
4095 khtml::ChildFrame * child = new khtml::ChildFrame;
4096 //kDebug( 6050 ) << "inserting new frame into frame map " << frameName;
4097 child->m_name = frameName;
4098 it = d->m_frames.insert( d->m_frames.end(), child );
4101 (*it)->m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
4102 (*it)->m_partContainerElement = frame;
4103 (*it)->m_params = params;
4105 // Support for <frame src="javascript:string">
4106 if ( d->isJavaScriptURL(url) )
4108 if ( processObjectRequest(*it, KUrl("about:blank"), QString("text/html") ) ) {
4109 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>((*it)->m_part));
4111 // See if we want to replace content with javascript: output..
4112 QVariant res = p->executeScript( DOM::Node(),
4113 d->codeForJavaScriptURL(url) );
4114 if ( res.type() == QVariant::String && p->d->m_redirectURL.isEmpty() ) {
4115 p->begin();
4116 // We recreated the document, so propagate domain again.
4117 d->propagateInitialDomainTo( p );
4118 p->write( res.toString() );
4119 p->end();
4121 return true;
4123 return false;
4125 KUrl u = url.isEmpty() ? KUrl() : completeURL( url );
4126 return requestObject( *it, u );
4129 QString KHTMLPart::requestFrameName()
4131 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
4134 bool KHTMLPart::requestObject( DOM::HTMLPartContainerElementImpl *frame, const QString &url,
4135 const QString &serviceType, const QStringList &params )
4137 //kDebug( 6005 ) << this << "frame=" << frame;
4138 khtml::ChildFrame *child = new khtml::ChildFrame;
4139 FrameIt it = d->m_objects.insert( d->m_objects.end(), child );
4140 (*it)->m_partContainerElement = frame;
4141 (*it)->m_type = khtml::ChildFrame::Object;
4142 (*it)->m_params = params;
4144 KParts::OpenUrlArguments args;
4145 args.setMimeType(serviceType);
4146 if (!requestObject( *it, completeURL( url ), args ) && !(*it)->m_run) {
4147 (*it)->m_bCompleted = true;
4148 return false;
4150 return true;
4153 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KUrl &url, const KParts::OpenUrlArguments &_args,
4154 const KParts::BrowserArguments& browserArgs )
4156 if (!checkLinkSecurity(url))
4158 kDebug(6005) << this << "checkLinkSecurity refused";
4159 return false;
4161 if ( child->m_bPreloaded )
4163 kDebug(6005) << "preload";
4164 if ( child->m_partContainerElement && child->m_part )
4165 child->m_partContainerElement->setWidget( child->m_part->widget() );
4167 child->m_bPreloaded = false;
4168 return true;
4171 //kDebug(6005) << "child=" << child << "child->m_part=" << child->m_part;
4173 KParts::OpenUrlArguments args( _args );
4175 if ( child->m_run )
4176 child->m_run->abort();
4178 if ( child->m_part && !args.reload() && urlcmp( child->m_part->url().url(), url.url(), KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment ) )
4179 args.setMimeType(child->m_serviceType);
4181 child->m_browserArgs = browserArgs;
4182 child->m_args = args;
4183 child->m_args.setReload(d->m_cachePolicy == KIO::CC_Reload);
4184 child->m_serviceName.clear();
4185 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
4186 child->m_args.metaData()["referrer"] = d->m_referrer;
4188 child->m_args.metaData().insert("PropagateHttpHeader", "true");
4189 child->m_args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
4190 child->m_args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
4191 child->m_args.metaData().insert("main_frame_request",
4192 parentPart() == 0 ? "TRUE":"FALSE");
4193 child->m_args.metaData().insert("ssl_was_in_use",
4194 d->m_ssl_in_use ? "TRUE":"FALSE");
4195 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
4196 child->m_args.metaData().insert("cross-domain", toplevelURL().url());
4198 // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
4199 if ((url.isEmpty() || url.url() == "about:blank") && args.mimeType().isEmpty())
4200 args.setMimeType(QLatin1String("text/html"));
4202 if ( args.mimeType().isEmpty() ) {
4203 kDebug(6050) << "Running new KHTMLRun for" << this << "and child=" << child;
4204 child->m_run = new KHTMLRun( this, child, url, child->m_args, child->m_browserArgs, true );
4205 d->m_bComplete = false; // ensures we stop it in checkCompleted...
4206 return false;
4207 } else {
4208 return processObjectRequest( child, url, args.mimeType() );
4212 void KHTMLPart::childLoadFailure( khtml::ChildFrame *child )
4214 child->m_bCompleted = true;
4215 if ( child->m_partContainerElement )
4216 child->m_partContainerElement->partLoadingErrorNotify();
4218 checkCompleted();
4221 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KUrl &_url, const QString &mimetype )
4223 //kDebug( 6050 ) << "trying to create part for" << mimetype;
4225 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
4226 // by an emitting frame part (emit openUrlRequest( blahurl, ... ) . A few lines below we delete the part
4227 // though -> the reference becomes invalid -> crash is likely
4228 KUrl url( _url );
4230 // khtmlrun called us this way to indicate a loading error
4231 if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
4233 childLoadFailure(child);
4234 return true;
4237 if (child->m_bNotify)
4239 child->m_bNotify = false;
4240 if ( !child->m_browserArgs.lockHistory() )
4241 emit d->m_extension->openUrlNotify();
4244 if ( child->m_serviceType != mimetype || !child->m_part || (child->m_run && child->m_run->serverSuggestsSave()))
4246 // We often get here if we didn't know the mimetype in advance, and had to rely
4247 // on KRun to figure it out. In this case, we let the element check if it wants to
4248 // handle this mimetype itself, for e.g. images.
4249 if ( child->m_partContainerElement &&
4250 child->m_partContainerElement->mimetypeHandledInternally(mimetype) ) {
4251 child->m_bCompleted = true;
4252 checkCompleted();
4253 return true;
4256 // Before attempting to load a part, check if the user wants that.
4257 // Many don't like getting ZIP files embedded.
4258 // However we don't want to ask for flash and other plugin things..
4259 if ( child->m_type != khtml::ChildFrame::Object && child->m_type != khtml::ChildFrame::IFrame )
4261 QString suggestedFileName;
4262 int disposition = 0;
4263 if ( child->m_run ) {
4264 suggestedFileName = child->m_run->suggestedFileName();
4265 disposition = (child->m_run->serverSuggestsSave()) ? KParts::BrowserRun::AttachmentDisposition : KParts::BrowserRun::InlineDisposition;
4268 KParts::BrowserRun::AskSaveResult res = KParts::BrowserRun::askEmbedOrSave(
4269 url, mimetype, suggestedFileName, disposition );
4270 switch( res ) {
4271 case KParts::BrowserRun::Save:
4272 KHTMLPopupGUIClient::saveURL( widget(), i18n( "Save As" ), url, child->m_args.metaData(), QString(), 0, suggestedFileName );
4273 // fall-through
4274 case KParts::BrowserRun::Cancel:
4275 child->m_bCompleted = true;
4276 checkCompleted();
4277 return true; // done
4278 default: // Open
4279 break;
4283 KMimeType::Ptr mime = KMimeType::mimeType(mimetype);
4284 if (mime) {
4285 // If KHTMLPart can handle the frame, then let's force using it, even
4286 // if the normally preferred part is another one, so that cross-frame
4287 // scripting can work.
4288 if (mime->is("text/html")
4289 || mime->is("application/xml")) { // this includes xhtml and svg
4290 child->m_serviceName = "khtml";
4294 QStringList dummy; // the list of servicetypes handled by the part is now unused.
4295 KParts::ReadOnlyPart *part = createPart( d->m_view->viewport(), this, mimetype, child->m_serviceName, dummy, child->m_params );
4297 if ( !part )
4299 childLoadFailure(child);
4300 return false;
4303 part->setObjectName( child->m_name );
4305 //CRITICAL STUFF
4306 if ( child->m_part )
4308 if (!qobject_cast<KHTMLPart*>(child->m_part) && child->m_jscript)
4309 child->m_jscript->clear();
4310 partManager()->removePart( (KParts::ReadOnlyPart *)child->m_part );
4311 delete (KParts::ReadOnlyPart *)child->m_part;
4312 if (child->m_liveconnect) {
4313 disconnect(child->m_liveconnect, SIGNAL(partEvent(const unsigned long, const QString &, const KParts::LiveConnectExtension::ArgList &)), child, SLOT(liveConnectEvent(const unsigned long, const QString&, const KParts::LiveConnectExtension::ArgList &)));
4314 child->m_liveconnect = 0L;
4318 child->m_serviceType = mimetype;
4319 if ( child->m_partContainerElement && part->widget() )
4320 child->m_partContainerElement->setWidget( part->widget() );
4322 if ( child->m_type != khtml::ChildFrame::Object )
4323 partManager()->addPart( part, false );
4324 // else
4325 // kDebug(6005) << "AH! NO FRAME!!!!!";
4327 child->m_part = part;
4329 if (qobject_cast<KHTMLPart*>(part)) {
4330 static_cast<KHTMLPart*>(part)->d->m_frame = child;
4331 } else if (child->m_partContainerElement) {
4332 child->m_liveconnect = KParts::LiveConnectExtension::childObject(part);
4333 if (child->m_liveconnect)
4334 connect(child->m_liveconnect, SIGNAL(partEvent(const unsigned long, const QString &, const KParts::LiveConnectExtension::ArgList &)), child, SLOT(liveConnectEvent(const unsigned long, const QString&, const KParts::LiveConnectExtension::ArgList &)));
4336 KParts::StatusBarExtension *sb = KParts::StatusBarExtension::childObject(part);
4337 if (sb)
4338 sb->setStatusBar( d->m_statusBarExtension->statusBar() );
4340 connect( part, SIGNAL( started( KIO::Job *) ),
4341 this, SLOT( slotChildStarted( KIO::Job *) ) );
4342 connect( part, SIGNAL( completed() ),
4343 this, SLOT( slotChildCompleted() ) );
4344 connect( part, SIGNAL( completed(bool) ),
4345 this, SLOT( slotChildCompleted(bool) ) );
4346 connect( part, SIGNAL( setStatusBarText( const QString & ) ),
4347 this, SIGNAL( setStatusBarText( const QString & ) ) );
4348 if ( part->inherits( "KHTMLPart" ) )
4350 connect( this, SIGNAL( completed() ),
4351 part, SLOT( slotParentCompleted() ) );
4352 connect( this, SIGNAL( completed(bool) ),
4353 part, SLOT( slotParentCompleted() ) );
4354 // As soon as the child's document is created, we need to set its domain
4355 // (but we do so only once, so it can't be simply done in the child)
4356 connect( part, SIGNAL( docCreated() ),
4357 this, SLOT( slotChildDocCreated() ) );
4360 child->m_extension = KParts::BrowserExtension::childObject( part );
4362 if ( child->m_extension )
4364 connect( child->m_extension, SIGNAL( openUrlNotify() ),
4365 d->m_extension, SIGNAL( openUrlNotify() ) );
4367 connect( child->m_extension, SIGNAL( openUrlRequestDelayed( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments & ) ),
4368 this, SLOT( slotChildURLRequest( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments & ) ) );
4370 connect( child->m_extension, SIGNAL( createNewWindow( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments &, const KParts::WindowArgs &, KParts::ReadOnlyPart ** ) ),
4371 d->m_extension, SIGNAL( createNewWindow( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments & , const KParts::WindowArgs &, KParts::ReadOnlyPart **) ) );
4373 connect( child->m_extension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)),
4374 d->m_extension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) );
4375 connect( child->m_extension, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)),
4376 d->m_extension, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) );
4378 connect( child->m_extension, SIGNAL( infoMessage( const QString & ) ),
4379 d->m_extension, SIGNAL( infoMessage( const QString & ) ) );
4381 connect( child->m_extension, SIGNAL( requestFocus( KParts::ReadOnlyPart * ) ),
4382 this, SLOT( slotRequestFocus( KParts::ReadOnlyPart * ) ) );
4384 child->m_extension->setBrowserInterface( d->m_extension->browserInterface() );
4387 else if ( child->m_partContainerElement && child->m_part &&
4388 child->m_partContainerElement->childWidget() != child->m_part->widget() )
4389 child->m_partContainerElement->setWidget( child->m_part->widget() );
4391 checkEmitLoadEvent();
4392 // Some JS code in the load event may have destroyed the part
4393 // In that case, abort
4394 if ( !child->m_part )
4395 return false;
4397 if ( child->m_bPreloaded )
4399 if ( child->m_partContainerElement && child->m_part )
4400 child->m_partContainerElement->setWidget( child->m_part->widget() );
4402 child->m_bPreloaded = false;
4403 return true;
4406 child->m_args.setReload(d->m_cachePolicy == KIO::CC_Reload);
4408 // make sure the part has a way to find out about the mimetype.
4409 // we actually set it in child->m_args in requestObject already,
4410 // but it's useless if we had to use a KHTMLRun instance, as the
4411 // point the run object is to find out exactly the mimetype.
4412 child->m_args.setMimeType(mimetype);
4414 // if not a frame set child as completed
4415 child->m_bCompleted = child->m_type == khtml::ChildFrame::Object;
4417 if ( child->m_part ) {
4418 child->m_part->setArguments( child->m_args );
4420 if ( child->m_extension ) {
4421 child->m_extension->setBrowserArguments( child->m_browserArgs );
4424 if(url.protocol() == "javascript" || url.url() == "about:blank") {
4425 if (!child->m_part->inherits("KHTMLPart"))
4426 return false;
4428 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(child->m_part));
4430 p->begin();
4431 if (d->m_doc && p->d->m_doc)
4432 p->d->m_doc->setBaseURL(d->m_doc->baseURL());
4434 // We may have to re-propagate the domain here if we go here due to navigation
4435 d->propagateInitialDomainTo(p);
4437 if (!url.url().startsWith("about:")) {
4438 p->write(url.path());
4439 } else {
4440 p->setUrl(url);
4441 // we need a body element. testcase: <iframe id="a"></iframe><script>alert(a.document.body);</script>
4442 p->write("<HTML><TITLE></TITLE><BODY></BODY></HTML>");
4444 p->end();
4445 return true;
4447 else if ( !url.isEmpty() )
4449 //kDebug( 6050 ) << "opening" << url << "in frame" << child->m_part;
4450 bool b = child->m_part->openUrl( url );
4451 if (child->m_bCompleted)
4452 checkCompleted();
4453 return b;
4455 else
4457 child->m_bCompleted = true;
4458 checkCompleted();
4459 return true;
4463 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget,
4464 QObject *parent, const QString &mimetype,
4465 QString &serviceName, QStringList &serviceTypes,
4466 const QStringList &params )
4468 QString constr;
4469 if ( !serviceName.isEmpty() )
4470 constr.append( QString::fromLatin1( "DesktopEntryName == '%1'" ).arg( serviceName ) );
4472 KService::List offers = KMimeTypeTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr );
4474 if ( offers.isEmpty() ) {
4475 int pos = mimetype.indexOf( "-plugin" );
4476 if (pos < 0)
4477 return 0L;
4478 QString stripped_mime = mimetype.left( pos );
4479 offers = KMimeTypeTrader::self()->query( stripped_mime, "KParts/ReadOnlyPart", constr );
4480 if ( offers.isEmpty() )
4481 return 0L;
4484 KService::List::ConstIterator it = offers.constBegin();
4485 const KService::List::ConstIterator itEnd = offers.constEnd();
4486 for ( ; it != itEnd; ++it )
4488 KService::Ptr service = (*it);
4490 KPluginLoader loader( *service, KHTMLGlobal::componentData() );
4491 KPluginFactory* const factory = loader.factory();
4492 if ( factory ) {
4493 // Turn params into a QVariantList as expected by KPluginFactory
4494 QVariantList variantlist;
4495 Q_FOREACH(const QString& str, params)
4496 variantlist << QVariant(str);
4498 if ( service->serviceTypes().contains( "Browser/View" ) )
4499 variantlist << QString("Browser/View");
4501 KParts::ReadOnlyPart* part = factory->create<KParts::ReadOnlyPart>(parentWidget, parent, QString(), variantlist);
4502 if ( part ) {
4503 serviceTypes = service->serviceTypes();
4504 serviceName = service->name();
4505 return part;
4507 } else {
4508 // TODO KMessageBox::error and i18n, like in KonqFactory::createView?
4509 kWarning() << QString("There was an error loading the module %1.\nThe diagnostics is:\n%2")
4510 .arg(service->name()).arg(loader.errorString());
4513 return 0;
4516 KParts::PartManager *KHTMLPart::partManager()
4518 if ( !d->m_manager && d->m_view )
4520 d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this );
4521 d->m_manager->setObjectName( "khtml part manager" );
4522 d->m_manager->setAllowNestedParts( true );
4523 connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
4524 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
4525 connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ),
4526 this, SLOT( slotPartRemoved( KParts::Part * ) ) );
4529 return d->m_manager;
4532 void KHTMLPart::submitFormAgain()
4534 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
4535 if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
4536 KHTMLPart::submitForm( d->m_submitForm->submitAction, d->m_submitForm->submitUrl, d->m_submitForm->submitFormData, d->m_submitForm->target, d->m_submitForm->submitContentType, d->m_submitForm->submitBoundary );
4538 delete d->m_submitForm;
4539 d->m_submitForm = 0;
4542 void KHTMLPart::submitFormProxy( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
4544 submitForm(action, url, formData, _target, contentType, boundary);
4547 void KHTMLPart::submitForm( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
4549 kDebug(6000) << this << "target=" << _target << "url=" << url;
4550 if (d->m_formNotification == KHTMLPart::Only) {
4551 emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
4552 return;
4553 } else if (d->m_formNotification == KHTMLPart::Before) {
4554 emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
4557 KUrl u = completeURL( url );
4559 if ( !u.isValid() )
4561 // ### ERROR HANDLING!
4562 return;
4565 // Form security checks
4568 * If these form security checks are still in this place in a month or two
4569 * I'm going to simply delete them.
4572 /* This is separate for a reason. It has to be _before_ all script, etc,
4573 * AND I don't want to break anything that uses checkLinkSecurity() in
4574 * other places.
4577 if (!d->m_submitForm) {
4578 if (u.protocol() != "https" && u.protocol() != "mailto") {
4579 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
4580 int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
4581 "\nA third party may be able to intercept and view this information."
4582 "\nAre you sure you wish to continue?"),
4583 i18n("Network Transmission"),KGuiItem(i18n("&Send Unencrypted")));
4584 if (rc == KMessageBox::Cancel)
4585 return;
4586 } else { // Going from nonSSL -> nonSSL
4587 KSSLSettings kss(true);
4588 if (kss.warnOnUnencrypted()) {
4589 int rc = KMessageBox::warningContinueCancel(NULL,
4590 i18n("Warning: Your data is about to be transmitted across the network unencrypted."
4591 "\nAre you sure you wish to continue?"),
4592 i18n("Network Transmission"),
4593 KGuiItem(i18n("&Send Unencrypted")),
4594 KStandardGuiItem::cancel(),
4595 "WarnOnUnencryptedForm");
4596 // Move this setting into KSSL instead
4597 QString grpNotifMsgs = QLatin1String("Notification Messages");
4598 KConfigGroup cg( KGlobal::config(), grpNotifMsgs );
4600 if (!cg.readEntry("WarnOnUnencryptedForm", true)) {
4601 cg.deleteEntry("WarnOnUnencryptedForm");
4602 cg.sync();
4603 kss.setWarnOnUnencrypted(false);
4604 kss.save();
4606 if (rc == KMessageBox::Cancel)
4607 return;
4612 if (u.protocol() == "mailto") {
4613 int rc = KMessageBox::warningContinueCancel(NULL,
4614 i18n("This site is attempting to submit form data via email.\n"
4615 "Do you want to continue?"),
4616 i18n("Network Transmission"),
4617 KGuiItem(i18n("&Send Email")),
4618 KStandardGuiItem::cancel(),
4619 "WarnTriedEmailSubmit");
4621 if (rc == KMessageBox::Cancel) {
4622 return;
4627 // End form security checks
4630 QString urlstring = u.url();
4632 if ( d->isJavaScriptURL(urlstring) ) {
4633 crossFrameExecuteScript( _target, d->codeForJavaScriptURL(urlstring) );
4634 return;
4637 if (!checkLinkSecurity(u,
4638 ki18n( "<qt>The form will be submitted to <br /><b>%1</b><br />on your local filesystem.<br />Do you want to submit the form?</qt>" ),
4639 i18n( "Submit" )))
4640 return;
4642 // OK. We're actually going to submit stuff. Clear any redirections,
4643 // we should win over them
4644 d->clearRedirection();
4646 KParts::OpenUrlArguments args;
4648 if (!d->m_referrer.isEmpty())
4649 args.metaData()["referrer"] = d->m_referrer;
4651 args.metaData().insert("PropagateHttpHeader", "true");
4652 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
4653 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
4654 args.metaData().insert("main_frame_request",
4655 parentPart() == 0 ? "TRUE":"FALSE");
4656 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
4657 args.metaData().insert("ssl_activate_warnings", "TRUE");
4658 //WABA: When we post a form we should treat it as the main url
4659 //the request should never be considered cross-domain
4660 //args.metaData().insert("cross-domain", toplevelURL().url());
4661 KParts::BrowserArguments browserArgs;
4662 browserArgs.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
4664 // Handle mailto: forms
4665 if (u.protocol() == "mailto") {
4666 // 1) Check for attach= and strip it
4667 QString q = u.query().mid(1);
4668 QStringList nvps = q.split("&");
4669 bool triedToAttach = false;
4671 QStringList::Iterator nvp = nvps.begin();
4672 const QStringList::Iterator nvpEnd = nvps.end();
4674 // cannot be a for loop as if something is removed we don't want to do ++nvp, as
4675 // remove returns an iterator pointing to the next item
4677 while (nvp != nvpEnd) {
4678 const QStringList pair = (*nvp).split("=");
4679 if (pair.count() >= 2) {
4680 if (pair.first().toLower() == "attach") {
4681 nvp = nvps.erase(nvp);
4682 triedToAttach = true;
4683 } else {
4684 ++nvp;
4686 } else {
4687 ++nvp;
4691 if (triedToAttach)
4692 KMessageBox::information(NULL, i18n("This site attempted to attach a file from your computer in the form submission. The attachment was removed for your protection."), i18n("KDE"), "WarnTriedAttach");
4694 // 2) Append body=
4695 QString bodyEnc;
4696 if (contentType.toLower() == "multipart/form-data") {
4697 // FIXME: is this correct? I suspect not
4698 bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(),
4699 formData.size())));
4700 } else if (contentType.toLower() == "text/plain") {
4701 // Convention seems to be to decode, and s/&/\n/
4702 QString tmpbody = QString::fromLatin1(formData.data(),
4703 formData.size());
4704 tmpbody.replace(QRegExp("[&]"), "\n");
4705 tmpbody.replace(QRegExp("[+]"), " ");
4706 tmpbody = KUrl::fromPercentEncoding(tmpbody.toLatin1()); // Decode the rest of it
4707 bodyEnc = QLatin1String( KUrl::toPercentEncoding(tmpbody) ); // Recode for the URL
4708 } else {
4709 bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(),
4710 formData.size())) );
4713 nvps.append(QString("body=%1").arg(bodyEnc));
4714 q = nvps.join("&");
4715 u.setQuery(q);
4718 if ( strcmp( action, "get" ) == 0 ) {
4719 if (u.protocol() != "mailto")
4720 u.setQuery( QString::fromLatin1( formData.data(), formData.size() ) );
4721 browserArgs.setDoPost( false );
4723 else {
4724 browserArgs.postData = formData;
4725 browserArgs.setDoPost( true );
4727 // construct some user headers if necessary
4728 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
4729 browserArgs.setContentType( "Content-Type: application/x-www-form-urlencoded" );
4730 else // contentType must be "multipart/form-data"
4731 browserArgs.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
4734 if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
4735 if( d->m_submitForm ) {
4736 kDebug(6000) << "ABORTING!";
4737 return;
4739 d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
4740 d->m_submitForm->submitAction = action;
4741 d->m_submitForm->submitUrl = url;
4742 d->m_submitForm->submitFormData = formData;
4743 d->m_submitForm->target = _target;
4744 d->m_submitForm->submitContentType = contentType;
4745 d->m_submitForm->submitBoundary = boundary;
4746 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
4748 else
4750 emit d->m_extension->openUrlRequest( u, args, browserArgs );
4754 void KHTMLPart::popupMenu( const QString &linkUrl )
4756 KUrl popupURL;
4757 KUrl linkKUrl;
4758 KParts::OpenUrlArguments args;
4759 KParts::BrowserArguments browserArgs;
4760 QString referrer;
4761 KParts::BrowserExtension::PopupFlags itemflags=KParts::BrowserExtension::ShowBookmark | KParts::BrowserExtension::ShowReload;
4763 if ( linkUrl.isEmpty() ) { // click on background
4764 KHTMLPart* khtmlPart = this;
4765 while ( khtmlPart->parentPart() )
4767 khtmlPart=khtmlPart->parentPart();
4769 popupURL = khtmlPart->url();
4770 referrer = khtmlPart->pageReferrer();
4771 if (hasSelection())
4772 itemflags = KParts::BrowserExtension::ShowTextSelectionItems;
4773 else
4774 itemflags |= KParts::BrowserExtension::ShowNavigationItems;
4775 } else { // click on link
4776 popupURL = completeURL( linkUrl );
4777 linkKUrl = popupURL;
4778 referrer = this->referrer();
4779 itemflags |= KParts::BrowserExtension::IsLink;
4781 if (!(d->m_strSelectedURLTarget).isEmpty() &&
4782 (d->m_strSelectedURLTarget.toLower() != "_top") &&
4783 (d->m_strSelectedURLTarget.toLower() != "_self") &&
4784 (d->m_strSelectedURLTarget.toLower() != "_parent")) {
4785 if (d->m_strSelectedURLTarget.toLower() == "_blank")
4786 browserArgs.setForcesNewWindow(true);
4787 else {
4788 KHTMLPart *p = this;
4789 while (p->parentPart())
4790 p = p->parentPart();
4791 if (!p->frameExists(d->m_strSelectedURLTarget))
4792 browserArgs.setForcesNewWindow(true);
4797 // Danger, Will Robinson. The Popup might stay around for a much
4798 // longer time than KHTMLPart. Deal with it.
4799 KHTMLPopupGUIClient* client = new KHTMLPopupGUIClient( this, linkKUrl );
4800 QPointer<QObject> guard( client );
4802 QString mimetype = QLatin1String( "text/html" );
4803 args.metaData()["referrer"] = referrer;
4805 if (!linkUrl.isEmpty()) // over a link
4807 if (popupURL.isLocalFile()) // safe to do this
4809 mimetype = KMimeType::findByUrl(popupURL,0,true,false)->name();
4811 else // look at "extension" of link
4813 const QString fname(popupURL.fileName(KUrl::ObeyTrailingSlash));
4814 if (!fname.isEmpty() && !popupURL.hasRef() && popupURL.query().isEmpty())
4816 KMimeType::Ptr pmt = KMimeType::findByPath(fname,0,true);
4818 // Further check for mime types guessed from the extension which,
4819 // on a web page, are more likely to be a script delivering content
4820 // of undecidable type. If the mime type from the extension is one
4821 // of these, don't use it. Retain the original type 'text/html'.
4822 if (pmt->name() != KMimeType::defaultMimeType() &&
4823 !pmt->is("application/x-perl") &&
4824 !pmt->is("application/x-perl-module") &&
4825 !pmt->is("application/x-php") &&
4826 !pmt->is("application/x-python-bytecode") &&
4827 !pmt->is("application/x-python") &&
4828 !pmt->is("application/x-shellscript"))
4829 mimetype = pmt->name();
4834 args.setMimeType(mimetype);
4836 emit d->m_extension->popupMenu( QCursor::pos(), popupURL, S_IFREG /*always a file*/,
4837 args, browserArgs, itemflags,
4838 client->actionGroups() );
4840 if ( !guard.isNull() ) {
4841 delete client;
4842 emit popupMenu(linkUrl, QCursor::pos());
4843 d->m_strSelectedURL.clear();
4844 d->m_strSelectedURLTarget.clear();
4848 void KHTMLPart::slotParentCompleted()
4850 //kDebug(6050) << this;
4851 if ( !d->m_redirectURL.isEmpty() && !d->m_redirectionTimer.isActive() )
4853 //kDebug(6050) << this << ": starting timer for child redirection -> " << d->m_redirectURL;
4854 d->m_redirectionTimer.setSingleShot( true );
4855 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
4859 void KHTMLPart::slotChildStarted( KIO::Job *job )
4861 khtml::ChildFrame *child = frame( sender() );
4863 assert( child );
4865 child->m_bCompleted = false;
4867 if ( d->m_bComplete )
4869 #if 0
4870 // WABA: Looks like this belongs somewhere else
4871 if ( !parentPart() ) // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes
4873 emit d->m_extension->openURLNotify();
4875 #endif
4876 d->m_bComplete = false;
4877 emit started( job );
4881 void KHTMLPart::slotChildCompleted()
4883 slotChildCompleted( false );
4886 void KHTMLPart::slotChildCompleted( bool pendingAction )
4888 khtml::ChildFrame *child = frame( sender() );
4890 if ( child ) {
4891 kDebug(6050) << this << "child=" << child << "m_partContainerElement=" << child->m_partContainerElement;
4892 child->m_bCompleted = true;
4893 child->m_bPendingRedirection = pendingAction;
4894 child->m_args = KParts::OpenUrlArguments();
4895 child->m_browserArgs = KParts::BrowserArguments();
4896 // dispatch load event
4897 if (!qobject_cast<KHTMLPart*>(child->m_part))
4898 QTimer::singleShot(0, child->m_partContainerElement, SLOT(slotEmitLoadEvent()));
4900 checkCompleted();
4903 void KHTMLPart::slotChildDocCreated()
4905 // Set domain to the frameset's domain
4906 // This must only be done when loading the frameset initially (#22039),
4907 // not when following a link in a frame (#44162).
4908 if (KHTMLPart* htmlFrame = qobject_cast<KHTMLPart*>(sender()))
4909 d->propagateInitialDomainTo( htmlFrame );
4911 // So it only happens once
4912 disconnect( sender(), SIGNAL( docCreated() ), this, SLOT( slotChildDocCreated() ) );
4915 void KHTMLPartPrivate::propagateInitialDomainTo(KHTMLPart* kid)
4917 // This method is used to propagate our domain information for
4918 // child frames, potentially widening to have less periods, and also
4919 // to provide a domain for about: or JavaScript: URLs altogether.
4920 // Note that DocumentImpl:;setDomain does the checking.
4921 if ( m_doc && kid->d->m_doc )
4922 kid->d->m_doc->setDomain( m_doc->domain() );
4925 void KHTMLPart::slotChildURLRequest( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs )
4927 khtml::ChildFrame *child = frame( sender()->parent() );
4928 KHTMLPart *callingHtmlPart = const_cast<KHTMLPart *>(dynamic_cast<const KHTMLPart *>(sender()->parent()));
4930 // TODO: handle child target correctly! currently the script are always executed for the parent
4931 QString urlStr = url.url();
4932 if ( d->isJavaScriptURL(urlStr) ) {
4933 executeScript( DOM::Node(), d->codeForJavaScriptURL(urlStr) );
4934 return;
4937 QString frameName = browserArgs.frameName.toLower();
4938 if ( !frameName.isEmpty() ) {
4939 if ( frameName == QLatin1String( "_top" ) )
4941 emit d->m_extension->openUrlRequest( url, args, browserArgs );
4942 return;
4944 else if ( frameName == QLatin1String( "_blank" ) )
4946 emit d->m_extension->createNewWindow( url, args, browserArgs );
4947 return;
4949 else if ( frameName == QLatin1String( "_parent" ) )
4951 KParts::BrowserArguments newBrowserArgs( browserArgs );
4952 newBrowserArgs.frameName.clear();
4953 emit d->m_extension->openUrlRequest( url, args, newBrowserArgs );
4954 return;
4956 else if ( frameName != QLatin1String( "_self" ) )
4958 khtml::ChildFrame *_frame = recursiveFrameRequest( callingHtmlPart, url, args, browserArgs );
4960 if ( !_frame )
4962 emit d->m_extension->openUrlRequest( url, args, browserArgs );
4963 return;
4966 child = _frame;
4970 if ( child && child->m_type != khtml::ChildFrame::Object ) {
4971 // Inform someone that we are about to show something else.
4972 child->m_bNotify = true;
4973 requestObject( child, url, args, browserArgs );
4974 } else if ( frameName== "_self" ) // this is for embedded objects (via <object>) which want to replace the current document
4976 KParts::BrowserArguments newBrowserArgs( browserArgs );
4977 newBrowserArgs.frameName.clear();
4978 emit d->m_extension->openUrlRequest( url, args, newBrowserArgs );
4982 void KHTMLPart::slotRequestFocus( KParts::ReadOnlyPart * )
4984 emit d->m_extension->requestFocus(this);
4987 khtml::ChildFrame *KHTMLPart::frame( const QObject *obj )
4989 assert( obj->inherits( "KParts::ReadOnlyPart" ) );
4990 const KParts::ReadOnlyPart* const part = static_cast<const KParts::ReadOnlyPart *>( obj );
4992 FrameIt it = d->m_frames.begin();
4993 const FrameIt end = d->m_frames.end();
4994 for (; it != end; ++it )
4995 if ( (KParts::ReadOnlyPart *)(*it)->m_part == part )
4996 return *it;
4998 FrameIt oi = d->m_objects.begin();
4999 const FrameIt oiEnd = d->m_objects.end();
5000 for (; oi != oiEnd; ++oi )
5001 if ( (KParts::ReadOnlyPart *)(*oi)->m_part == part )
5002 return *oi;
5004 return 0L;
5007 //#define DEBUG_FINDFRAME
5009 bool KHTMLPart::checkFrameAccess(KHTMLPart *callingHtmlPart)
5011 if (callingHtmlPart == this)
5012 return true; // trivial
5014 if (!xmlDocImpl()) {
5015 #ifdef DEBUG_FINDFRAME
5016 kDebug(6050) << "Empty part" << this << "URL = " << url();
5017 #endif
5018 return false; // we are empty?
5021 // now compare the domains
5022 if (callingHtmlPart && callingHtmlPart->xmlDocImpl() && xmlDocImpl()) {
5023 DOM::DOMString actDomain = callingHtmlPart->xmlDocImpl()->domain();
5024 DOM::DOMString destDomain = xmlDocImpl()->domain();
5026 #ifdef DEBUG_FINDFRAME
5027 kDebug(6050) << "actDomain =" << actDomain.string() << "destDomain =" << destDomain.string();
5028 #endif
5030 if (actDomain == destDomain)
5031 return true;
5033 #ifdef DEBUG_FINDFRAME
5034 else
5036 kDebug(6050) << "Unknown part/domain" << callingHtmlPart << "tries to access part" << this;
5038 #endif
5039 return false;
5042 KHTMLPart *
5043 KHTMLPart::findFrameParent( KParts::ReadOnlyPart *callingPart, const QString &f, khtml::ChildFrame **childFrame )
5045 #ifdef DEBUG_FINDFRAME
5046 kDebug(6050) << this << "URL =" << url() << "name =" << name() << "findFrameParent(" << f << ")";
5047 #endif
5048 // Check access
5049 KHTMLPart* const callingHtmlPart = dynamic_cast<KHTMLPart *>(callingPart);
5051 if (!checkFrameAccess(callingHtmlPart))
5052 return 0;
5054 if (!childFrame && !parentPart() && (objectName() == f))
5055 return this;
5057 FrameIt it = d->m_frames.find( f );
5058 const FrameIt end = d->m_frames.end();
5059 if ( it != end )
5061 #ifdef DEBUG_FINDFRAME
5062 kDebug(6050) << "FOUND!";
5063 #endif
5064 if (childFrame)
5065 *childFrame = *it;
5066 return this;
5069 it = d->m_frames.begin();
5070 for (; it != end; ++it )
5072 KParts::ReadOnlyPart* const p = (*it)->m_part;
5073 if ( p && p->inherits( "KHTMLPart" ))
5075 KHTMLPart* const frameParent = static_cast<KHTMLPart*>(p)->findFrameParent(callingPart, f, childFrame);
5076 if (frameParent)
5077 return frameParent;
5080 return 0;
5084 KHTMLPart *KHTMLPart::findFrame( const QString &f )
5086 khtml::ChildFrame *childFrame;
5087 KHTMLPart *parentFrame = findFrameParent(this, f, &childFrame);
5088 if (parentFrame)
5090 KParts::ReadOnlyPart *p = childFrame->m_part;
5091 if ( p && p->inherits( "KHTMLPart" ))
5092 return static_cast<KHTMLPart *>(p);
5094 return 0;
5097 KParts::ReadOnlyPart *KHTMLPart::findFramePart(const QString &f)
5099 khtml::ChildFrame *childFrame;
5100 return findFrameParent(this, f, &childFrame) ? static_cast<KParts::ReadOnlyPart *>(childFrame->m_part) : 0L;
5103 KParts::ReadOnlyPart *KHTMLPart::currentFrame() const
5105 KParts::ReadOnlyPart* part = (KParts::ReadOnlyPart*)(this);
5106 // Find active part in our frame manager, in case we are a frameset
5107 // and keep doing that (in case of nested framesets).
5108 // Just realized we could also do this recursively, calling part->currentFrame()...
5109 while ( part && part->inherits("KHTMLPart") &&
5110 static_cast<KHTMLPart *>(part)->d->m_frames.count() > 0 ) {
5111 KHTMLPart* frameset = static_cast<KHTMLPart *>(part);
5112 part = static_cast<KParts::ReadOnlyPart *>(frameset->partManager()->activePart());
5113 if ( !part ) return frameset;
5115 return part;
5118 bool KHTMLPart::frameExists( const QString &frameName )
5120 FrameIt it = d->m_frames.find( frameName );
5121 if ( it == d->m_frames.end() )
5122 return false;
5124 // WABA: We only return true if the child actually has a frame
5125 // set. Otherwise we might find our preloaded-selve.
5126 // This happens when we restore the frameset.
5127 return (!(*it)->m_partContainerElement.isNull());
5130 KJSProxy *KHTMLPart::framejScript(KParts::ReadOnlyPart *framePart)
5132 KHTMLPart* const kp = qobject_cast<KHTMLPart*>(framePart);
5133 if (kp)
5134 return kp->jScript();
5136 FrameIt it = d->m_frames.begin();
5137 const FrameIt itEnd = d->m_frames.end();
5139 for (; it != itEnd; ++it)
5140 if (framePart == (*it)->m_part) {
5141 if (!(*it)->m_jscript)
5142 createJScript(*it);
5143 return (*it)->m_jscript;
5145 return 0L;
5148 KHTMLPart *KHTMLPart::parentPart()
5150 return qobject_cast<KHTMLPart*>( parent() );
5153 khtml::ChildFrame *KHTMLPart::recursiveFrameRequest( KHTMLPart *callingHtmlPart, const KUrl &url,
5154 const KParts::OpenUrlArguments &args,
5155 const KParts::BrowserArguments &browserArgs, bool callParent )
5157 #ifdef DEBUG_FINDFRAME
5158 kDebug( 6050 ) << this << "frame = " << args.frameName << "url = " << url;
5159 #endif
5160 khtml::ChildFrame *childFrame;
5161 KHTMLPart *childPart = findFrameParent(callingHtmlPart, browserArgs.frameName, &childFrame);
5162 if (childPart)
5164 if (childPart == this)
5165 return childFrame;
5167 childPart->requestObject( childFrame, url, args, browserArgs );
5168 return 0;
5171 if ( parentPart() && callParent )
5173 khtml::ChildFrame *res = parentPart()->recursiveFrameRequest( callingHtmlPart, url, args, browserArgs, callParent );
5175 if ( res )
5176 parentPart()->requestObject( res, url, args, browserArgs );
5179 return 0L;
5182 #ifdef DEBUG_SAVESTATE
5183 static int s_saveStateIndentLevel = 0;
5184 #endif
5186 void KHTMLPart::saveState( QDataStream &stream )
5188 #ifdef DEBUG_SAVESTATE
5189 QString indent= QString().leftJustified( s_saveStateIndentLevel * 4, ' ' );
5190 const int indentLevel = s_saveStateIndentLevel++;
5191 kDebug( 6050 ) << indent << "saveState this=" << this << " '" << objectName() << "' saving URL " << url().url();
5192 #endif
5194 stream << url() << (qint32)d->m_view->contentsX() << (qint32)d->m_view->contentsY()
5195 << (qint32) d->m_view->contentsWidth() << (qint32) d->m_view->contentsHeight() << (qint32) d->m_view->marginWidth() << (qint32) d->m_view->marginHeight();
5197 // save link cursor position
5198 int focusNodeNumber;
5199 if (!d->m_focusNodeRestored)
5200 focusNodeNumber = d->m_focusNodeNumber;
5201 else if (d->m_doc && d->m_doc->focusNode())
5202 focusNodeNumber = d->m_doc->nodeAbsIndex(d->m_doc->focusNode());
5203 else
5204 focusNodeNumber = -1;
5205 stream << focusNodeNumber;
5207 // Save the doc's cache id.
5208 stream << d->m_cacheId;
5210 // Save the state of the document (Most notably the state of any forms)
5211 QStringList docState;
5212 if (d->m_doc)
5214 docState = d->m_doc->docState();
5216 stream << d->m_encoding << d->m_sheetUsed << docState;
5218 stream << d->m_zoomFactor;
5219 stream << d->m_fontScaleFactor;
5221 stream << d->m_httpHeaders;
5222 stream << d->m_pageServices;
5223 stream << d->m_pageReferrer;
5225 // Save ssl data
5226 stream << d->m_ssl_in_use
5227 << d->m_ssl_peer_chain
5228 << d->m_ssl_peer_ip
5229 << d->m_ssl_cipher
5230 << d->m_ssl_protocol_version
5231 << d->m_ssl_cipher_used_bits
5232 << d->m_ssl_cipher_bits
5233 << d->m_ssl_cert_errors
5234 << d->m_ssl_parent_ip
5235 << d->m_ssl_parent_cert;
5238 QStringList frameNameLst, frameServiceTypeLst, frameServiceNameLst;
5239 KUrl::List frameURLLst;
5240 QList<QByteArray> frameStateBufferLst;
5241 QList<int> frameTypeLst;
5243 ConstFrameIt it = d->m_frames.constBegin();
5244 const ConstFrameIt end = d->m_frames.constEnd();
5245 for (; it != end; ++it )
5247 if ( !(*it)->m_part )
5248 continue;
5250 frameNameLst << (*it)->m_name;
5251 frameServiceTypeLst << (*it)->m_serviceType;
5252 frameServiceNameLst << (*it)->m_serviceName;
5253 frameURLLst << (*it)->m_part->url();
5255 QByteArray state;
5256 QDataStream frameStream( &state, QIODevice::WriteOnly );
5258 if ( (*it)->m_extension )
5259 (*it)->m_extension->saveState( frameStream );
5261 frameStateBufferLst << state;
5263 frameTypeLst << int( (*it)->m_type );
5266 // Save frame data
5267 stream << (quint32) frameNameLst.count();
5268 stream << frameNameLst << frameServiceTypeLst << frameServiceNameLst << frameURLLst << frameStateBufferLst << frameTypeLst;
5269 #ifdef DEBUG_SAVESTATE
5270 s_saveStateIndentLevel = indentLevel;
5271 #endif
5274 void KHTMLPart::restoreState( QDataStream &stream )
5276 KUrl u;
5277 qint32 xOffset, yOffset, wContents, hContents, mWidth, mHeight;
5278 quint32 frameCount;
5279 QStringList frameNames, frameServiceTypes, docState, frameServiceNames;
5280 QList<int> frameTypes;
5281 KUrl::List frameURLs;
5282 QList<QByteArray> frameStateBuffers;
5283 QList<int> fSizes;
5284 QString encoding, sheetUsed;
5285 long old_cacheId = d->m_cacheId;
5287 stream >> u >> xOffset >> yOffset >> wContents >> hContents >> mWidth >> mHeight;
5289 d->m_view->setMarginWidth( mWidth );
5290 d->m_view->setMarginHeight( mHeight );
5292 // restore link cursor position
5293 // nth node is active. value is set in checkCompleted()
5294 stream >> d->m_focusNodeNumber;
5295 d->m_focusNodeRestored = false;
5297 stream >> d->m_cacheId;
5299 stream >> encoding >> sheetUsed >> docState;
5301 d->m_encoding = encoding;
5302 d->m_sheetUsed = sheetUsed;
5304 int zoomFactor;
5305 stream >> zoomFactor;
5306 setZoomFactor(zoomFactor);
5308 int fontScaleFactor;
5309 stream >> fontScaleFactor;
5310 setFontScaleFactor(fontScaleFactor);
5312 stream >> d->m_httpHeaders;
5313 stream >> d->m_pageServices;
5314 stream >> d->m_pageReferrer;
5316 // Restore ssl data
5317 stream >> d->m_ssl_in_use
5318 >> d->m_ssl_peer_chain
5319 >> d->m_ssl_peer_ip
5320 >> d->m_ssl_cipher
5321 >> d->m_ssl_protocol_version
5322 >> d->m_ssl_cipher_used_bits
5323 >> d->m_ssl_cipher_bits
5324 >> d->m_ssl_cert_errors
5325 >> d->m_ssl_parent_ip
5326 >> d->m_ssl_parent_cert;
5328 setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
5330 stream >> frameCount >> frameNames >> frameServiceTypes >> frameServiceNames
5331 >> frameURLs >> frameStateBuffers >> frameTypes;
5333 d->m_bComplete = false;
5334 d->m_bLoadEventEmitted = false;
5336 // kDebug( 6050 ) << "docState.count() = " << docState.count();
5337 // kDebug( 6050 ) << "m_url " << url().url() << " <-> " << u.url();
5338 // kDebug( 6050 ) << "m_frames.count() " << d->m_frames.count() << " <-> " << frameCount;
5340 if (d->m_cacheId == old_cacheId)
5342 // Partial restore
5343 d->m_redirectionTimer.stop();
5345 FrameIt fIt = d->m_frames.begin();
5346 const FrameIt fEnd = d->m_frames.end();
5348 for (; fIt != fEnd; ++fIt )
5349 (*fIt)->m_bCompleted = false;
5351 fIt = d->m_frames.begin();
5353 QStringList::ConstIterator fNameIt = frameNames.constBegin();
5354 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin();
5355 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin();
5356 KUrl::List::ConstIterator fURLIt = frameURLs.constBegin();
5357 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin();
5358 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin();
5360 for (; fIt != fEnd; ++fIt, ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt )
5362 khtml::ChildFrame* const child = *fIt;
5364 // kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt;
5366 if ( child->m_name != *fNameIt || child->m_serviceType != *fServiceTypeIt )
5368 child->m_bPreloaded = true;
5369 child->m_name = *fNameIt;
5370 child->m_serviceName = *fServiceNameIt;
5371 child->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt);
5372 processObjectRequest( child, *fURLIt, *fServiceTypeIt );
5374 if ( child->m_part )
5376 child->m_bCompleted = false;
5377 if ( child->m_extension && !(*fBufferIt).isEmpty() )
5379 QDataStream frameStream( *fBufferIt );
5380 child->m_extension->restoreState( frameStream );
5382 else
5383 child->m_part->openUrl( *fURLIt );
5387 KParts::OpenUrlArguments args( arguments() );
5388 args.setXOffset(xOffset);
5389 args.setYOffset(yOffset);
5390 setArguments(args);
5392 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
5393 browserArgs.docState = docState;
5394 d->m_extension->setBrowserArguments(browserArgs);
5396 d->m_view->resizeContents( wContents, hContents );
5397 d->m_view->setContentsPos( xOffset, yOffset );
5399 setUrl(u);
5401 else
5403 // Full restore.
5404 closeUrl();
5405 // We must force a clear because we want to be sure to delete all
5406 // frames.
5407 d->m_bCleared = false;
5408 clear();
5409 d->m_encoding = encoding;
5410 d->m_sheetUsed = sheetUsed;
5412 QStringList::ConstIterator fNameIt = frameNames.constBegin();
5413 const QStringList::ConstIterator fNameEnd = frameNames.constEnd();
5415 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin();
5416 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin();
5417 KUrl::List::ConstIterator fURLIt = frameURLs.constBegin();
5418 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin();
5419 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin();
5421 for (; fNameIt != fNameEnd; ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt )
5423 khtml::ChildFrame* const newChild = new khtml::ChildFrame;
5424 newChild->m_bPreloaded = true;
5425 newChild->m_name = *fNameIt;
5426 newChild->m_serviceName = *fServiceNameIt;
5427 newChild->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt);
5429 // kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt;
5431 const FrameIt childFrame = d->m_frames.insert( d->m_frames.end(), newChild );
5433 processObjectRequest( *childFrame, *fURLIt, *fServiceTypeIt );
5435 (*childFrame)->m_bPreloaded = true;
5437 if ( (*childFrame)->m_part )
5439 if ( (*childFrame)->m_extension && !(*fBufferIt).isEmpty() )
5441 QDataStream frameStream( *fBufferIt );
5442 (*childFrame)->m_extension->restoreState( frameStream );
5444 else
5445 (*childFrame)->m_part->openUrl( *fURLIt );
5449 KParts::OpenUrlArguments args( arguments() );
5450 args.setXOffset(xOffset);
5451 args.setYOffset(yOffset);
5452 setArguments(args);
5454 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
5455 browserArgs.docState = docState;
5456 d->m_extension->setBrowserArguments(browserArgs);
5458 if (!KHTMLPageCache::self()->isComplete(d->m_cacheId))
5460 d->m_restored = true;
5461 openUrl( u );
5462 d->m_restored = false;
5464 else
5466 restoreURL( u );
5472 void KHTMLPart::show()
5474 if ( d->m_view )
5475 d->m_view->show();
5478 void KHTMLPart::hide()
5480 if ( d->m_view )
5481 d->m_view->hide();
5484 DOM::Node KHTMLPart::nodeUnderMouse() const
5486 return d->m_view->nodeUnderMouse();
5489 DOM::Node KHTMLPart::nonSharedNodeUnderMouse() const
5491 return d->m_view->nonSharedNodeUnderMouse();
5494 void KHTMLPart::emitSelectionChanged()
5496 emit d->m_extension->enableAction( "copy", hasSelection() );
5498 emit d->m_extension->selectionInfo( selectedText() );
5499 emit selectionChanged();
5502 int KHTMLPart::zoomFactor() const
5504 return d->m_zoomFactor;
5507 // ### make the list configurable ?
5508 static const int zoomSizes[] = { 20, 40, 60, 80, 90, 95, 100, 105, 110, 120, 140, 160, 180, 200, 250, 300 };
5509 static const int zoomSizeCount = (sizeof(zoomSizes) / sizeof(int));
5510 static const int minZoom = 20;
5511 static const int maxZoom = 300;
5513 // My idea of useful stepping ;-) (LS)
5514 extern const int KDE_NO_EXPORT fastZoomSizes[] = { 20, 50, 75, 90, 100, 120, 150, 200, 300 };
5515 extern const int KDE_NO_EXPORT fastZoomSizeCount = sizeof fastZoomSizes / sizeof fastZoomSizes[0];
5517 void KHTMLPart::slotIncZoom()
5519 zoomIn(zoomSizes, zoomSizeCount);
5522 void KHTMLPart::slotDecZoom()
5524 zoomOut(zoomSizes, zoomSizeCount);
5527 void KHTMLPart::slotIncZoomFast()
5529 zoomIn(fastZoomSizes, fastZoomSizeCount);
5532 void KHTMLPart::slotDecZoomFast()
5534 zoomOut(fastZoomSizes, fastZoomSizeCount);
5537 void KHTMLPart::zoomIn(const int stepping[], int count)
5539 int zoomFactor = d->m_zoomFactor;
5541 if (zoomFactor < maxZoom) {
5542 // find the entry nearest to the given zoomsizes
5543 for (int i = 0; i < count; ++i)
5544 if (stepping[i] > zoomFactor) {
5545 zoomFactor = stepping[i];
5546 break;
5548 setZoomFactor(zoomFactor);
5552 void KHTMLPart::zoomOut(const int stepping[], int count)
5554 int zoomFactor = d->m_zoomFactor;
5555 if (zoomFactor > minZoom) {
5556 // find the entry nearest to the given zoomsizes
5557 for (int i = count-1; i >= 0; --i)
5558 if (stepping[i] < zoomFactor) {
5559 zoomFactor = stepping[i];
5560 break;
5562 setZoomFactor(zoomFactor);
5566 void KHTMLPart::setZoomFactor (int percent)
5568 // ### zooming under 100% is majorly botched,
5569 // so disable that for now.
5570 if (percent < 100) percent = 100;
5571 // ### if (percent < minZoom) percent = minZoom;
5573 if (percent > maxZoom) percent = maxZoom;
5574 if (d->m_zoomFactor == percent) return;
5575 d->m_zoomFactor = percent;
5577 if(d->m_view) {
5578 QApplication::setOverrideCursor( Qt::WaitCursor );
5579 d->m_view->setZoomLevel( d->m_zoomFactor );
5580 QApplication::restoreOverrideCursor();
5583 ConstFrameIt it = d->m_frames.constBegin();
5584 const ConstFrameIt end = d->m_frames.constEnd();
5585 for (; it != end; ++it )
5586 if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
5587 KParts::ReadOnlyPart* const p = ( *it )->m_part;
5588 static_cast<KHTMLPart*>( p )->setZoomFactor(d->m_zoomFactor);
5591 if ( d->m_guiProfile == BrowserViewGUI ) {
5592 d->m_paDecZoomFactor->setEnabled( d->m_zoomFactor > minZoom );
5593 d->m_paIncZoomFactor->setEnabled( d->m_zoomFactor < maxZoom );
5596 void KHTMLPart::slotIncFontSize()
5598 incFontSize(zoomSizes, zoomSizeCount);
5601 void KHTMLPart::slotDecFontSize()
5603 decFontSize(zoomSizes, zoomSizeCount);
5606 void KHTMLPart::slotIncFontSizeFast()
5608 incFontSize(fastZoomSizes, fastZoomSizeCount);
5611 void KHTMLPart::slotDecFontSizeFast()
5613 decFontSize(fastZoomSizes, fastZoomSizeCount);
5616 void KHTMLPart::incFontSize(const int stepping[], int count)
5618 int zoomFactor = d->m_fontScaleFactor;
5620 if (zoomFactor < maxZoom) {
5621 // find the entry nearest to the given zoomsizes
5622 for (int i = 0; i < count; ++i)
5623 if (stepping[i] > zoomFactor) {
5624 zoomFactor = stepping[i];
5625 break;
5627 setFontScaleFactor(zoomFactor);
5631 void KHTMLPart::decFontSize(const int stepping[], int count)
5633 int zoomFactor = d->m_fontScaleFactor;
5634 if (zoomFactor > minZoom) {
5635 // find the entry nearest to the given zoomsizes
5636 for (int i = count-1; i >= 0; --i)
5637 if (stepping[i] < zoomFactor) {
5638 zoomFactor = stepping[i];
5639 break;
5641 setFontScaleFactor(zoomFactor);
5645 void KHTMLPart::setFontScaleFactor(int percent)
5647 if (percent < minZoom) percent = minZoom;
5648 if (percent > maxZoom) percent = maxZoom;
5649 if (d->m_fontScaleFactor == percent) return;
5650 d->m_fontScaleFactor = percent;
5652 if (d->m_view && d->m_doc) {
5653 QApplication::setOverrideCursor( Qt::WaitCursor );
5654 if (d->m_doc->styleSelector())
5655 d->m_doc->styleSelector()->computeFontSizes(d->m_doc->logicalDpiY(), d->m_fontScaleFactor);
5656 d->m_doc->recalcStyle( NodeImpl::Force );
5657 QApplication::restoreOverrideCursor();
5660 ConstFrameIt it = d->m_frames.constBegin();
5661 const ConstFrameIt end = d->m_frames.constEnd();
5662 for (; it != end; ++it )
5663 if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
5664 KParts::ReadOnlyPart* const p = ( *it )->m_part;
5665 static_cast<KHTMLPart*>( p )->setFontScaleFactor(d->m_fontScaleFactor);
5669 int KHTMLPart::fontScaleFactor() const
5671 return d->m_fontScaleFactor;
5674 void KHTMLPart::slotZoomView( int delta )
5676 if ( delta < 0 )
5677 slotIncZoom();
5678 else
5679 slotDecZoom();
5682 void KHTMLPart::setStatusBarText( const QString& text, StatusBarPriority p)
5684 if (!d->m_statusMessagesEnabled)
5685 return;
5687 d->m_statusBarText[p] = text;
5689 // shift handling ?
5690 QString tobe = d->m_statusBarText[BarHoverText];
5691 if (tobe.isEmpty())
5692 tobe = d->m_statusBarText[BarOverrideText];
5693 if (tobe.isEmpty()) {
5694 tobe = d->m_statusBarText[BarDefaultText];
5695 if (!tobe.isEmpty() && d->m_jobspeed)
5696 tobe += " ";
5697 if (d->m_jobspeed)
5698 tobe += i18n( "(%1/s)" , KIO::convertSize( d->m_jobspeed ) );
5700 tobe = "<qt>"+tobe;
5702 emit ReadOnlyPart::setStatusBarText(tobe);
5706 void KHTMLPart::setJSStatusBarText( const QString &text )
5708 setStatusBarText(text, BarOverrideText);
5711 void KHTMLPart::setJSDefaultStatusBarText( const QString &text )
5713 setStatusBarText(text, BarDefaultText);
5716 QString KHTMLPart::jsStatusBarText() const
5718 return d->m_statusBarText[BarOverrideText];
5721 QString KHTMLPart::jsDefaultStatusBarText() const
5723 return d->m_statusBarText[BarDefaultText];
5726 QString KHTMLPart::referrer() const
5728 return d->m_referrer;
5731 QString KHTMLPart::pageReferrer() const
5733 KUrl referrerURL = KUrl( d->m_pageReferrer );
5734 if (referrerURL.isValid())
5736 QString protocol = referrerURL.protocol();
5738 if ((protocol == "http") ||
5739 ((protocol == "https") && (url().protocol() == "https")))
5741 referrerURL.setRef(QString());
5742 referrerURL.setUser(QString());
5743 referrerURL.setPass(QString());
5744 return referrerURL.url();
5748 return QString();
5752 QString KHTMLPart::lastModified() const
5754 if ( d->m_lastModified.isEmpty() && url().isLocalFile() ) {
5755 // Local file: set last-modified from the file's mtime.
5756 // Done on demand to save time when this isn't needed - but can lead
5757 // to slightly wrong results if updating the file on disk w/o reloading.
5758 QDateTime lastModif = QFileInfo( url().toLocalFile() ).lastModified();
5759 d->m_lastModified = lastModif.toString( Qt::LocalDate );
5761 //kDebug(6050) << d->m_lastModified;
5762 return d->m_lastModified;
5765 void KHTMLPart::slotLoadImages()
5767 if (d->m_doc )
5768 d->m_doc->docLoader()->setAutoloadImages( !d->m_doc->docLoader()->autoloadImages() );
5770 ConstFrameIt it = d->m_frames.constBegin();
5771 const ConstFrameIt end = d->m_frames.constEnd();
5772 for (; it != end; ++it )
5773 if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
5774 KParts::ReadOnlyPart* const p = ( *it )->m_part;
5775 static_cast<KHTMLPart*>( p )->slotLoadImages();
5779 void KHTMLPart::reparseConfiguration()
5781 KHTMLSettings *settings = KHTMLGlobal::defaultHTMLSettings();
5782 settings->init();
5784 setAutoloadImages( settings->autoLoadImages() );
5785 if (d->m_doc)
5786 d->m_doc->docLoader()->setShowAnimations( settings->showAnimations() );
5788 d->m_bOpenMiddleClick = settings->isOpenMiddleClickEnabled();
5789 d->m_bBackRightClick = settings->isBackRightClickEnabled();
5790 d->m_bJScriptEnabled = settings->isJavaScriptEnabled(url().host());
5791 setDebugScript( settings->isJavaScriptDebugEnabled() );
5792 d->m_bJavaEnabled = settings->isJavaEnabled(url().host());
5793 d->m_bPluginsEnabled = settings->isPluginsEnabled(url().host());
5794 d->m_metaRefreshEnabled = settings->isAutoDelayedActionsEnabled ();
5796 delete d->m_settings;
5797 d->m_settings = new KHTMLSettings(*KHTMLGlobal::defaultHTMLSettings());
5799 QApplication::setOverrideCursor( Qt::WaitCursor );
5800 khtml::CSSStyleSelector::reparseConfiguration();
5801 if(d->m_doc) d->m_doc->updateStyleSelector();
5802 QApplication::restoreOverrideCursor();
5804 if (d->m_view) {
5805 KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling();
5806 if (ssm == KHTMLSettings::KSmoothScrollingDisabled)
5807 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled);
5808 else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient)
5809 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient);
5810 else
5811 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled);
5814 if (KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled())
5815 runAdFilter();
5818 QStringList KHTMLPart::frameNames() const
5820 QStringList res;
5822 ConstFrameIt it = d->m_frames.constBegin();
5823 const ConstFrameIt end = d->m_frames.constEnd();
5824 for (; it != end; ++it )
5825 if (!(*it)->m_bPreloaded && (*it)->m_part)
5826 res += (*it)->m_name;
5828 return res;
5831 QList<KParts::ReadOnlyPart*> KHTMLPart::frames() const
5833 QList<KParts::ReadOnlyPart*> res;
5835 ConstFrameIt it = d->m_frames.constBegin();
5836 const ConstFrameIt end = d->m_frames.constEnd();
5837 for (; it != end; ++it )
5838 if (!(*it)->m_bPreloaded && (*it)->m_part) // ### TODO: make sure that we always create an empty
5839 // KHTMLPart for frames so this never happens.
5840 res.append( (*it)->m_part );
5842 return res;
5845 bool KHTMLPart::openUrlInFrame( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs)
5847 kDebug( 6050 ) << this << url;
5848 FrameIt it = d->m_frames.find( browserArgs.frameName );
5850 if ( it == d->m_frames.end() )
5851 return false;
5853 // Inform someone that we are about to show something else.
5854 if ( !browserArgs.lockHistory() )
5855 emit d->m_extension->openUrlNotify();
5857 requestObject( *it, url, args, browserArgs );
5859 return true;
5862 void KHTMLPart::setDNDEnabled( bool b )
5864 d->m_bDnd = b;
5867 bool KHTMLPart::dndEnabled() const
5869 return d->m_bDnd;
5872 void KHTMLPart::customEvent( QEvent *event )
5874 if ( khtml::MousePressEvent::test( event ) )
5876 khtmlMousePressEvent( static_cast<khtml::MousePressEvent *>( event ) );
5877 return;
5880 if ( khtml::MouseDoubleClickEvent::test( event ) )
5882 khtmlMouseDoubleClickEvent( static_cast<khtml::MouseDoubleClickEvent *>( event ) );
5883 return;
5886 if ( khtml::MouseMoveEvent::test( event ) )
5888 khtmlMouseMoveEvent( static_cast<khtml::MouseMoveEvent *>( event ) );
5889 return;
5892 if ( khtml::MouseReleaseEvent::test( event ) )
5894 khtmlMouseReleaseEvent( static_cast<khtml::MouseReleaseEvent *>( event ) );
5895 return;
5898 if ( khtml::DrawContentsEvent::test( event ) )
5900 khtmlDrawContentsEvent( static_cast<khtml::DrawContentsEvent *>( event ) );
5901 return;
5904 KParts::ReadOnlyPart::customEvent( event );
5907 bool KHTMLPart::isPointInsideSelection(int x, int y)
5909 // Treat a collapsed selection like no selection.
5910 if (d->editor_context.m_selection.state() == Selection::CARET)
5911 return false;
5912 if (!xmlDocImpl()->renderer())
5913 return false;
5915 khtml::RenderObject::NodeInfo nodeInfo(true, true);
5916 xmlDocImpl()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y);
5917 NodeImpl *innerNode = nodeInfo.innerNode();
5918 if (!innerNode || !innerNode->renderer())
5919 return false;
5921 return innerNode->isPointInsideSelection(x, y, d->editor_context.m_selection);
5924 /** returns the position of the first inline text box of the line at
5925 * coordinate y in renderNode
5927 * This is a helper function for line-by-line text selection.
5929 static bool firstRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
5931 for (khtml::RenderObject *n = renderNode; n; n = n->nextSibling()) {
5932 if (n->isText()) {
5933 khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
5934 for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
5935 if (box->m_y == y && textRenderer->element()) {
5936 startNode = textRenderer->element();
5937 startOffset = box->m_start;
5938 return true;
5943 if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
5944 return true;
5948 return false;
5951 /** returns the position of the last inline text box of the line at
5952 * coordinate y in renderNode
5954 * This is a helper function for line-by-line text selection.
5956 static bool lastRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
5958 khtml::RenderObject *n = renderNode;
5959 if (!n) {
5960 return false;
5962 khtml::RenderObject *next;
5963 while ((next = n->nextSibling())) {
5964 n = next;
5967 while (1) {
5968 if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
5969 return true;
5972 if (n->isText()) {
5973 khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
5974 for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
5975 if (box->m_y == y && textRenderer->element()) {
5976 endNode = textRenderer->element();
5977 endOffset = box->m_start + box->m_len;
5978 return true;
5983 if (n == renderNode) {
5984 return false;
5987 n = n->previousSibling();
5991 void KHTMLPart::handleMousePressEventDoubleClick(khtml::MouseDoubleClickEvent *event)
5993 QMouseEvent *mouse = event->qmouseEvent();
5994 DOM::Node innerNode = event->innerNode();
5996 Selection selection;
5998 if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() &&
5999 innerNode.handle()->renderer()->shouldSelect()) {
6000 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()));
6001 if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
6002 selection.moveTo(pos);
6003 selection.expandUsingGranularity(Selection::WORD);
6007 if (selection.state() != Selection::CARET) {
6008 d->editor_context.beginSelectingText(Selection::WORD);
6011 setCaret(selection);
6012 startAutoScroll();
6015 void KHTMLPart::handleMousePressEventTripleClick(khtml::MouseDoubleClickEvent *event)
6017 QMouseEvent *mouse = event->qmouseEvent();
6018 DOM::Node innerNode = event->innerNode();
6020 Selection selection;
6022 if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() &&
6023 innerNode.handle()->renderer()->shouldSelect()) {
6024 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()));
6025 if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
6026 selection.moveTo(pos);
6027 selection.expandUsingGranularity(Selection::LINE);
6031 if (selection.state() != Selection::CARET) {
6032 d->editor_context.beginSelectingText(Selection::LINE);
6035 setCaret(selection);
6036 startAutoScroll();
6039 void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event)
6041 QMouseEvent *mouse = event->qmouseEvent();
6042 DOM::Node innerNode = event->innerNode();
6044 if (mouse->button() == Qt::LeftButton) {
6045 Selection sel;
6047 if (!innerNode.isNull() && innerNode.handle()->renderer() &&
6048 innerNode.handle()->renderer()->shouldSelect()) {
6049 bool extendSelection = mouse->modifiers() & Qt::ShiftModifier;
6051 // Don't restart the selection when the mouse is pressed on an
6052 // existing selection so we can allow for text dragging.
6053 if (!extendSelection && isPointInsideSelection(event->x(), event->y())) {
6054 return;
6056 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()));
6057 if (pos.isEmpty())
6058 pos = Position(innerNode.handle(), innerNode.handle()->caretMinOffset());
6060 sel = caret();
6061 if (extendSelection && sel.notEmpty()) {
6062 sel.clearModifyBias();
6063 sel.setExtent(pos);
6064 if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
6065 sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
6067 d->editor_context.m_beganSelectingText = true;
6068 } else {
6069 sel = pos;
6070 d->editor_context.m_selectionGranularity = Selection::CHARACTER;
6074 setCaret(sel);
6075 startAutoScroll();
6079 void KHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent *event )
6081 DOM::DOMString url = event->url();
6082 QMouseEvent *_mouse = event->qmouseEvent();
6083 DOM::Node innerNode = event->innerNode();
6084 d->m_mousePressNode = innerNode;
6086 d->m_dragStartPos = QPoint(event->x(), event->y());
6088 if ( !event->url().isNull() ) {
6089 d->m_strSelectedURL = event->url().string();
6090 d->m_strSelectedURLTarget = event->target().string();
6092 else {
6093 d->m_strSelectedURL.clear();
6094 d->m_strSelectedURLTarget.clear();
6097 if ( _mouse->button() == Qt::LeftButton ||
6098 _mouse->button() == Qt::MidButton )
6100 d->m_bMousePressed = true;
6102 #ifdef KHTML_NO_SELECTION
6103 d->m_dragLastPos = _mouse->globalPos();
6104 #else
6105 if ( _mouse->button() == Qt::LeftButton )
6107 if ( (!d->m_strSelectedURL.isNull() && !isEditable())
6108 || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) )
6109 return;
6111 d->editor_context.m_beganSelectingText = false;
6113 handleMousePressEventSingleClick(event);
6115 #endif
6118 if ( _mouse->button() == Qt::RightButton && parentPart() != 0 && d->m_bBackRightClick )
6120 d->m_bRightMousePressed = true;
6121 } else if ( _mouse->button() == Qt::RightButton )
6123 popupMenu( d->m_strSelectedURL );
6124 // might be deleted, don't touch "this"
6128 void KHTMLPart::khtmlMouseDoubleClickEvent( khtml::MouseDoubleClickEvent *event )
6130 QMouseEvent *_mouse = event->qmouseEvent();
6131 if ( _mouse->button() == Qt::LeftButton )
6133 d->m_bMousePressed = true;
6134 d->editor_context.m_beganSelectingText = false;
6136 if (event->clickCount() == 2) {
6137 handleMousePressEventDoubleClick(event);
6138 return;
6141 if (event->clickCount() >= 3) {
6142 handleMousePressEventTripleClick(event);
6143 return;
6148 #ifndef KHTML_NO_SELECTION
6149 bool KHTMLPart::isExtendingSelection() const
6151 // This is it, the whole detection. khtmlMousePressEvent only sets this
6152 // on LMB or MMB, but never on RMB. As text selection doesn't work for MMB,
6153 // it's sufficient to only rely on this flag to detect selection extension.
6154 return d->editor_context.m_beganSelectingText;
6157 void KHTMLPart::extendSelectionTo(int x, int y, const DOM::Node &innerNode)
6159 // handle making selection
6160 Position pos(innerNode.handle()->positionForCoordinates(x, y));
6162 // Don't modify the selection if we're not on a node.
6163 if (pos.isEmpty())
6164 return;
6166 // Restart the selection if this is the first mouse move. This work is usually
6167 // done in khtmlMousePressEvent, but not if the mouse press was on an existing selection.
6168 Selection sel = caret();
6169 sel.clearModifyBias();
6170 if (!d->editor_context.m_beganSelectingText) {
6171 // We are beginning a selection during press-drag, when the original click
6172 // wasn't appropriate for one. Make sure to set the granularity.
6173 d->editor_context.beginSelectingText(Selection::CHARACTER);
6174 sel.moveTo(pos);
6177 sel.setExtent(pos);
6178 if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
6179 sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
6181 setCaret(sel);
6184 #endif // KHTML_NO_SELECTION
6186 bool KHTMLPart::handleMouseMoveEventDrag(khtml::MouseMoveEvent *event)
6188 #ifdef QT_NO_DRAGANDDROP
6189 return false;
6190 #else
6191 DOM::Node innerNode = event->innerNode();
6193 if( (d->m_bMousePressed &&
6194 ( (!d->m_strSelectedURL.isEmpty() && !isEditable())
6195 || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) ) )
6196 && ( d->m_dragStartPos - QPoint(event->x(), event->y()) ).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
6198 DOM::DOMString url = event->url();
6200 QPixmap pix;
6201 HTMLImageElementImpl *img = 0L;
6202 KUrl u;
6204 // qDebug("****************** Event URL: %s", url.string().toLatin1().constData());
6205 // qDebug("****************** Event Target: %s", target.string().toLatin1().constData());
6207 // Normal image...
6208 if ( url.length() == 0 && innerNode.handle() && innerNode.handle()->id() == ID_IMG )
6210 img = static_cast<HTMLImageElementImpl *>(innerNode.handle());
6211 u = KUrl( completeURL( khtml::parseURL(img->getAttribute(ATTR_SRC)).string() ) );
6212 pix = KIconLoader::global()->loadIcon("image-x-generic", KIconLoader::Desktop);
6214 else
6216 // Text or image link...
6217 u = completeURL( d->m_strSelectedURL );
6218 pix = KIO::pixmapForUrl(u, 0, KIconLoader::Desktop, KIconLoader::SizeMedium);
6221 u.setPass(QString());
6223 QDrag *drag = new QDrag( d->m_view->viewport() );
6224 QMap<QString, QString> metaDataMap;
6225 if ( !d->m_referrer.isEmpty() )
6226 metaDataMap.insert( "referrer", d->m_referrer );
6227 QMimeData* mimeData = new QMimeData();
6228 u.populateMimeData( mimeData, metaDataMap );
6229 drag->setMimeData( mimeData );
6231 if( img && img->complete() )
6232 drag->mimeData()->setImageData( img->currentImage() );
6234 if ( !pix.isNull() )
6235 drag->setPixmap( pix );
6237 stopAutoScroll();
6238 drag->start();
6240 // when we finish our drag, we need to undo our mouse press
6241 d->m_bMousePressed = false;
6242 d->m_strSelectedURL.clear();
6243 d->m_strSelectedURLTarget.clear();
6244 return true;
6246 return false;
6247 #endif // QT_NO_DRAGANDDROP
6250 bool KHTMLPart::handleMouseMoveEventOver(khtml::MouseMoveEvent *event)
6252 // Mouse clicked -> do nothing
6253 if ( d->m_bMousePressed ) return false;
6255 DOM::DOMString url = event->url();
6257 // The mouse is over something
6258 if ( url.length() )
6260 DOM::DOMString target = event->target();
6261 QMouseEvent *_mouse = event->qmouseEvent();
6262 DOM::Node innerNode = event->innerNode();
6264 bool shiftPressed = ( _mouse->modifiers() & Qt::ShiftModifier );
6266 // Image map
6267 if ( !innerNode.isNull() && innerNode.elementId() == ID_IMG )
6269 HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
6270 if ( i && i->isServerMap() )
6272 khtml::RenderObject *r = i->renderer();
6273 if(r)
6275 int absx, absy;
6276 r->absolutePosition(absx, absy);
6277 int x(event->x() - absx), y(event->y() - absy);
6279 d->m_overURL = url.string() + QString("?%1,%2").arg(x).arg(y);
6280 d->m_overURLTarget = target.string();
6281 overURL( d->m_overURL, target.string(), shiftPressed );
6282 return true;
6287 // normal link
6288 if ( d->m_overURL.isEmpty() || d->m_overURL != url || d->m_overURLTarget != target )
6290 d->m_overURL = url.string();
6291 d->m_overURLTarget = target.string();
6292 overURL( d->m_overURL, target.string(), shiftPressed );
6295 else // Not over a link...
6297 if( !d->m_overURL.isEmpty() ) // and we were over a link -> reset to "default statusbar text"
6299 // reset to "default statusbar text"
6300 resetHoverText();
6303 return true;
6306 void KHTMLPart::handleMouseMoveEventSelection(khtml::MouseMoveEvent *event)
6308 // Mouse not pressed. Do nothing.
6309 if (!d->m_bMousePressed)
6310 return;
6312 #ifdef KHTML_NO_SELECTION
6313 if (d->m_doc && d->m_view) {
6314 QPoint diff( mouse->globalPos() - d->m_dragLastPos );
6316 if (abs(diff.x()) > 64 || abs(diff.y()) > 64) {
6317 d->m_view->scrollBy(-diff.x(), -diff.y());
6318 d->m_dragLastPos = mouse->globalPos();
6321 #else
6323 QMouseEvent *mouse = event->qmouseEvent();
6324 DOM::Node innerNode = event->innerNode();
6326 if ( (mouse->buttons() & Qt::LeftButton) == 0 || !innerNode.handle() || !innerNode.handle()->renderer() ||
6327 !innerNode.handle()->renderer()->shouldSelect())
6328 return;
6330 // handle making selection
6331 extendSelectionTo(event->x(), event->y(), innerNode);
6332 #endif // KHTML_NO_SELECTION
6335 void KHTMLPart::khtmlMouseMoveEvent( khtml::MouseMoveEvent *event )
6337 if (handleMouseMoveEventDrag(event))
6338 return;
6340 if (handleMouseMoveEventOver(event))
6341 return;
6343 handleMouseMoveEventSelection(event);
6346 void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
6348 DOM::Node innerNode = event->innerNode();
6349 d->m_mousePressNode = DOM::Node();
6351 if ( d->m_bMousePressed ) {
6352 setStatusBarText(QString(), BarHoverText);
6353 stopAutoScroll();
6356 // Used to prevent mouseMoveEvent from initiating a drag before
6357 // the mouse is pressed again.
6358 d->m_bMousePressed = false;
6360 QMouseEvent *_mouse = event->qmouseEvent();
6361 if ( _mouse->button() == Qt::RightButton && parentPart() != 0 && d->m_bBackRightClick )
6363 d->m_bRightMousePressed = false;
6364 KParts::BrowserInterface *tmp_iface = d->m_extension->browserInterface();
6365 if( tmp_iface ) {
6366 tmp_iface->callMethod( "goHistory", -1 );
6369 #ifndef QT_NO_CLIPBOARD
6370 if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == Qt::MidButton) && (event->url().isNull())) {
6371 kDebug( 6050 ) << "MMB shouldOpen=" << d->m_bOpenMiddleClick;
6373 if (d->m_bOpenMiddleClick) {
6374 KHTMLPart *p = this;
6375 while (p->parentPart()) p = p->parentPart();
6376 p->d->m_extension->pasteRequest();
6379 #endif
6381 #ifndef KHTML_NO_SELECTION
6384 // Clear the selection if the mouse didn't move after the last mouse press.
6385 // We do this so when clicking on the selection, the selection goes away.
6386 // However, if we are editing, place the caret.
6387 if (!d->editor_context.m_beganSelectingText
6388 && d->m_dragStartPos.x() == event->x()
6389 && d->m_dragStartPos.y() == event->y()
6390 && d->editor_context.m_selection.state() == Selection::RANGE) {
6391 Selection selection;
6392 #ifdef APPLE_CHANGES
6393 if (d->editor_context.m_selection.base().node()->isContentEditable())
6394 #endif
6395 selection.moveTo(d->editor_context.m_selection.base().node()->positionForCoordinates(event->x(), event->y()));
6396 setCaret(selection);
6398 // get selected text and paste to the clipboard
6399 #ifndef QT_NO_CLIPBOARD
6400 QString text = selectedText();
6401 text.replace(QChar(0xa0), ' ');
6402 if (!text.isEmpty()) {
6403 disconnect( qApp->clipboard(), SIGNAL( selectionChanged()), this, SLOT( slotClearSelection()));
6404 qApp->clipboard()->setText(text,QClipboard::Selection);
6405 connect( qApp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
6407 #endif
6408 //kDebug( 6000 ) << "selectedText = " << text;
6409 emitSelectionChanged();
6410 //kDebug(6000) << "rel2: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << "), caretOfs " << d->caretOffset();
6412 #endif
6415 void KHTMLPart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * )
6419 void KHTMLPart::guiActivateEvent( KParts::GUIActivateEvent *event )
6421 if ( event->activated() )
6423 emitSelectionChanged();
6424 emit d->m_extension->enableAction( "print", d->m_doc != 0 );
6426 if ( !d->m_settings->autoLoadImages() && d->m_paLoadImages )
6428 QList<QAction*> lst;
6429 lst.append( d->m_paLoadImages );
6430 plugActionList( "loadImages", lst );
6435 void KHTMLPart::slotPrintFrame()
6437 if ( d->m_frames.count() == 0 )
6438 return;
6440 KParts::ReadOnlyPart *frame = currentFrame();
6441 if (!frame)
6442 return;
6444 KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject( frame );
6446 if ( !ext )
6447 return;
6450 const QMetaObject *mo = ext->metaObject();
6453 if (mo->indexOfSlot( "print()") != -1)
6454 QMetaObject::invokeMethod(ext, "print()", Qt::DirectConnection);
6457 void KHTMLPart::slotSelectAll()
6459 KParts::ReadOnlyPart *part = currentFrame();
6460 if (part && part->inherits("KHTMLPart"))
6461 static_cast<KHTMLPart *>(part)->selectAll();
6464 void KHTMLPart::startAutoScroll()
6466 connect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ));
6467 d->m_scrollTimer.setSingleShot(false);
6468 d->m_scrollTimer.start(100);
6471 void KHTMLPart::stopAutoScroll()
6473 disconnect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ));
6474 if (d->m_scrollTimer.isActive())
6475 d->m_scrollTimer.stop();
6479 void KHTMLPart::slotAutoScroll()
6481 if (d->m_view)
6482 d->m_view->doAutoScroll();
6483 else
6484 stopAutoScroll(); // Safety
6487 void KHTMLPart::runAdFilter()
6489 if ( parentPart() )
6490 parentPart()->runAdFilter();
6492 if ( !d->m_doc )
6493 return;
6495 QSetIterator<khtml::CachedObject*> it( d->m_doc->docLoader()->m_docObjects );
6496 while (it.hasNext())
6498 khtml::CachedObject* obj = it.next();
6499 if ( obj->type() == khtml::CachedObject::Image ) {
6500 khtml::CachedImage *image = static_cast<khtml::CachedImage *>(obj);
6501 bool wasBlocked = image->m_wasBlocked;
6502 image->m_wasBlocked = KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( image->url().string() ) );
6503 if ( image->m_wasBlocked != wasBlocked )
6504 image->do_notify(QRect(QPoint(0,0), image->pixmap_size()));
6508 if ( KHTMLGlobal::defaultHTMLSettings()->isHideAdsEnabled() ) {
6509 for ( NodeImpl *nextNode, *node = d->m_doc; node; node = nextNode ) {
6511 // We might be deleting 'node' shortly.
6512 nextNode = node->traverseNextNode();
6514 if ( node->id() == ID_IMG ||
6515 node->id() == ID_IFRAME ||
6516 (node->id() == ID_INPUT && static_cast<HTMLInputElementImpl *>(node)->inputType() == HTMLInputElementImpl::IMAGE ))
6518 if ( KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( static_cast<ElementImpl *>(node)->getAttribute(ATTR_SRC).string() ) ) )
6520 // We found an IMG, IFRAME or INPUT (of type IMAGE) matching a filter.
6521 node->ref();
6522 NodeImpl *parent = node->parent();
6523 if( parent )
6525 int exception = 0;
6526 parent->removeChild(node, exception);
6528 node->deref();
6535 void KHTMLPart::selectAll()
6537 if (!d->m_doc) return;
6539 NodeImpl *first;
6540 if (d->m_doc->isHTMLDocument())
6541 first = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
6542 else
6543 first = d->m_doc;
6544 NodeImpl *next;
6546 // Look for first text/cdata node that has a renderer,
6547 // or first childless replaced element
6548 while ( first && !(first->renderer()
6549 && ((first->nodeType() == Node::TEXT_NODE || first->nodeType() == Node::CDATA_SECTION_NODE)
6550 || (first->renderer()->isReplaced() && !first->renderer()->firstChild()))))
6552 next = first->firstChild();
6553 if ( !next ) next = first->nextSibling();
6554 while( first && !next )
6556 first = first->parentNode();
6557 if ( first )
6558 next = first->nextSibling();
6560 first = next;
6563 NodeImpl *last;
6564 if (d->m_doc->isHTMLDocument())
6565 last = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
6566 else
6567 last = d->m_doc;
6568 // Look for last text/cdata node that has a renderer,
6569 // or last childless replaced element
6570 // ### Instead of changing this loop, use findLastSelectableNode
6571 // in render_table.cpp (LS)
6572 while ( last && !(last->renderer()
6573 && ((last->nodeType() == Node::TEXT_NODE || last->nodeType() == Node::CDATA_SECTION_NODE)
6574 || (last->renderer()->isReplaced() && !last->renderer()->lastChild()))))
6576 next = last->lastChild();
6577 if ( !next ) next = last->previousSibling();
6578 while ( last && !next )
6580 last = last->parentNode();
6581 if ( last )
6582 next = last->previousSibling();
6584 last = next;
6587 if ( !first || !last )
6588 return;
6589 Q_ASSERT(first->renderer());
6590 Q_ASSERT(last->renderer());
6591 d->editor_context.m_selection.moveTo(Position(first, 0), Position(last, last->nodeValue().length()));
6592 d->m_doc->updateSelection();
6594 emitSelectionChanged();
6597 bool KHTMLPart::checkLinkSecurity(const KUrl &linkURL,const KLocalizedString &message, const QString &button)
6599 bool linkAllowed = true;
6601 if ( d->m_doc )
6602 linkAllowed = KAuthorized::authorizeUrlAction("redirect", url(), linkURL);
6604 if ( !linkAllowed ) {
6605 khtml::Tokenizer *tokenizer = d->m_doc->tokenizer();
6606 if (tokenizer)
6607 tokenizer->setOnHold(true);
6609 int response = KMessageBox::Cancel;
6610 if (!message.isEmpty())
6612 // Dangerous flag makes the Cancel button the default
6613 response = KMessageBox::warningContinueCancel( 0,
6614 message.subs(Qt::escape(linkURL.prettyUrl())).toString(),
6615 i18n( "Security Warning" ),
6616 KGuiItem(button),
6617 KStandardGuiItem::cancel(),
6618 QString(), // no don't ask again info
6619 KMessageBox::Notify | KMessageBox::Dangerous );
6621 else
6623 KMessageBox::error( 0,
6624 i18n( "<qt>Access by untrusted page to<br /><b>%1</b><br /> denied.</qt>", Qt::escape(linkURL.prettyUrl())),
6625 i18n( "Security Alert" ));
6628 if (tokenizer)
6629 tokenizer->setOnHold(false);
6630 return (response==KMessageBox::Continue);
6632 return true;
6635 void KHTMLPart::slotPartRemoved( KParts::Part *part )
6637 // kDebug(6050) << part;
6638 if ( part == d->m_activeFrame )
6640 d->m_activeFrame = 0L;
6641 if ( !part->inherits( "KHTMLPart" ) )
6643 if (factory()) {
6644 factory()->removeClient( part );
6646 if (childClients().contains(part)) {
6647 removeChildClient( part );
6653 void KHTMLPart::slotActiveFrameChanged( KParts::Part *part )
6655 // kDebug(6050) << this << "part=" << part;
6656 if ( part == this )
6658 kError(6050) << "strange error! we activated ourselves";
6659 assert( false );
6660 return;
6662 // kDebug(6050) << "d->m_activeFrame=" << d->m_activeFrame;
6663 if ( d->m_activeFrame && d->m_activeFrame->widget() && d->m_activeFrame->widget()->inherits( "QFrame" ) )
6665 QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
6666 if (frame->frameStyle() != QFrame::NoFrame)
6668 frame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken);
6669 frame->repaint();
6673 if( d->m_activeFrame && !d->m_activeFrame->inherits( "KHTMLPart" ) )
6675 if (factory()) {
6676 factory()->removeClient( d->m_activeFrame );
6678 removeChildClient( d->m_activeFrame );
6680 if( part && !part->inherits( "KHTMLPart" ) )
6682 if (factory()) {
6683 factory()->addClient( part );
6685 insertChildClient( part );
6689 d->m_activeFrame = part;
6691 if ( d->m_activeFrame && d->m_activeFrame->widget()->inherits( "QFrame" ) )
6693 QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
6694 if (frame->frameStyle() != QFrame::NoFrame)
6696 frame->setFrameStyle( QFrame::StyledPanel | QFrame::Plain);
6697 frame->repaint();
6699 kDebug(6050) << "new active frame " << d->m_activeFrame;
6702 updateActions();
6704 // (note: childObject returns 0 if the argument is 0)
6705 d->m_extension->setExtensionProxy( KParts::BrowserExtension::childObject( d->m_activeFrame ) );
6708 void KHTMLPart::setActiveNode(const DOM::Node &node)
6710 if (!d->m_doc || !d->m_view)
6711 return;
6713 // Set the document's active node
6714 d->m_doc->setFocusNode(node.handle());
6716 // Scroll the view if necessary to ensure that the new focus node is visible
6717 QRect rect = node.handle()->getRect();
6718 d->m_view->ensureVisible(rect.right(), rect.bottom());
6719 d->m_view->ensureVisible(rect.left(), rect.top());
6722 DOM::Node KHTMLPart::activeNode() const
6724 return DOM::Node(d->m_doc?d->m_doc->focusNode():0);
6727 DOM::EventListener *KHTMLPart::createHTMLEventListener( QString code, QString name, NodeImpl* node, bool svg )
6729 KJSProxy *proxy = jScript();
6731 if (!proxy)
6732 return 0;
6734 return proxy->createHTMLEventHandler( url().url(), name, code, node, svg );
6737 KHTMLPart *KHTMLPart::opener()
6739 return d->m_opener;
6742 void KHTMLPart::setOpener(KHTMLPart *_opener)
6744 d->m_opener = _opener;
6747 bool KHTMLPart::openedByJS()
6749 return d->m_openedByJS;
6752 void KHTMLPart::setOpenedByJS(bool _openedByJS)
6754 d->m_openedByJS = _openedByJS;
6757 void KHTMLPart::preloadStyleSheet(const QString &url, const QString &stylesheet)
6759 khtml::Cache::preloadStyleSheet(url, stylesheet);
6762 void KHTMLPart::preloadScript(const QString &url, const QString &script)
6764 khtml::Cache::preloadScript(url, script);
6767 long KHTMLPart::cacheId() const
6769 return d->m_cacheId;
6772 bool KHTMLPart::restored() const
6774 return d->m_restored;
6777 bool KHTMLPart::pluginPageQuestionAsked(const QString& mimetype) const
6779 // parentPart() should be const!
6780 KHTMLPart* parent = const_cast<KHTMLPart *>(this)->parentPart();
6781 if ( parent )
6782 return parent->pluginPageQuestionAsked(mimetype);
6784 return d->m_pluginPageQuestionAsked.contains(mimetype);
6787 void KHTMLPart::setPluginPageQuestionAsked(const QString& mimetype)
6789 if ( parentPart() )
6790 parentPart()->setPluginPageQuestionAsked(mimetype);
6792 d->m_pluginPageQuestionAsked.append(mimetype);
6795 KEncodingDetector *KHTMLPart::createDecoder()
6797 KEncodingDetector *dec = new KEncodingDetector();
6798 if( !d->m_encoding.isNull() )
6799 dec->setEncoding( d->m_encoding.toLatin1().constData(),
6800 d->m_haveEncoding ? KEncodingDetector::UserChosenEncoding : KEncodingDetector::EncodingFromHTTPHeader);
6801 else {
6802 // Inherit the default encoding from the parent frame if there is one.
6803 QByteArray defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
6804 ? QByteArray( parentPart()->d->m_decoder->encoding() ) : settings()->encoding().toLatin1();
6805 dec->setEncoding(defaultEncoding.constData(), KEncodingDetector::DefaultEncoding);
6807 #ifdef APPLE_CHANGES
6808 if (d->m_doc)
6809 d->m_doc->setDecoder(d->m_decoder);
6810 #endif
6811 dec->setAutoDetectLanguage( d->m_autoDetectLanguage );
6812 return dec;
6815 void KHTMLPart::emitCaretPositionChanged(const DOM::Position &pos) {
6816 // pos must not be already converted to range-compliant coordinates
6817 Position rng_pos = pos.equivalentRangeCompliantPosition();
6818 Node node = rng_pos.node();
6819 emit caretPositionChanged(node, rng_pos.offset());
6822 void KHTMLPart::restoreScrollPosition()
6824 const KParts::OpenUrlArguments args( arguments() );
6826 if ( url().hasRef() && !d->m_restoreScrollPosition && !args.reload()) {
6827 if ( !d->m_doc || !d->m_doc->parsing() )
6828 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
6829 if ( !gotoAnchor(url().encodedHtmlRef()) )
6830 gotoAnchor(url().htmlRef());
6831 return;
6834 // Check whether the viewport has become large enough to encompass the stored
6835 // offsets. If the document has been fully loaded, force the new coordinates,
6836 // even if the canvas is too short (can happen when user resizes the window
6837 // during loading).
6838 if (d->m_view->contentsHeight() - d->m_view->visibleHeight() >= args.yOffset()
6839 || d->m_bComplete) {
6840 d->m_view->setContentsPos(args.xOffset(), args.yOffset());
6841 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
6846 void KHTMLPart::openWallet(DOM::HTMLFormElementImpl *form)
6848 #ifndef KHTML_NO_WALLET
6849 KHTMLPart *p;
6851 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
6854 if (p) {
6855 p->openWallet(form);
6856 return;
6859 if (onlyLocalReferences()) { // avoid triggering on local apps, thumbnails
6860 return;
6863 if (d->m_wallet) {
6864 if (d->m_bWalletOpened) {
6865 if (d->m_wallet->isOpen()) {
6866 form->walletOpened(d->m_wallet);
6867 return;
6869 d->m_wallet->deleteLater();
6870 d->m_wallet = 0L;
6871 d->m_bWalletOpened = false;
6875 if (!d->m_wq) {
6876 KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
6877 d->m_wq = new KHTMLWalletQueue(this);
6878 d->m_wq->wallet = wallet;
6879 connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
6880 connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
6882 assert(form);
6883 d->m_wq->callers.append(KHTMLWalletQueue::Caller(form, form->document()));
6884 #endif // KHTML_NO_WALLET
6888 void KHTMLPart::saveToWallet(const QString& key, const QMap<QString,QString>& data)
6890 #ifndef KHTML_NO_WALLET
6891 KHTMLPart *p;
6893 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
6896 if (p) {
6897 p->saveToWallet(key, data);
6898 return;
6901 if (d->m_wallet) {
6902 if (d->m_bWalletOpened) {
6903 if (d->m_wallet->isOpen()) {
6904 if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder())) {
6905 d->m_wallet->createFolder(KWallet::Wallet::FormDataFolder());
6907 d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder());
6908 d->m_wallet->writeMap(key, data);
6909 return;
6911 d->m_wallet->deleteLater();
6912 d->m_wallet = 0L;
6913 d->m_bWalletOpened = false;
6917 if (!d->m_wq) {
6918 KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
6919 d->m_wq = new KHTMLWalletQueue(this);
6920 d->m_wq->wallet = wallet;
6921 connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
6922 connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
6924 d->m_wq->savers.append(qMakePair(key, data));
6925 #endif // KHTML_NO_WALLET
6929 void KHTMLPart::dequeueWallet(DOM::HTMLFormElementImpl *form) {
6930 #ifndef KHTML_NO_WALLET
6931 KHTMLPart *p;
6933 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
6936 if (p) {
6937 p->dequeueWallet(form);
6938 return;
6941 if (d->m_wq) {
6942 d->m_wq->callers.removeAll(KHTMLWalletQueue::Caller(form, form->document()));
6944 #endif // KHTML_NO_WALLET
6948 void KHTMLPart::walletOpened(KWallet::Wallet *wallet) {
6949 #ifndef KHTML_NO_WALLET
6950 assert(!d->m_wallet);
6951 assert(d->m_wq);
6953 d->m_wq->deleteLater(); // safe?
6954 d->m_wq = 0L;
6956 if (!wallet) {
6957 d->m_bWalletOpened = false;
6958 return;
6961 d->m_wallet = wallet;
6962 d->m_bWalletOpened = true;
6963 connect(d->m_wallet, SIGNAL(walletClosed()), SLOT(slotWalletClosed()));
6965 if (!d->m_statusBarWalletLabel) {
6966 d->m_statusBarWalletLabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
6967 d->m_statusBarWalletLabel->setFixedHeight(KHTMLGlobal::iconLoader()->currentSize(KIconLoader::Small));
6968 d->m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
6969 d->m_statusBarWalletLabel->setUseCursor(false);
6970 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarWalletLabel, 0, false);
6971 d->m_statusBarWalletLabel->setPixmap(SmallIcon("wallet-open"));
6972 connect(d->m_statusBarWalletLabel, SIGNAL(leftClickedUrl()), SLOT(launchWalletManager()));
6973 connect(d->m_statusBarWalletLabel, SIGNAL(rightClickedUrl()), SLOT(walletMenu()));
6975 d->m_statusBarWalletLabel->setToolTip(i18n("The wallet '%1' is open and being used for form data and passwords.", KWallet::Wallet::NetworkWallet()));
6976 #endif // KHTML_NO_WALLET
6980 KWallet::Wallet *KHTMLPart::wallet()
6982 #ifndef KHTML_NO_WALLET
6983 KHTMLPart *p;
6985 for (p = parentPart(); p && p->parentPart(); p = p->parentPart())
6988 if (p)
6989 return p->wallet();
6991 return d->m_wallet;
6992 #else
6993 return 0;
6994 #endif // !KHTML_NO_WALLET
6998 void KHTMLPart::slotWalletClosed()
7000 #ifndef KHTML_NO_WALLET
7001 if (d->m_wallet) {
7002 d->m_wallet->deleteLater();
7003 d->m_wallet = 0L;
7005 d->m_bWalletOpened = false;
7006 if (d->m_statusBarWalletLabel) {
7007 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarWalletLabel);
7008 delete d->m_statusBarWalletLabel;
7009 d->m_statusBarWalletLabel = 0L;
7011 #endif // KHTML_NO_WALLET
7014 void KHTMLPart::launchWalletManager()
7016 #ifndef KHTML_NO_WALLET
7017 QDBusInterface r("org.kde.kwalletmanager", "/kwalletmanager/MainWindow_1",
7018 "org.kde.KMainWindow");
7019 if (!r.isValid()) {
7020 KToolInvocation::startServiceByDesktopName("kwalletmanager_show");
7021 } else {
7022 r.call(QDBus::NoBlock, "show");
7023 r.call(QDBus::NoBlock, "raise");
7025 #endif // KHTML_NO_WALLET
7028 void KHTMLPart::walletMenu()
7030 #ifndef KHTML_NO_WALLET
7031 KMenu *m = new KMenu(0L);
7032 m->addAction(i18n("&Close Wallet"), this, SLOT(slotWalletClosed()));
7033 m->popup(QCursor::pos());
7034 #endif // KHTML_NO_WALLET
7037 void KHTMLPart::slotToggleCaretMode()
7039 setCaretMode(d->m_paToggleCaretMode->isChecked());
7042 void KHTMLPart::setFormNotification(KHTMLPart::FormNotification fn) {
7043 d->m_formNotification = fn;
7046 KHTMLPart::FormNotification KHTMLPart::formNotification() const {
7047 return d->m_formNotification;
7050 KUrl KHTMLPart::toplevelURL()
7052 KHTMLPart* part = this;
7053 while (part->parentPart())
7054 part = part->parentPart();
7056 if (!part)
7057 return KUrl();
7059 return part->url();
7062 bool KHTMLPart::isModified() const
7064 if ( !d->m_doc )
7065 return false;
7067 return d->m_doc->unsubmittedFormChanges();
7070 void KHTMLPart::setDebugScript( bool enable )
7072 unplugActionList( "debugScriptList" );
7073 if ( enable ) {
7074 if (!d->m_paDebugScript) {
7075 d->m_paDebugScript = new KAction( i18n( "JavaScript &Debugger" ), this );
7076 actionCollection()->addAction( "debugScript", d->m_paDebugScript );
7077 connect( d->m_paDebugScript, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugScript() ) );
7079 d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
7080 QList<QAction*> lst;
7081 lst.append( d->m_paDebugScript );
7082 plugActionList( "debugScriptList", lst );
7084 d->m_bJScriptDebugEnabled = enable;
7087 void KHTMLPart::setSuppressedPopupIndicator( bool enable, KHTMLPart *originPart )
7089 if ( parentPart() ) {
7090 parentPart()->setSuppressedPopupIndicator( enable, originPart );
7091 return;
7094 if ( enable && originPart ) {
7095 d->m_openableSuppressedPopups++;
7096 if ( d->m_suppressedPopupOriginParts.indexOf( originPart ) == -1 )
7097 d->m_suppressedPopupOriginParts.append( originPart );
7100 if ( enable && !d->m_statusBarPopupLabel ) {
7101 d->m_statusBarPopupLabel = new KUrlLabel( d->m_statusBarExtension->statusBar() );
7102 d->m_statusBarPopupLabel->setFixedHeight( KHTMLGlobal::iconLoader()->currentSize( KIconLoader::Small) );
7103 d->m_statusBarPopupLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ));
7104 d->m_statusBarPopupLabel->setUseCursor( false );
7105 d->m_statusBarExtension->addStatusBarItem( d->m_statusBarPopupLabel, 0, false );
7106 d->m_statusBarPopupLabel->setPixmap( SmallIcon( "window-suppressed") );
7108 d->m_statusBarPopupLabel->setToolTip(i18n("This page was prevented from opening a new window via JavaScript." ) );
7110 connect(d->m_statusBarPopupLabel, SIGNAL(leftClickedUrl()), SLOT(suppressedPopupMenu()));
7111 if (d->m_settings->jsPopupBlockerPassivePopup()) {
7112 QPixmap px;
7113 px = MainBarIcon( "window-suppressed" );
7114 KPassivePopup::message(i18n("Popup Window Blocked"),i18n("This page has attempted to open a popup window but was blocked.\nYou can click on this icon in the status bar to control this behavior\nor to open the popup."),px,d->m_statusBarPopupLabel);
7116 } else if ( !enable && d->m_statusBarPopupLabel ) {
7117 d->m_statusBarPopupLabel->setToolTip("" );
7118 d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarPopupLabel );
7119 delete d->m_statusBarPopupLabel;
7120 d->m_statusBarPopupLabel = 0L;
7124 void KHTMLPart::suppressedPopupMenu() {
7125 KMenu *m = new KMenu(0L);
7126 if ( d->m_openableSuppressedPopups )
7127 m->addAction(i18np("&Show Blocked Popup Window","&Show %1 Blocked Popup Windows", d->m_openableSuppressedPopups), this, SLOT(showSuppressedPopups()));
7128 QAction *a = m->addAction(i18n("Show Blocked Window Passive Popup &Notification"), this, SLOT(togglePopupPassivePopup()));
7129 a->setChecked(d->m_settings->jsPopupBlockerPassivePopup());
7130 m->addAction(i18n("&Configure JavaScript New Window Policies..."), this, SLOT(launchJSConfigDialog()));
7131 m->popup(QCursor::pos());
7134 void KHTMLPart::togglePopupPassivePopup() {
7135 // Same hack as in disableJSErrorExtension()
7136 d->m_settings->setJSPopupBlockerPassivePopup( !d->m_settings->jsPopupBlockerPassivePopup() );
7137 emit configurationChanged();
7140 void KHTMLPart::showSuppressedPopups() {
7141 foreach ( KHTMLPart* part, d->m_suppressedPopupOriginParts ) {
7142 if (part) {
7143 KJS::Window *w = KJS::Window::retrieveWindow( part );
7144 if (w) {
7145 w->showSuppressedWindows();
7146 w->forgetSuppressedWindows();
7150 setSuppressedPopupIndicator( false );
7151 d->m_openableSuppressedPopups = 0;
7152 d->m_suppressedPopupOriginParts.clear();
7155 // Extension to use for "view document source", "save as" etc.
7156 // Using the right extension can help the viewer get into the right mode (#40496)
7157 QString KHTMLPart::defaultExtension() const
7159 if ( !d->m_doc )
7160 return ".html";
7161 if ( !d->m_doc->isHTMLDocument() )
7162 return ".xml";
7163 return d->m_doc->htmlMode() == DOM::DocumentImpl::XHtml ? ".xhtml" : ".html";
7166 bool KHTMLPart::inProgress() const
7168 if (!d->m_bComplete || d->m_runningScripts || (d->m_doc && d->m_doc->parsing()))
7169 return true;
7171 // Any frame that hasn't completed yet ?
7172 ConstFrameIt it = d->m_frames.constBegin();
7173 const ConstFrameIt end = d->m_frames.constEnd();
7174 for (; it != end; ++it ) {
7175 if ((*it)->m_run || !(*it)->m_bCompleted)
7176 return true;
7179 return d->m_submitForm || !d->m_redirectURL.isEmpty() || d->m_redirectionTimer.isActive() || d->m_job;
7182 using namespace KParts;
7183 #include "khtml_part.moc"
7184 #include "khtmlpart_p.moc"
7185 #ifndef KHTML_NO_WALLET
7186 #include "khtml_wallet_p.moc"
7187 #endif