fix logic
[personal-kdelibs.git] / khtml / khtml_part.cpp
blob4edc2e86e36eae4d5ef1ab5449c2c37dea06b99e
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 <kactioncollection.h>
94 #include <kfiledialog.h>
95 #include <kmimetypetrader.h>
96 #include <ktemporaryfile.h>
97 #include <kglobalsettings.h>
98 #include <ktoolinvocation.h>
99 #include <kauthorized.h>
100 #include <kparts/browserinterface.h>
101 #include <kde_file.h>
102 #include <kactionmenu.h>
103 #include <ktoggleaction.h>
104 #include <kcodecaction.h>
105 #include <kselectaction.h>
107 #include <ksslinfodialog.h>
109 #include <kfileitem.h>
110 #include <kurifilter.h>
111 #include <kstatusbar.h>
112 #include <kurllabel.h>
114 #include <QtGui/QClipboard>
115 #include <QtCore/QFile>
116 #include <QtCore/QMetaEnum>
117 #include <QtGui/QTextDocument>
118 #include <QtCore/QDate>
119 #include <QtNetwork/QSslCertificate>
121 #include "khtmlpart_p.h"
122 #include "khtml_iface.h"
123 #include "kpassivepopup.h"
124 #include "kmenu.h"
125 #include "rendering/render_form.h"
126 #include <kwindowsystem.h>
127 #include <kconfiggroup.h>
129 #include "ecma/debugger/debugwindow.h"
131 // SVG
132 #include <svg/SVGDocument.h>
134 bool KHTMLPartPrivate::s_dnsInitialised = false;
136 // DNS prefetch settings
137 static const int sMaxDNSPrefetchPerPage = 42;
138 static const int sDNSPrefetchTimerDelay = 200;
139 static const int sDNSTTLSeconds = 400;
140 static const int sDNSCacheSize = 500;
143 namespace khtml {
145 class PartStyleSheetLoader : public CachedObjectClient
147 public:
148 PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
150 m_part = part;
151 m_cachedSheet = dl->requestStyleSheet(url, QString(), "text/css",
152 true /* "user sheet" */);
153 if (m_cachedSheet)
154 m_cachedSheet->ref( this );
156 virtual ~PartStyleSheetLoader()
158 if ( m_cachedSheet ) m_cachedSheet->deref(this);
160 virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet, const DOM::DOMString &, const DOM::DOMString &/*mimetype*/)
162 if ( m_part )
163 m_part->setUserStyleSheet( sheet.string() );
165 delete this;
167 virtual void error( int, const QString& ) {
168 delete this;
170 QPointer<KHTMLPart> m_part;
171 khtml::CachedCSSStyleSheet *m_cachedSheet;
175 void khtml::ChildFrame::liveConnectEvent(const unsigned long, const QString & event, const KParts::LiveConnectExtension::ArgList & args)
177 if (!m_part || !m_partContainerElement || !m_liveconnect)
178 // hmmm
179 return;
181 QString script;
182 script.sprintf("%s(", event.toLatin1().constData());
184 KParts::LiveConnectExtension::ArgList::const_iterator i = args.begin();
185 const KParts::LiveConnectExtension::ArgList::const_iterator argsBegin = i;
186 const KParts::LiveConnectExtension::ArgList::const_iterator argsEnd = args.end();
188 for ( ; i != argsEnd; ++i) {
189 if (i != argsBegin)
190 script += ",";
191 if ((*i).first == KParts::LiveConnectExtension::TypeString) {
192 script += "\"";
193 script += QString((*i).second).replace('\\', "\\\\").replace('"', "\\\"");
194 script += "\"";
195 } else
196 script += (*i).second;
198 script += ")";
199 kDebug(6050) << script;
201 KHTMLPart * part = qobject_cast<KHTMLPart*>(m_part->parent());
202 if (!part)
203 return;
204 if (!m_jscript)
205 part->framejScript(m_part);
206 if (m_jscript) {
207 // we have a jscript => a part in an iframe
208 KJS::Completion cmp;
209 m_jscript->evaluate(QString(), 1, script, 0L, &cmp);
210 } else
211 part->executeScript(DOM::Node(m_partContainerElement), script);
214 KHTMLFrameList::Iterator KHTMLFrameList::find( const QString &name )
216 Iterator it = begin();
217 const Iterator e = end();
219 for (; it!=e; ++it )
220 if ( (*it)->m_name==name )
221 break;
223 return it;
226 KHTMLPart::KHTMLPart( QWidget *parentWidget, QObject *parent, GUIProfile prof )
227 : KParts::ReadOnlyPart( parent )
229 d = 0;
230 KHTMLGlobal::registerPart( this );
231 setComponentData( KHTMLGlobal::componentData(), false );
232 init( new KHTMLView( this, parentWidget ), prof );
235 KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, GUIProfile prof )
236 : KParts::ReadOnlyPart( parent )
238 d = 0;
239 KHTMLGlobal::registerPart( this );
240 setComponentData( KHTMLGlobal::componentData(), false );
241 assert( view );
242 if (!view->part())
243 view->setPart( this );
244 init( view, prof );
247 void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
249 if ( prof == DefaultGUI )
250 setXMLFile( "khtml.rc" );
251 else if ( prof == BrowserViewGUI )
252 setXMLFile( "khtml_browser.rc" );
254 d = new KHTMLPartPrivate(this, parent());
256 d->m_view = view;
258 if (!parentPart()) {
259 QWidget *widget = new QWidget( view->parentWidget() );
260 QVBoxLayout *layout = new QVBoxLayout( widget );
261 layout->setContentsMargins( 0, 0, 0, 0 );
262 layout->setSpacing( 0 );
263 widget->setLayout( layout );
265 d->m_topViewBar = new KHTMLViewBar( KHTMLViewBar::Top, d->m_view, widget );
266 d->m_bottomViewBar = new KHTMLViewBar( KHTMLViewBar::Bottom, d->m_view, widget );
268 layout->addWidget( d->m_topViewBar );
269 layout->addWidget( d->m_view );
270 layout->addWidget( d->m_bottomViewBar );
271 setWidget( widget );
272 widget->setFocusProxy( d->m_view );
273 } else {
274 setWidget( view );
277 d->m_guiProfile = prof;
278 d->m_extension = new KHTMLPartBrowserExtension( this );
279 d->m_extension->setObjectName( "KHTMLBrowserExtension" );
280 d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
281 d->m_statusBarExtension = new KParts::StatusBarExtension( this );
282 d->m_statusBarPopupLabel = 0L;
283 d->m_openableSuppressedPopups = 0;
285 d->m_paLoadImages = 0;
286 d->m_paDebugScript = 0;
287 d->m_bMousePressed = false;
288 d->m_bRightMousePressed = false;
289 d->m_bCleared = false;
291 if ( prof == BrowserViewGUI ) {
292 d->m_paViewDocument = new KAction( i18n( "View Do&cument Source" ), this );
293 actionCollection()->addAction( "viewDocumentSource", d->m_paViewDocument );
294 d->m_paViewDocument->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_U) );
295 connect( d->m_paViewDocument, SIGNAL( triggered( bool ) ), this, SLOT( slotViewDocumentSource() ) );
297 d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), this );
298 actionCollection()->addAction( "viewFrameSource", d->m_paViewFrame );
299 connect( d->m_paViewFrame, SIGNAL( triggered( bool ) ), this, SLOT( slotViewFrameSource() ) );
301 d->m_paViewInfo = new KAction( i18n( "View Document Information" ), this );
302 actionCollection()->addAction( "viewPageInfo", d->m_paViewInfo );
303 d->m_paViewInfo->setShortcut( QKeySequence(Qt::CTRL+Qt::Key_I) );
304 connect( d->m_paViewInfo, SIGNAL( triggered( bool ) ), this, SLOT( slotViewPageInfo() ) );
306 d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), this );
307 actionCollection()->addAction( "saveBackground", d->m_paSaveBackground );
308 connect( d->m_paSaveBackground, SIGNAL( triggered( bool ) ), this, SLOT( slotSaveBackground() ) );
310 d->m_paSaveDocument = actionCollection()->addAction( KStandardAction::SaveAs, "saveDocument",
311 this, SLOT( slotSaveDocument() ) );
312 if ( parentPart() )
313 d->m_paSaveDocument->setShortcuts( KShortcut() ); // avoid clashes
315 d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), this );
316 actionCollection()->addAction( "saveFrame", d->m_paSaveFrame );
317 connect( d->m_paSaveFrame, SIGNAL( triggered( bool ) ), this, SLOT( slotSaveFrame() ) );
318 } else {
319 d->m_paViewDocument = 0;
320 d->m_paViewFrame = 0;
321 d->m_paViewInfo = 0;
322 d->m_paSaveBackground = 0;
323 d->m_paSaveDocument = 0;
324 d->m_paSaveFrame = 0;
327 d->m_paSecurity = new KAction( i18n( "SSL" ), this );
328 actionCollection()->addAction( "security", d->m_paSecurity );
329 connect( d->m_paSecurity, SIGNAL( triggered( bool ) ), this, SLOT( slotSecurity() ) );
331 d->m_paDebugRenderTree = new KAction( i18n( "Print Rendering Tree to STDOUT" ), this );
332 actionCollection()->addAction( "debugRenderTree", d->m_paDebugRenderTree );
333 connect( d->m_paDebugRenderTree, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugRenderTree() ) );
335 d->m_paDebugDOMTree = new KAction( i18n( "Print DOM Tree to STDOUT" ), this );
336 actionCollection()->addAction( "debugDOMTree", d->m_paDebugDOMTree );
337 connect( d->m_paDebugDOMTree, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugDOMTree() ) );
339 d->m_paStopAnimations = new KAction( i18n( "Stop Animated Images" ), this );
340 actionCollection()->addAction( "stopAnimations", d->m_paStopAnimations );
341 connect( d->m_paStopAnimations, SIGNAL( triggered( bool ) ), this, SLOT( slotStopAnimations() ) );
343 d->m_paSetEncoding = new KCodecAction( KIcon("character-set"), i18n( "Set &Encoding" ), this, true );
344 actionCollection()->addAction( "setEncoding", d->m_paSetEncoding );
345 // d->m_paSetEncoding->setDelayed( false );
347 connect( d->m_paSetEncoding, SIGNAL(triggered(const QString&)), this, SLOT( slotSetEncoding(const QString &)));
348 connect( d->m_paSetEncoding, SIGNAL(triggered(KEncodingDetector::AutoDetectScript)), this, SLOT( slotAutomaticDetectionLanguage(KEncodingDetector::AutoDetectScript)));
350 if ( KGlobal::config()->hasGroup( "HTML Settings" ) ) {
351 KConfigGroup config( KGlobal::config(), "HTML Settings" );
353 d->m_autoDetectLanguage = static_cast<KEncodingDetector::AutoDetectScript>(config.readEntry( "AutomaticDetectionLanguage", /*static_cast<int>(language) */0));
354 if (d->m_autoDetectLanguage==KEncodingDetector::None) {
355 const QByteArray name = KGlobal::locale()->encoding().toLower();
356 // kWarning() << "00000000 ";
357 if (name.endsWith("1251")||name.startsWith("koi")||name=="iso-8859-5")
358 d->m_autoDetectLanguage=KEncodingDetector::Cyrillic;
359 else if (name.endsWith("1256")||name=="iso-8859-6")
360 d->m_autoDetectLanguage=KEncodingDetector::Arabic;
361 else if (name.endsWith("1257")||name=="iso-8859-13"||name=="iso-8859-4")
362 d->m_autoDetectLanguage=KEncodingDetector::Baltic;
363 else if (name.endsWith("1250")|| name=="ibm852" || name=="iso-8859-2" || name=="iso-8859-3" )
364 d->m_autoDetectLanguage=KEncodingDetector::CentralEuropean;
365 else if (name.endsWith("1253")|| name=="iso-8859-7" )
366 d->m_autoDetectLanguage=KEncodingDetector::Greek;
367 else if (name.endsWith("1255")|| name=="iso-8859-8" || name=="iso-8859-8-i" )
368 d->m_autoDetectLanguage=KEncodingDetector::Hebrew;
369 else if (name=="jis7" || name=="eucjp" || name=="sjis" )
370 d->m_autoDetectLanguage=KEncodingDetector::Japanese;
371 else if (name.endsWith("1254")|| name=="iso-8859-9" )
372 d->m_autoDetectLanguage=KEncodingDetector::Turkish;
373 else if (name.endsWith("1252")|| name=="iso-8859-1" || name=="iso-8859-15" )
374 d->m_autoDetectLanguage=KEncodingDetector::WesternEuropean;
375 else
376 d->m_autoDetectLanguage=KEncodingDetector::SemiautomaticDetection;
377 // kWarning() << "0000000end " << d->m_autoDetectLanguage << " " << KGlobal::locale()->encodingMib();
379 d->m_paSetEncoding->setCurrentAutoDetectScript(d->m_autoDetectLanguage);
382 d->m_paUseStylesheet = new KSelectAction( i18n( "Use S&tylesheet"), this );
383 actionCollection()->addAction( "useStylesheet", d->m_paUseStylesheet );
384 connect( d->m_paUseStylesheet, SIGNAL( triggered( int ) ), this, SLOT( slotUseStylesheet() ) );
386 if ( prof == BrowserViewGUI ) {
387 d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, "format-font-size-more", i18n( "Enlarge Font" ), this );
388 actionCollection()->addAction( "incFontSizes", d->m_paIncZoomFactor );
389 connect(d->m_paIncZoomFactor, SIGNAL(triggered(bool)), SLOT( slotIncFontSizeFast() ));
390 d->m_paIncZoomFactor->setWhatsThis( i18n( "Enlarge Font<br /><br />"
391 "Make the font in this window bigger. "
392 "Click and hold down the mouse button for a menu with all available font sizes." ) );
394 d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, "format-font-size-less", i18n( "Shrink Font" ), this );
395 actionCollection()->addAction( "decFontSizes", d->m_paDecZoomFactor );
396 connect(d->m_paDecZoomFactor, SIGNAL(triggered(bool)), SLOT( slotDecFontSizeFast() ));
397 d->m_paDecZoomFactor->setWhatsThis( i18n( "Shrink Font<br /><br />"
398 "Make the font in this window smaller. "
399 "Click and hold down the mouse button for a menu with all available font sizes." ) );
400 if (!parentPart()) {
401 // For framesets, this action also affects frames, so only
402 // the frameset needs to define a shortcut for the action.
404 // TODO: Why also CTRL+=? Because of http://trolltech.com/developer/knowledgebase/524/?
405 // Nobody else does it...
406 d->m_paIncZoomFactor->setShortcut( KShortcut("CTRL++; CTRL+=") );
407 d->m_paDecZoomFactor->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_Minus) );
411 d->m_paFind = actionCollection()->addAction( KStandardAction::Find, "find", this, SLOT( slotFind() ) );
412 d->m_paFind->setWhatsThis( i18n( "Find text<br /><br />"
413 "Shows a dialog that allows you to find text on the displayed page." ) );
415 d->m_paFindNext = actionCollection()->addAction( KStandardAction::FindNext, "findNext", this, SLOT( slotFindNext() ) );
416 d->m_paFindNext->setWhatsThis( i18n( "Find next<br /><br />"
417 "Find the next occurrence of the text that you "
418 "have found using the <b>Find Text</b> function" ) );
420 d->m_paFindPrev = actionCollection()->addAction( KStandardAction::FindPrev, "findPrevious",
421 this, SLOT( slotFindPrev() ) );
422 d->m_paFindPrev->setWhatsThis( i18n( "Find previous<br /><br />"
423 "Find the previous occurrence of the text that you "
424 "have found using the <b>Find Text</b> function" ) );
426 d->m_paFindAheadText = new KAction( i18n("Find Text as You Type"), this );
427 actionCollection()->addAction( "findAheadText", d->m_paFindAheadText );
428 d->m_paFindAheadText->setShortcuts( KShortcut( '/' ) );
429 connect( d->m_paFindAheadText, SIGNAL( triggered( bool ) ), this, SLOT( slotFindAheadText()) );
431 d->m_paFindAheadLinks = new KAction( i18n("Find Links as You Type"), this );
432 actionCollection()->addAction( "findAheadLink", d->m_paFindAheadLinks );
433 d->m_paFindAheadLinks->setShortcuts( KShortcut( '\'' ) );
434 connect( d->m_paFindAheadLinks, SIGNAL( triggered( bool ) ), this, SLOT( slotFindAheadLink() ) );
436 d->m_paFindAheadText->setEnabled( false );
437 d->m_paFindAheadLinks->setEnabled( false );
439 if ( parentPart() )
441 d->m_paFind->setShortcuts( KShortcut() ); // avoid clashes
442 d->m_paFindNext->setShortcuts( KShortcut() ); // avoid clashes
443 d->m_paFindPrev->setShortcuts( KShortcut() ); // avoid clashes
444 d->m_paFindAheadText->setShortcuts( KShortcut());
445 d->m_paFindAheadLinks->setShortcuts( KShortcut());
448 d->m_paPrintFrame = new KAction( i18n( "Print Frame..." ), this );
449 actionCollection()->addAction( "printFrame", d->m_paPrintFrame );
450 d->m_paPrintFrame->setIcon( KIcon( "document-print-frame" ) );
451 connect( d->m_paPrintFrame, SIGNAL( triggered( bool ) ), this, SLOT( slotPrintFrame() ) );
452 d->m_paPrintFrame->setWhatsThis( i18n( "Print Frame<br /><br />"
453 "Some pages have several frames. To print only a single frame, click "
454 "on it and then use this function." ) );
456 // Warning: The name selectAll is used hardcoded by some 3rd parties to remove the
457 // shortcut for selectAll so they do not get ambigous shortcuts. Renaming it
458 // will either crash or render useless that workaround. It would be better
459 // to use the name KStandardAction::name(KStandardAction::SelectAll) but we
460 // can't for the same reason.
461 d->m_paSelectAll = actionCollection()->addAction( KStandardAction::SelectAll, "selectAll",
462 this, SLOT( slotSelectAll() ) );
463 d->m_paSelectAll->setShortcutContext( Qt::WidgetWithChildrenShortcut );
464 if ( parentPart() )
465 d->m_paSelectAll->setShortcuts( KShortcut() ); // avoid clashes
467 d->m_paToggleCaretMode = new KToggleAction(i18n("Toggle Caret Mode"), this );
468 actionCollection()->addAction( "caretMode", d->m_paToggleCaretMode );
469 d->m_paToggleCaretMode->setShortcut( QKeySequence(Qt::Key_F7) );
470 connect( d->m_paToggleCaretMode, SIGNAL( triggered( bool ) ), this, SLOT(slotToggleCaretMode()) );
471 d->m_paToggleCaretMode->setChecked(isCaretMode());
472 if (parentPart())
473 d->m_paToggleCaretMode->setShortcut(KShortcut()); // avoid clashes
475 // set the default java(script) flags according to the current host.
476 d->m_bOpenMiddleClick = d->m_settings->isOpenMiddleClickEnabled();
477 d->m_bBackRightClick = d->m_settings->isBackRightClickEnabled();
478 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
479 setDebugScript( d->m_settings->isJavaScriptDebugEnabled() );
480 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
481 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
483 // Set the meta-refresh flag...
484 d->m_metaRefreshEnabled = d->m_settings->isAutoDelayedActionsEnabled ();
486 KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling();
487 if (ssm == KHTMLSettings::KSmoothScrollingDisabled)
488 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled);
489 else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient)
490 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient);
491 else
492 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled);
494 if (d->m_bDNSPrefetchIsDefault && !onlyLocalReferences()) {
495 KHTMLSettings::KDNSPrefetch dpm = d->m_settings->dnsPrefetch();
496 if (dpm == KHTMLSettings::KDNSPrefetchDisabled)
497 d->m_bDNSPrefetch = DNSPrefetchDisabled;
498 else if (dpm == KHTMLSettings::KDNSPrefetchOnlyWWWAndSLD)
499 d->m_bDNSPrefetch = DNSPrefetchOnlyWWWAndSLD;
500 else
501 d->m_bDNSPrefetch = DNSPrefetchEnabled;
504 if (!KHTMLPartPrivate::s_dnsInitialised && d->m_bDNSPrefetch != DNSPrefetchDisabled) {
505 KIO::HostInfo::setCacheSize( sDNSCacheSize );
506 KIO::HostInfo::setTTL( sDNSTTLSeconds );
507 KHTMLPartPrivate::s_dnsInitialised = true;
510 actionCollection()->associateWidget(view);
512 connect( view, SIGNAL( zoomView( int ) ), SLOT( slotZoomView( int ) ) );
514 connect( this, SIGNAL( completed() ),
515 this, SLOT( updateActions() ) );
516 connect( this, SIGNAL( completed( bool ) ),
517 this, SLOT( updateActions() ) );
518 connect( this, SIGNAL( started( KIO::Job * ) ),
519 this, SLOT( updateActions() ) );
521 connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
522 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
523 connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
524 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
525 connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
526 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
528 connect ( &d->m_progressUpdateTimer, SIGNAL( timeout() ), this, SLOT( slotProgressUpdate() ) );
530 findTextBegin(); //reset find variables
532 connect( &d->m_redirectionTimer, SIGNAL( timeout() ),
533 this, SLOT( slotRedirect() ) );
535 if (QDBusConnection::sessionBus().isConnected()) {
536 new KHTMLPartIface(this); // our "adaptor"
537 for (int i = 1; ; ++i)
538 if (QDBusConnection::sessionBus().registerObject(QString("/KHTML/%1/widget").arg(i), this))
539 break;
540 else if (i == 0xffff)
541 kFatal() << "Something is very wrong in KHTMLPart!";
544 if (prof == BrowserViewGUI && !parentPart())
545 loadPlugins();
547 // "khtml" catalog does not exist, our translations are in kdelibs.
548 // removing this catalog from KGlobal::locale() prevents problems
549 // with changing the language in applications at runtime -Thomas Reitelbach
550 // DF: a better fix would be to set the right catalog name in the KComponentData!
551 KGlobal::locale()->removeCatalog("khtml");
554 KHTMLPart::~KHTMLPart()
556 kDebug(6050) << this;
557 KConfigGroup config( KGlobal::config(), "HTML Settings" );
558 config.writeEntry( "AutomaticDetectionLanguage", int(d->m_autoDetectLanguage) );
560 slotWalletClosed();
561 if (!parentPart()) { // only delete it if the top khtml_part closes
562 removeJSErrorExtension();
563 delete d->m_statusBarPopupLabel;
566 if ( d->m_manager )
568 d->m_manager->setActivePart( 0 );
569 // We specify "this" as parent qobject for d->manager, so no need to delete it.
572 stopAutoScroll();
573 d->m_redirectionTimer.stop();
575 if (!d->m_bComplete)
576 closeUrl();
578 disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
579 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
580 disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
581 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
582 disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
583 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
585 clear();
587 if ( d->m_view )
589 d->m_view->hide();
590 d->m_view->viewport()->hide();
591 d->m_view->m_part = 0;
594 // Have to delete this here since we forward declare it in khtmlpart_p and
595 // at least some compilers won't call the destructor in this case.
596 delete d->m_jsedlg;
597 d->m_jsedlg = 0;
599 if (!parentPart()) // only delete d->m_frame if the top khtml_part closes
600 delete d->m_frame;
601 delete d; d = 0;
602 KHTMLGlobal::deregisterPart( this );
605 bool KHTMLPart::restoreURL( const KUrl &url )
607 kDebug( 6050 ) << url;
609 d->m_redirectionTimer.stop();
612 * That's not a good idea as it will call closeUrl() on all
613 * child frames, preventing them from further loading. This
614 * method gets called from restoreState() in case of a full frameset
615 * restoral, and restoreState() calls closeUrl() before restoring
616 * anyway.
617 kDebug( 6050 ) << "closing old URL";
618 closeUrl();
621 d->m_bComplete = false;
622 d->m_bLoadEventEmitted = false;
623 d->m_workingURL = url;
625 // set the java(script) flags according to the current host.
626 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
627 setDebugScript( KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
628 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host());
629 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host());
631 setUrl(url);
633 d->m_restoreScrollPosition = true;
634 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
635 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
637 KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &)));
639 emit started( 0L );
641 return true;
644 bool KHTMLPartPrivate::isLocalAnchorJump( const KUrl& url )
646 return url.hasRef() && urlcmp( url.url(), q->url().url(),
647 KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment );
650 void KHTMLPartPrivate::executeAnchorJump( const KUrl& url, bool lockHistory )
652 // Note: we want to emit openUrlNotify first thing, to make the history capture the old state.
653 if (!lockHistory)
654 emit m_extension->openUrlNotify();
656 if ( !q->gotoAnchor( url.encodedHtmlRef()) )
657 q->gotoAnchor( url.htmlRef() );
659 q->setUrl(url);
660 emit m_extension->setLocationBarUrl( url.prettyUrl() );
663 bool KHTMLPart::openUrl( const KUrl &url )
665 kDebug( 6050 ) << this << "opening" << url;
667 d->m_redirectionTimer.stop();
669 // check to see if this is an "error://" URL. This is caused when an error
670 // occurs before this part was loaded (e.g. KonqRun), and is passed to
671 // khtmlpart so that it can display the error.
672 if ( url.protocol() == "error" && url.hasSubUrl() ) {
673 closeUrl();
675 if( d->m_bJScriptEnabled ) {
676 d->m_statusBarText[BarOverrideText].clear();
677 d->m_statusBarText[BarDefaultText].clear();
681 * The format of the error url is that two variables are passed in the query:
682 * error = int kio error code, errText = QString error text from kio
683 * and the URL where the error happened is passed as a sub URL.
685 KUrl::List urls = KUrl::split( url );
686 //kDebug(6050) << "Handling error URL. URL count:" << urls.count();
688 if ( urls.count() > 1 ) {
689 KUrl mainURL = urls.first();
690 int error = mainURL.queryItem( "error" ).toInt();
691 // error=0 isn't a valid error code, so 0 means it's missing from the URL
692 if ( error == 0 ) error = KIO::ERR_UNKNOWN;
693 QString errorText = mainURL.queryItem( "errText" );
694 urls.pop_front();
695 d->m_workingURL = KUrl::join( urls );
696 //kDebug(6050) << "Emitting fixed URL " << d->m_workingURL.prettyUrl();
697 emit d->m_extension->setLocationBarUrl( d->m_workingURL.prettyUrl() );
698 htmlError( error, errorText, d->m_workingURL );
699 return true;
703 if (!parentPart()) { // only do it for toplevel part
704 QString host = url.isLocalFile() ? "localhost" : url.host();
705 QString userAgent = KProtocolManager::userAgentForHost(host);
706 if (userAgent != KProtocolManager::userAgentForHost(QString())) {
707 if (!d->m_statusBarUALabel) {
708 d->m_statusBarUALabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
709 d->m_statusBarUALabel->setFixedHeight(KHTMLGlobal::iconLoader()->currentSize(KIconLoader::Small));
710 d->m_statusBarUALabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
711 d->m_statusBarUALabel->setUseCursor(false);
712 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarUALabel, 0, false);
713 d->m_statusBarUALabel->setPixmap(SmallIcon("preferences-web-browser-identification"));
715 d->m_statusBarUALabel->setToolTip(i18n("The fake user-agent '%1' is in use.", userAgent));
716 } else if (d->m_statusBarUALabel) {
717 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarUALabel);
718 delete d->m_statusBarUALabel;
719 d->m_statusBarUALabel = 0L;
723 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
724 KParts::OpenUrlArguments args( arguments() );
726 // in case
727 // a) we have no frameset (don't test m_frames.count(), iframes get in there)
728 // b) the url is identical with the currently displayed one (except for the htmlref!)
729 // c) the url request is not a POST operation and
730 // d) the caller did not request to reload the page
731 // e) there was no HTTP redirection meanwhile (testcase: webmin's software/tree.cgi)
732 // => we don't reload the whole document and
733 // we just jump to the requested html anchor
734 bool isFrameSet = false;
735 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
736 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
737 isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET);
740 if (isFrameSet && d->isLocalAnchorJump(url) && browserArgs.softReload)
742 QList<khtml::ChildFrame*>::Iterator it = d->m_frames.begin();
743 const QList<khtml::ChildFrame*>::Iterator end = d->m_frames.end();
744 for (; it != end; ++it) {
745 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part );
746 if (part)
748 // We are reloading frames to make them jump into offsets.
749 KParts::OpenUrlArguments partargs( part->arguments() );
750 partargs.setReload( true );
751 part->setArguments( partargs );
753 part->openUrl( part->url() );
755 }/*next it*/
756 return true;
759 if ( url.hasRef() && !isFrameSet )
761 bool noReloadForced = !args.reload() && !browserArgs.redirectedRequest() && !browserArgs.doPost();
762 if ( noReloadForced && d->isLocalAnchorJump(url) )
764 kDebug( 6050 ) << "jumping to anchor. m_url = " << url;
765 setUrl(url);
766 emit started( 0 );
768 if ( !gotoAnchor( url.encodedHtmlRef()) )
769 gotoAnchor( url.htmlRef() );
771 d->m_bComplete = true;
772 if (d->m_doc)
773 d->m_doc->setParsing(false);
775 kDebug( 6050 ) << "completed...";
776 emit completed();
777 return true;
781 // Save offset of viewport when page is reloaded to be compliant
782 // to every other capable browser out there.
783 if (args.reload()) {
784 args.setXOffset( d->m_view->contentsX() );
785 args.setYOffset( d->m_view->contentsY() );
786 setArguments(args);
789 if (!d->m_restored)
790 closeUrl();
792 d->m_restoreScrollPosition = d->m_restored;
793 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
794 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
796 // 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
797 // data arrives) (Simon)
798 d->m_workingURL = url;
799 if(url.protocol().startsWith( "http" ) && !url.host().isEmpty() &&
800 url.path().isEmpty()) {
801 d->m_workingURL.setPath("/");
802 emit d->m_extension->setLocationBarUrl( d->m_workingURL.prettyUrl() );
804 setUrl(d->m_workingURL);
806 QMap<QString,QString>& metaData = args.metaData();
807 metaData.insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" );
808 metaData.insert("ssl_parent_ip", d->m_ssl_parent_ip);
809 metaData.insert("ssl_parent_cert", d->m_ssl_parent_cert);
810 metaData.insert("PropagateHttpHeader", "true");
811 metaData.insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" );
812 metaData.insert("ssl_activate_warnings", "TRUE" );
813 metaData.insert("cross-domain", toplevelURL().url());
815 if (d->m_restored)
817 metaData.insert("referrer", d->m_pageReferrer);
818 d->m_cachePolicy = KIO::CC_Cache;
820 else if (args.reload())
821 d->m_cachePolicy = KIO::CC_Reload;
822 else
823 d->m_cachePolicy = KProtocolManager::cacheControl();
825 if ( browserArgs.doPost() && (url.protocol().startsWith("http")) )
827 d->m_job = KIO::http_post( url, browserArgs.postData, KIO::HideProgressInfo );
828 d->m_job->addMetaData("content-type", browserArgs.contentType() );
830 else
832 d->m_job = KIO::get( url, KIO::NoReload, KIO::HideProgressInfo );
833 d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
836 if (widget())
837 d->m_job->ui()->setWindow(widget()->topLevelWidget());
838 d->m_job->addMetaData(metaData);
840 connect( d->m_job, SIGNAL( result( KJob* ) ),
841 SLOT( slotFinished( KJob* ) ) );
842 connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
843 SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
844 connect ( d->m_job, SIGNAL( infoMessage( KJob*, const QString&, const QString& ) ),
845 SLOT( slotInfoMessage(KJob*, const QString& ) ) );
846 connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KUrl& ) ),
847 SLOT( slotRedirection(KIO::Job*, const KUrl&) ) );
849 d->m_bComplete = false;
850 d->m_bLoadEventEmitted = false;
852 // delete old status bar msg's from kjs (if it _was_ activated on last URL)
853 if( d->m_bJScriptEnabled ) {
854 d->m_statusBarText[BarOverrideText].clear();
855 d->m_statusBarText[BarDefaultText].clear();
858 // set the javascript flags according to the current url
859 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
860 setDebugScript( KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
861 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host());
862 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host());
865 connect( d->m_job, SIGNAL( speed( KJob*, unsigned long ) ),
866 this, SLOT( slotJobSpeed( KJob*, unsigned long ) ) );
868 connect( d->m_job, SIGNAL( percent( KJob*, unsigned long ) ),
869 this, SLOT( slotJobPercent( KJob*, unsigned long ) ) );
871 connect( d->m_job, SIGNAL( result( KJob* ) ),
872 this, SLOT( slotJobDone( KJob* ) ) );
874 d->m_jobspeed = 0;
876 // If this was an explicit reload and the user style sheet should be used,
877 // do a stat to see whether the stylesheet was changed in the meanwhile.
878 if ( args.reload() && !settings()->userStyleSheet().isEmpty() ) {
879 KUrl url( settings()->userStyleSheet() );
880 KIO::StatJob *job = KIO::stat( url, KIO::HideProgressInfo );
881 connect( job, SIGNAL( result( KJob * ) ),
882 this, SLOT( slotUserSheetStatDone( KJob * ) ) );
884 startingJob( d->m_job );
885 emit started( 0L );
887 return true;
890 bool KHTMLPart::closeUrl()
892 if ( d->m_job )
894 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
895 d->m_job->kill();
896 d->m_job = 0;
899 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
900 HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
902 if ( hdoc->body() && d->m_bLoadEventEmitted ) {
903 hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false );
904 if ( d->m_doc )
905 d->m_doc->updateRendering();
906 d->m_bLoadEventEmitted = false;
910 d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
911 d->m_bLoadEventEmitted = true; // don't want that one either
912 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
914 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
916 KHTMLPageCache::self()->cancelFetch(this);
917 if ( d->m_doc && d->m_doc->parsing() )
919 kDebug( 6050 ) << " was still parsing... calling end ";
920 slotFinishedParsing();
921 d->m_doc->setParsing(false);
924 if ( !d->m_workingURL.isEmpty() )
926 // Aborted before starting to render
927 kDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << url().prettyUrl();
928 emit d->m_extension->setLocationBarUrl( url().prettyUrl() );
931 d->m_workingURL = KUrl();
933 if ( d->m_doc && d->m_doc->docLoader() )
934 khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() );
936 // tell all subframes to stop as well
938 ConstFrameIt it = d->m_frames.constBegin();
939 const ConstFrameIt end = d->m_frames.constEnd();
940 for (; it != end; ++it )
942 if ( (*it)->m_run )
943 (*it)->m_run->abort();
944 if ( !( *it )->m_part.isNull() )
945 ( *it )->m_part->closeUrl();
948 // tell all objects to stop as well
950 ConstFrameIt it = d->m_objects.constBegin();
951 const ConstFrameIt end = d->m_objects.constEnd();
952 for (; it != end; ++it)
954 if ( !( *it )->m_part.isNull() )
955 ( *it )->m_part->closeUrl();
958 // Stop any started redirections as well!! (DA)
959 if ( d && d->m_redirectionTimer.isActive() )
960 d->m_redirectionTimer.stop();
962 // null node activated.
963 emit nodeActivated(Node());
965 // make sure before clear() runs, we pop out of a dialog's message loop
966 if ( d->m_view )
967 d->m_view->closeChildDialogs();
969 return true;
972 DOM::HTMLDocument KHTMLPart::htmlDocument() const
974 if (d->m_doc && d->m_doc->isHTMLDocument())
975 return static_cast<HTMLDocumentImpl*>(d->m_doc);
976 else
977 return static_cast<HTMLDocumentImpl*>(0);
980 DOM::Document KHTMLPart::document() const
982 return d->m_doc;
985 QString KHTMLPart::documentSource() const
987 QString sourceStr;
988 if ( !( url().isLocalFile() ) && KHTMLPageCache::self()->isComplete( d->m_cacheId ) )
990 QByteArray sourceArray;
991 QDataStream dataStream( &sourceArray, QIODevice::WriteOnly );
992 KHTMLPageCache::self()->saveData( d->m_cacheId, &dataStream );
993 QTextStream stream( sourceArray, QIODevice::ReadOnly );
994 stream.setCodec( QTextCodec::codecForName( encoding().toLatin1().constData() ) );
995 sourceStr = stream.readAll();
996 } else
998 QString tmpFile;
999 if( KIO::NetAccess::download( url(), tmpFile, NULL ) )
1001 QFile f( tmpFile );
1002 if ( f.open( QIODevice::ReadOnly ) )
1004 QTextStream stream( &f );
1005 stream.setCodec( QTextCodec::codecForName( encoding().toLatin1().constData() ) );
1006 sourceStr = stream.readAll();
1007 f.close();
1009 KIO::NetAccess::removeTempFile( tmpFile );
1013 return sourceStr;
1017 KParts::BrowserExtension *KHTMLPart::browserExtension() const
1019 return d->m_extension;
1022 KParts::BrowserHostExtension *KHTMLPart::browserHostExtension() const
1024 return d->m_hostExtension;
1027 KHTMLView *KHTMLPart::view() const
1029 return d->m_view;
1032 KHTMLViewBar *KHTMLPart::pTopViewBar() const
1034 if (const_cast<KHTMLPart*>(this)->parentPart())
1035 return const_cast<KHTMLPart*>(this)->parentPart()->pTopViewBar();
1036 return d->m_topViewBar;
1039 KHTMLViewBar *KHTMLPart::pBottomViewBar() const
1041 if (const_cast<KHTMLPart*>(this)->parentPart())
1042 return const_cast<KHTMLPart*>(this)->parentPart()->pBottomViewBar();
1043 return d->m_bottomViewBar;
1046 void KHTMLPart::setStatusMessagesEnabled( bool enable )
1048 d->m_statusMessagesEnabled = enable;
1051 KJS::Interpreter *KHTMLPart::jScriptInterpreter()
1053 KJSProxy *proxy = jScript();
1054 if (!proxy || proxy->paused())
1055 return 0;
1057 return proxy->interpreter();
1060 bool KHTMLPart::statusMessagesEnabled() const
1062 return d->m_statusMessagesEnabled;
1065 void KHTMLPart::setJScriptEnabled( bool enable )
1067 if ( !enable && jScriptEnabled() && d->m_frame && d->m_frame->m_jscript ) {
1068 d->m_frame->m_jscript->clear();
1070 d->m_bJScriptForce = enable;
1071 d->m_bJScriptOverride = true;
1074 bool KHTMLPart::jScriptEnabled() const
1076 if(onlyLocalReferences()) return false;
1078 if ( d->m_bJScriptOverride )
1079 return d->m_bJScriptForce;
1080 return d->m_bJScriptEnabled;
1083 void KHTMLPart::setDNSPrefetch( DNSPrefetch pmode )
1085 d->m_bDNSPrefetch = pmode;
1086 d->m_bDNSPrefetchIsDefault = false;
1089 KHTMLPart::DNSPrefetch KHTMLPart::dnsPrefetch() const
1091 if (onlyLocalReferences())
1092 return DNSPrefetchDisabled;
1093 return d->m_bDNSPrefetch;
1096 void KHTMLPart::setMetaRefreshEnabled( bool enable )
1098 d->m_metaRefreshEnabled = enable;
1101 bool KHTMLPart::metaRefreshEnabled() const
1103 return d->m_metaRefreshEnabled;
1106 // Define this to disable dlopening kjs_html, when directly linking to it.
1107 // You need to edit khtml/Makefile.am to add ./ecma/libkjs_html.la to LIBADD
1108 // and to edit khtml/ecma/Makefile.am to s/kjs_html/libkjs_html/, remove libkhtml from LIBADD,
1109 // remove LDFLAGS line, and replace kde_module with either lib (shared) or noinst (static)
1110 // Also, change the order of "ecma" and "." in khtml's SUBDIRS line.
1111 // OK - that's the default now, use the opposite of the above instructions to go back
1112 // to "dlopening it" - but it breaks exception catching in kjs_binding.cpp
1113 #define DIRECT_LINKAGE_TO_ECMA
1115 #ifdef DIRECT_LINKAGE_TO_ECMA
1116 extern "C" { KJSProxy *kjs_html_init(khtml::ChildFrame * childframe); }
1117 #endif
1119 static bool createJScript(khtml::ChildFrame *frame)
1121 #ifndef DIRECT_LINKAGE_TO_ECMA
1122 KLibrary *lib = KLibLoader::self()->library(QLatin1String("kjs_html"));
1123 if ( !lib ) {
1124 setJScriptEnabled( false );
1125 return false;
1127 // look for plain C init function
1128 void *sym = lib->symbol("kjs_html_init");
1129 if ( !sym ) {
1130 lib->unload();
1131 setJScriptEnabled( false );
1132 return false;
1134 typedef KJSProxy* (*initFunction)(khtml::ChildFrame *);
1135 initFunction initSym = (initFunction) sym;
1136 frame->m_jscript = (*initSym)(d->m_frame);
1137 frame->m_kjs_lib = lib;
1138 #else
1139 frame->m_jscript = kjs_html_init(frame);
1140 #endif
1141 return true;
1144 KJSProxy *KHTMLPart::jScript()
1146 if (!jScriptEnabled()) return 0;
1148 if ( !d->m_frame ) {
1149 KHTMLPart * p = parentPart();
1150 if (!p) {
1151 d->m_frame = new khtml::ChildFrame;
1152 d->m_frame->m_part = this;
1153 } else {
1154 ConstFrameIt it = p->d->m_frames.constBegin();
1155 const ConstFrameIt end = p->d->m_frames.constEnd();
1156 for (; it != end; ++it)
1157 if ((*it)->m_part.operator->() == this) {
1158 d->m_frame = *it;
1159 break;
1162 if ( !d->m_frame )
1163 return 0;
1165 if ( !d->m_frame->m_jscript )
1166 if (!createJScript(d->m_frame))
1167 return 0;
1168 d->m_frame->m_jscript->setDebugEnabled(d->m_bJScriptDebugEnabled);
1170 return d->m_frame->m_jscript;
1173 QVariant KHTMLPart::crossFrameExecuteScript(const QString& target, const QString& script)
1175 KHTMLPart* destpart = this;
1177 QString trg = target.toLower();
1179 if (target == "_top") {
1180 while (destpart->parentPart())
1181 destpart = destpart->parentPart();
1183 else if (target == "_parent") {
1184 if (parentPart())
1185 destpart = parentPart();
1187 else if (target == "_self" || target == "_blank") {
1188 // we always allow these
1190 else {
1191 destpart = findFrame(target);
1192 if (!destpart)
1193 destpart = this;
1196 // easy way out?
1197 if (destpart == this)
1198 return executeScript(DOM::Node(), script);
1200 // now compare the domains
1201 if (destpart->checkFrameAccess(this))
1202 return destpart->executeScript(DOM::Node(), script);
1204 // eww, something went wrong. better execute it in our frame
1205 return executeScript(DOM::Node(), script);
1208 //Enable this to see all JS scripts being executed
1209 //#define KJS_VERBOSE
1211 KJSErrorDlg *KHTMLPart::jsErrorExtension() {
1212 if (!d->m_settings->jsErrorsEnabled()) {
1213 return 0L;
1216 if (parentPart()) {
1217 return parentPart()->jsErrorExtension();
1220 if (!d->m_statusBarJSErrorLabel) {
1221 d->m_statusBarJSErrorLabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
1222 d->m_statusBarJSErrorLabel->setFixedHeight(KIconLoader::global()->currentSize(KIconLoader::Small));
1223 d->m_statusBarJSErrorLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
1224 d->m_statusBarJSErrorLabel->setUseCursor(false);
1225 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarJSErrorLabel, 0, false);
1226 d->m_statusBarJSErrorLabel->setToolTip(i18n("This web page contains coding errors."));
1227 d->m_statusBarJSErrorLabel->setPixmap(SmallIcon("script-error"));
1228 connect(d->m_statusBarJSErrorLabel, SIGNAL(leftClickedUrl()), SLOT(launchJSErrorDialog()));
1229 connect(d->m_statusBarJSErrorLabel, SIGNAL(rightClickedUrl()), SLOT(jsErrorDialogContextMenu()));
1231 if (!d->m_jsedlg) {
1232 d->m_jsedlg = new KJSErrorDlg;
1233 d->m_jsedlg->setURL(url().prettyUrl());
1234 if (KGlobalSettings::showIconsOnPushButtons()) {
1235 d->m_jsedlg->_clear->setIcon(KIcon("edit-clear-locationbar-ltr"));
1236 d->m_jsedlg->_close->setIcon(KIcon("window-close"));
1239 return d->m_jsedlg;
1242 void KHTMLPart::removeJSErrorExtension() {
1243 if (parentPart()) {
1244 parentPart()->removeJSErrorExtension();
1245 return;
1247 if (d->m_statusBarJSErrorLabel != 0) {
1248 d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarJSErrorLabel );
1249 delete d->m_statusBarJSErrorLabel;
1250 d->m_statusBarJSErrorLabel = 0;
1252 delete d->m_jsedlg;
1253 d->m_jsedlg = 0;
1256 void KHTMLPart::disableJSErrorExtension() {
1257 removeJSErrorExtension();
1258 // These two lines are really kind of hacky, and it sucks to do this inside
1259 // KHTML but I don't know of anything that's reasonably easy as an alternative
1260 // right now. It makes me wonder if there should be a more clean way to
1261 // contact all running "KHTML" instance as opposed to Konqueror instances too.
1262 d->m_settings->setJSErrorsEnabled(false);
1263 emit configurationChanged();
1266 void KHTMLPart::jsErrorDialogContextMenu() {
1267 KMenu *m = new KMenu(0L);
1268 m->addAction(i18n("&Hide Errors"), this, SLOT(removeJSErrorExtension()));
1269 m->addAction(i18n("&Disable Error Reporting"), this, SLOT(disableJSErrorExtension()));
1270 m->popup(QCursor::pos());
1273 void KHTMLPart::launchJSErrorDialog() {
1274 KJSErrorDlg *dlg = jsErrorExtension();
1275 if (dlg) {
1276 dlg->show();
1277 dlg->raise();
1281 void KHTMLPart::launchJSConfigDialog() {
1282 QStringList args;
1283 args << "khtml_java_js";
1284 KToolInvocation::kdeinitExec( "kcmshell4", args );
1287 QVariant KHTMLPart::executeScript(const QString& filename, int baseLine, const DOM::Node& n, const QString& script)
1289 #ifdef KJS_VERBOSE
1290 // The script is now printed by KJS's Parser::parse
1291 kDebug(6070) << "executeScript: caller='" << objectName() << "' filename=" << filename << " baseLine=" << baseLine /*<< " script=" << script*/;
1292 #endif
1293 KJSProxy *proxy = jScript();
1295 if (!proxy || proxy->paused())
1296 return QVariant();
1298 //Make sure to initialize the interpreter before creating Completion
1299 (void)proxy->interpreter();
1301 KJS::Completion comp;
1303 QVariant ret = proxy->evaluate(filename, baseLine, script, n, &comp);
1306 * Error handling
1308 if (comp.complType() == KJS::Throw && comp.value()) {
1309 KJSErrorDlg *dlg = jsErrorExtension();
1310 if (dlg) {
1311 QString msg = KJSDebugger::DebugWindow::exceptionToString(
1312 proxy->interpreter()->globalExec(), comp.value());
1313 dlg->addError(i18n("<qt><b>Error</b>: %1: %2</qt>",
1314 Qt::escape(filename), Qt::escape(msg)));
1318 // Handle immediate redirects now (e.g. location='foo')
1319 if ( !d->m_redirectURL.isEmpty() && d->m_delayRedirect == -1 )
1321 kDebug(6070) << "executeScript done, handling immediate redirection NOW";
1322 // Must abort tokenizer, no further script must execute.
1323 khtml::Tokenizer* t = d->m_doc->tokenizer();
1324 if(t)
1325 t->abort();
1326 d->m_redirectionTimer.setSingleShot( true );
1327 d->m_redirectionTimer.start( 0 );
1330 return ret;
1333 QVariant KHTMLPart::executeScript( const QString &script )
1335 return executeScript( DOM::Node(), script );
1338 QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script )
1340 #ifdef KJS_VERBOSE
1341 kDebug(6070) << "caller=" << objectName() << "node=" << n.nodeName().string().toLatin1().constData() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " /* << script */;
1342 #endif
1343 KJSProxy *proxy = jScript();
1345 if (!proxy || proxy->paused())
1346 return QVariant();
1347 (void)proxy->interpreter();//Make sure stuff is initialized
1349 ++(d->m_runningScripts);
1350 KJS::Completion comp;
1351 const QVariant ret = proxy->evaluate( QString(), 1, script, n, &comp );
1352 --(d->m_runningScripts);
1355 * Error handling
1357 if (comp.complType() == KJS::Throw && !comp.value()) {
1358 KJSErrorDlg *dlg = jsErrorExtension();
1359 if (dlg) {
1360 QString msg = KJSDebugger::DebugWindow::exceptionToString(
1361 proxy->interpreter()->globalExec(), comp.value());
1362 dlg->addError(i18n("<qt><b>Error</b>: node %1: %2</qt>",
1363 n.nodeName().string(), Qt::escape(msg)));
1367 if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
1368 submitFormAgain();
1370 #ifdef KJS_VERBOSE
1371 kDebug(6070) << "done";
1372 #endif
1373 return ret;
1376 void KHTMLPart::setJavaEnabled( bool enable )
1378 d->m_bJavaForce = enable;
1379 d->m_bJavaOverride = true;
1382 bool KHTMLPart::javaEnabled() const
1384 if (onlyLocalReferences()) return false;
1386 #ifndef Q_WS_QWS
1387 if( d->m_bJavaOverride )
1388 return d->m_bJavaForce;
1389 return d->m_bJavaEnabled;
1390 #else
1391 return false;
1392 #endif
1395 void KHTMLPart::setPluginsEnabled( bool enable )
1397 d->m_bPluginsForce = enable;
1398 d->m_bPluginsOverride = true;
1401 bool KHTMLPart::pluginsEnabled() const
1403 if (onlyLocalReferences()) return false;
1405 if ( d->m_bPluginsOverride )
1406 return d->m_bPluginsForce;
1407 return d->m_bPluginsEnabled;
1410 static int s_DOMTreeIndentLevel = 0;
1412 void KHTMLPart::slotDebugDOMTree()
1414 if ( d->m_doc )
1415 qDebug("%s", d->m_doc->toString().string().toLatin1().constData());
1417 // Now print the contents of the frames that contain HTML
1419 const int indentLevel = s_DOMTreeIndentLevel++;
1421 ConstFrameIt it = d->m_frames.constBegin();
1422 const ConstFrameIt end = d->m_frames.constEnd();
1423 for (; it != end; ++it )
1424 if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
1425 KParts::ReadOnlyPart* const p = ( *it )->m_part;
1426 kDebug(6050) << QString().leftJustified(s_DOMTreeIndentLevel*4,' ') << "FRAME " << p->objectName() << " ";
1427 static_cast<KHTMLPart*>( p )->slotDebugDOMTree();
1429 s_DOMTreeIndentLevel = indentLevel;
1432 void KHTMLPart::slotDebugScript()
1434 if (jScript())
1435 jScript()->showDebugWindow();
1438 void KHTMLPart::slotDebugRenderTree()
1440 #ifndef NDEBUG
1441 if ( d->m_doc ) {
1442 d->m_doc->renderer()->printTree();
1443 // dump out the contents of the rendering & DOM trees
1444 // QString dumps;
1445 // QTextStream outputStream(dumps,QIODevice::WriteOnly);
1446 // d->m_doc->renderer()->layer()->dump( outputStream );
1447 // kDebug() << "dump output:" << "\n" + dumps;
1449 #endif
1452 void KHTMLPart::slotStopAnimations()
1454 stopAnimations();
1457 void KHTMLPart::setAutoloadImages( bool enable )
1459 if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
1460 return;
1462 if ( d->m_doc )
1463 d->m_doc->docLoader()->setAutoloadImages( enable );
1465 unplugActionList( "loadImages" );
1467 if ( enable ) {
1468 delete d->m_paLoadImages;
1469 d->m_paLoadImages = 0;
1471 else if ( !d->m_paLoadImages ) {
1472 d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), this );
1473 actionCollection()->addAction( "loadImages", d->m_paLoadImages );
1474 d->m_paLoadImages->setIcon( KIcon( "image-loading" ) );
1475 connect( d->m_paLoadImages, SIGNAL( triggered( bool ) ), this, SLOT( slotLoadImages() ) );
1478 if ( d->m_paLoadImages ) {
1479 QList<QAction*> lst;
1480 lst.append( d->m_paLoadImages );
1481 plugActionList( "loadImages", lst );
1485 bool KHTMLPart::autoloadImages() const
1487 if ( d->m_doc )
1488 return d->m_doc->docLoader()->autoloadImages();
1490 return true;
1493 void KHTMLPart::clear()
1495 if ( d->m_bCleared )
1496 return;
1498 d->m_bCleared = true;
1500 d->m_bClearing = true;
1503 ConstFrameIt it = d->m_frames.constBegin();
1504 const ConstFrameIt end = d->m_frames.constEnd();
1505 for(; it != end; ++it )
1507 // Stop HTMLRun jobs for frames
1508 if ( (*it)->m_run )
1509 (*it)->m_run->abort();
1514 ConstFrameIt it = d->m_objects.constBegin();
1515 const ConstFrameIt end = d->m_objects.constEnd();
1516 for(; it != end; ++it )
1518 // Stop HTMLRun jobs for objects
1519 if ( (*it)->m_run )
1520 (*it)->m_run->abort();
1525 findTextBegin(); // resets d->m_findNode and d->m_findPos
1526 d->m_mousePressNode = DOM::Node();
1529 if ( d->m_doc )
1531 if (d->m_doc->attached()) //the view may have detached it already
1532 d->m_doc->detach();
1535 // Moving past doc so that onUnload works.
1536 if ( d->m_frame && d->m_frame->m_jscript )
1537 d->m_frame->m_jscript->clear();
1539 // stopping marquees
1540 if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->layer())
1541 d->m_doc->renderer()->layer()->suspendMarquees();
1543 if ( d->m_view )
1544 d->m_view->clear();
1546 // do not dereference the document before the jscript and view are cleared, as some destructors
1547 // might still try to access the document.
1548 if ( d->m_doc ) {
1549 d->m_doc->deref();
1551 d->m_doc = 0;
1553 delete d->m_decoder;
1554 d->m_decoder = 0;
1556 // We don't want to change between parts if we are going to delete all of them anyway
1557 disconnect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ),
1558 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
1560 if (d->m_frames.count())
1562 const KHTMLFrameList frames = d->m_frames;
1563 d->m_frames.clear();
1564 ConstFrameIt it = frames.begin();
1565 const ConstFrameIt end = frames.end();
1566 for(; it != end; ++it )
1568 if ( (*it)->m_part )
1570 partManager()->removePart( (*it)->m_part );
1571 delete (KParts::ReadOnlyPart *)(*it)->m_part;
1573 delete *it;
1576 d->m_suppressedPopupOriginParts.clear();
1578 if (d->m_objects.count())
1580 KHTMLFrameList objects = d->m_objects;
1581 d->m_objects.clear();
1582 ConstFrameIt oi = objects.constBegin();
1583 const ConstFrameIt oiEnd = objects.constEnd();
1585 for (; oi != oiEnd; ++oi )
1587 if ( (*oi)->m_part )
1588 delete (KParts::ReadOnlyPart *)(*oi)->m_part;
1589 delete *oi;
1593 // Listen to part changes again
1594 connect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ),
1595 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
1597 d->clearRedirection();
1598 d->m_redirectLockHistory = true;
1599 d->m_bClearing = false;
1600 d->m_frameNameId = 1;
1601 d->m_bFirstData = true;
1603 d->m_bMousePressed = false;
1605 if (d->editor_context.m_caretBlinkTimer >= 0)
1606 killTimer(d->editor_context.m_caretBlinkTimer);
1607 d->editor_context.reset();
1608 #ifndef QT_NO_CLIPBOARD
1609 connect( qApp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
1610 #endif
1612 d->m_jobPercent = 0;
1614 if ( !d->m_haveEncoding )
1615 d->m_encoding.clear();
1617 d->m_DNSPrefetchQueue.clear();
1618 if (d->m_DNSPrefetchTimer > 0)
1619 killTimer(d->m_DNSPrefetchTimer);
1620 d->m_DNSPrefetchTimer = -1;
1621 d->m_lookedupHosts.clear();
1622 if (d->m_DNSTTLTimer > 0)
1623 killTimer(d->m_DNSTTLTimer);
1624 d->m_DNSTTLTimer = -1;
1625 d->m_numDNSPrefetchedNames = 0;
1627 #ifdef SPEED_DEBUG
1628 d->m_parsetime.restart();
1629 #endif
1632 bool KHTMLPart::openFile()
1634 return true;
1637 DOM::HTMLDocumentImpl *KHTMLPart::docImpl() const
1639 if ( d && d->m_doc && d->m_doc->isHTMLDocument() )
1640 return static_cast<HTMLDocumentImpl*>(d->m_doc);
1641 return 0;
1644 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
1646 if ( d )
1647 return d->m_doc;
1648 return 0;
1651 void KHTMLPart::slotInfoMessage(KJob* kio_job, const QString& msg)
1653 assert(d->m_job == kio_job);
1655 if (!parentPart())
1656 setStatusBarText(msg, BarDefaultText);
1659 void KHTMLPart::setPageSecurity( PageSecurity sec )
1661 emit d->m_extension->setPageSecurity( sec );
1664 void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
1666 assert ( d->m_job == kio_job );
1668 //kDebug( 6050 ) << "slotData: " << data.size();
1669 // The first data ?
1670 if ( !d->m_workingURL.isEmpty() )
1672 //kDebug( 6050 ) << "begin!";
1674 // We must suspend KIO while we're inside begin() because it can cause
1675 // crashes if a window (such as kjsdebugger) goes back into the event loop,
1676 // more data arrives, and begin() gets called again (re-entered).
1677 d->m_job->suspend();
1678 begin( d->m_workingURL, arguments().xOffset(), arguments().yOffset() );
1679 d->m_job->resume();
1681 if (d->m_cachePolicy == KIO::CC_Refresh)
1682 d->m_doc->docLoader()->setCachePolicy(KIO::CC_Verify);
1683 else
1684 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
1686 d->m_workingURL = KUrl();
1688 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
1690 // When the first data arrives, the metadata has just been made available
1691 d->m_httpHeaders = d->m_job->queryMetaData("HTTP-Headers");
1692 time_t cacheCreationDate = d->m_job->queryMetaData("cache-creation-date").toLong();
1693 d->m_doc->docLoader()->setCacheCreationDate(cacheCreationDate);
1695 d->m_pageServices = d->m_job->queryMetaData("PageServices");
1696 d->m_pageReferrer = d->m_job->queryMetaData("referrer");
1697 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
1700 KHTMLPart *p = parentPart();
1701 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
1702 while (p->parentPart()) p = p->parentPart();
1704 p->setPageSecurity( NotCrypted );
1708 setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
1710 // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
1711 d->m_ssl_parent_ip = d->m_job->queryMetaData("ssl_parent_ip");
1712 d->m_ssl_parent_cert = d->m_job->queryMetaData("ssl_parent_cert");
1713 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
1714 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
1715 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
1716 d->m_ssl_protocol_version = d->m_job->queryMetaData("ssl_protocol_version");
1717 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
1718 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
1719 d->m_ssl_cert_errors = d->m_job->queryMetaData("ssl_cert_errors");
1721 // Check for charset meta-data
1722 QString qData = d->m_job->queryMetaData("charset");
1723 if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
1724 d->m_encoding = qData;
1727 // Support for http-refresh
1728 qData = d->m_job->queryMetaData("http-refresh");
1729 if( !qData.isEmpty())
1730 d->m_doc->processHttpEquiv("refresh", qData);
1732 // DISABLED: Support Content-Location per section 14.14 of RFC 2616.
1733 // See BR# 51185,BR# 82747
1735 QString baseURL = d->m_job->queryMetaData ("content-location");
1736 if (!baseURL.isEmpty())
1737 d->m_doc->setBaseURL(KUrl( d->m_doc->completeURL(baseURL) ));
1740 // Support for Content-Language
1741 QString language = d->m_job->queryMetaData("content-language");
1742 if (!language.isEmpty())
1743 d->m_doc->setContentLanguage(language);
1745 if ( !url().isLocalFile() )
1747 // Support for http last-modified
1748 d->m_lastModified = d->m_job->queryMetaData("modified");
1750 else
1751 d->m_lastModified.clear(); // done on-demand by lastModified()
1754 KHTMLPageCache::self()->addData(d->m_cacheId, data);
1755 write( data.data(), data.size() );
1757 if (d->m_frame && d->m_frame->m_jscript)
1758 d->m_frame->m_jscript->dataReceived();
1762 void KHTMLPart::slotRestoreData(const QByteArray &data )
1764 // The first data ?
1765 if ( !d->m_workingURL.isEmpty() )
1767 long saveCacheId = d->m_cacheId;
1768 QString savePageReferrer = d->m_pageReferrer;
1769 QString saveEncoding = d->m_encoding;
1770 begin( d->m_workingURL, arguments().xOffset(), arguments().yOffset() );
1771 d->m_encoding = saveEncoding;
1772 d->m_pageReferrer = savePageReferrer;
1773 d->m_cacheId = saveCacheId;
1774 d->m_workingURL = KUrl();
1777 //kDebug( 6050 ) << data.size();
1778 write( data.data(), data.size() );
1780 if (data.size() == 0)
1782 //kDebug( 6050 ) << "<<end of data>>";
1783 // End of data.
1784 if (d->m_doc && d->m_doc->parsing())
1785 end(); //will emit completed()
1789 void KHTMLPart::showError( KJob* job )
1791 kDebug(6050) << "d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
1792 << " d->m_bCleared=" << d->m_bCleared;
1794 if (job->error() == KIO::ERR_NO_CONTENT)
1795 return;
1797 if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
1798 job->uiDelegate()->showErrorMessage();
1799 else
1801 htmlError( job->error(), job->errorText(), d->m_workingURL );
1805 // This is a protected method, placed here because of it's relevance to showError
1806 void KHTMLPart::htmlError( int errorCode, const QString& text, const KUrl& reqUrl )
1808 kDebug(6050) << "errorCode" << errorCode << "text" << text;
1809 // make sure we're not executing any embedded JS
1810 bool bJSFO = d->m_bJScriptForce;
1811 bool bJSOO = d->m_bJScriptOverride;
1812 d->m_bJScriptForce = false;
1813 d->m_bJScriptOverride = true;
1814 begin();
1816 QString errorName, techName, description;
1817 QStringList causes, solutions;
1819 QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
1820 QDataStream stream(raw);
1822 stream >> errorName >> techName >> description >> causes >> solutions;
1824 QString url, protocol, datetime;
1825 url = Qt::escape( reqUrl.prettyUrl() );
1826 protocol = reqUrl.protocol();
1827 datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
1828 KLocale::LongDate );
1830 QString filename( KStandardDirs::locate( "data", "khtml/error.html" ) );
1831 QFile file( filename );
1832 bool isOpened = file.open( QIODevice::ReadOnly );
1833 if ( !isOpened )
1834 kWarning(6050) << "Could not open error html template:" << filename;
1836 QString html = QString( QLatin1String( file.readAll() ) );
1838 html.replace( QLatin1String( "TITLE" ), i18n( "Error: %1 - %2", errorName, url ) );
1839 html.replace( QLatin1String( "DIRECTION" ), QApplication::isRightToLeft() ? "rtl" : "ltr" );
1840 html.replace( QLatin1String( "ICON_PATH" ), KIconLoader::global()->iconPath( "dialog-warning", -KIconLoader::SizeHuge ) );
1842 QString doc = QLatin1String( "<h1>" );
1843 doc += i18n( "The requested operation could not be completed" );
1844 doc += QLatin1String( "</h1><h2>" );
1845 doc += errorName;
1846 doc += QLatin1String( "</h2>" );
1847 if ( !techName.isNull() ) {
1848 doc += QLatin1String( "<h2>" );
1849 doc += i18n( "Technical Reason: " );
1850 doc += techName;
1851 doc += QLatin1String( "</h2>" );
1853 doc += QLatin1String( "<h3>" );
1854 doc += i18n( "Details of the Request:" );
1855 doc += QLatin1String( "</h3><ul><li>" );
1856 doc += i18n( "URL: %1" , url );
1857 doc += QLatin1String( "</li><li>" );
1858 if ( !protocol.isNull() ) {
1859 doc += i18n( "Protocol: %1", protocol );
1860 doc += QLatin1String( "</li><li>" );
1862 doc += i18n( "Date and Time: %1" , datetime );
1863 doc += QLatin1String( "</li><li>" );
1864 doc += i18n( "Additional Information: %1" , text );
1865 doc += QLatin1String( "</li></ul><h3>" );
1866 doc += i18n( "Description:" );
1867 doc += QLatin1String( "</h3><p>" );
1868 doc += description;
1869 doc += QLatin1String( "</p>" );
1870 if ( causes.count() ) {
1871 doc += QLatin1String( "<h3>" );
1872 doc += i18n( "Possible Causes:" );
1873 doc += QLatin1String( "</h3><ul><li>" );
1874 doc += causes.join( "</li><li>" );
1875 doc += QLatin1String( "</li></ul>" );
1877 if ( solutions.count() ) {
1878 doc += QLatin1String( "<h3>" );
1879 doc += i18n( "Possible Solutions:" );
1880 doc += QLatin1String( "</h3><ul><li>" );
1881 doc += solutions.join( "</li><li>" );
1882 doc += QLatin1String( "</li></ul>" );
1885 html.replace( QLatin1String("TEXT"), doc );
1887 write( html );
1888 end();
1890 d->m_bJScriptForce = bJSFO;
1891 d->m_bJScriptOverride = bJSOO;
1893 // make the working url the current url, so that reload works and
1894 // emit the progress signals to advance one step in the history
1895 // (so that 'back' works)
1896 setUrl(reqUrl); // same as d->m_workingURL
1897 d->m_workingURL = KUrl();
1898 emit started( 0 );
1899 emit completed();
1902 void KHTMLPart::slotFinished( KJob * job )
1904 d->m_job = 0L;
1905 d->m_jobspeed = 0L;
1907 if (job->error())
1909 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
1911 // The following catches errors that occur as a result of HTTP
1912 // to FTP redirections where the FTP URL is a directory. Since
1913 // KIO cannot change a redirection request from GET to LISTDIR,
1914 // we have to take care of it here once we know for sure it is
1915 // a directory...
1916 if (job->error() == KIO::ERR_IS_DIRECTORY)
1918 emit canceled( job->errorString() );
1919 emit d->m_extension->openUrlRequest( d->m_workingURL );
1921 else
1923 emit canceled( job->errorString() );
1924 // TODO: what else ?
1925 checkCompleted();
1926 showError( job );
1929 return;
1931 KIO::TransferJob *tjob = ::qobject_cast<KIO::TransferJob*>(job);
1932 if (tjob && tjob->isErrorPage()) {
1933 HTMLPartContainerElementImpl *elt = d->m_frame ?
1934 (HTMLPartContainerElementImpl*)d->m_frame->m_partContainerElement : 0;
1936 if (!elt)
1937 return;
1939 elt->partLoadingErrorNotify();
1940 checkCompleted();
1941 if (d->m_bComplete) return;
1944 //kDebug( 6050 ) << "slotFinished";
1946 KHTMLPageCache::self()->endData(d->m_cacheId);
1947 if (d->m_frame && d->m_frame->m_jscript)
1948 d->m_frame->m_jscript->dataReceived();
1950 if ( d->m_doc && d->m_doc->docLoader()->expireDate() && url().protocol().toLower().startsWith("http"))
1951 KIO::http_update_cache(url(), false, d->m_doc->docLoader()->expireDate());
1953 d->m_workingURL = KUrl();
1955 if ( d->m_doc && d->m_doc->parsing())
1956 end(); //will emit completed()
1959 void KHTMLPart::begin( const KUrl &url, int xOffset, int yOffset )
1961 // No need to show this for a new page until an error is triggered
1962 if (!parentPart()) {
1963 removeJSErrorExtension();
1964 setSuppressedPopupIndicator( false );
1965 d->m_openableSuppressedPopups = 0;
1966 foreach ( KHTMLPart* part, d->m_suppressedPopupOriginParts ) {
1967 if (part) {
1968 KJS::Window *w = KJS::Window::retrieveWindow( part );
1969 if (w)
1970 w->forgetSuppressedWindows();
1975 d->m_bCleared = false;
1976 d->m_cacheId = 0;
1977 d->m_bComplete = false;
1978 d->m_bLoadEventEmitted = false;
1979 clear();
1980 d->m_bCleared = false;
1982 if(url.isValid()) {
1983 QString urlString = url.url();
1984 KHTMLGlobal::vLinks()->insert( urlString );
1985 QString urlString2 = url.prettyUrl();
1986 if ( urlString != urlString2 ) {
1987 KHTMLGlobal::vLinks()->insert( urlString2 );
1991 // ###
1992 //stopParser();
1994 KParts::OpenUrlArguments args = arguments();
1995 args.setXOffset(xOffset);
1996 args.setYOffset(yOffset);
1997 setArguments(args);
1999 d->m_pageReferrer.clear();
2001 KUrl ref(url);
2002 d->m_referrer = ref.protocol().startsWith("http") ? ref.url() : "";
2004 setUrl(url);
2006 bool servedAsXHTML = args.mimeType() == "application/xhtml+xml";
2007 bool servedAsSVG = !servedAsXHTML && args.mimeType() == "image/svg+xml";
2008 KMimeType::Ptr mime = KMimeType::mimeType( args.mimeType(), KMimeType::ResolveAliases );
2009 // We want to make sure text/xml and application/xml are both handled right...
2010 bool servedAsXML = mime && mime->is( "text/xml" );
2011 // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl
2012 if ( servedAsSVG ) {
2013 d->m_doc = DOMImplementationImpl::instance()->createSVGDocument( d->m_view );
2014 } else {
2015 if ( servedAsXML && !servedAsXHTML ) { // any XML derivative, except XHTML
2016 d->m_doc = DOMImplementationImpl::instance()->createXMLDocument( d->m_view );
2017 } else {
2018 d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
2019 // HTML or XHTML? (#86446)
2020 static_cast<HTMLDocumentImpl *>(d->m_doc)->setHTMLRequested( !servedAsXHTML );
2024 d->m_doc->ref();
2025 d->m_doc->setURL( url.url() );
2026 d->m_doc->open( );
2027 if (!d->m_doc->attached())
2028 d->m_doc->attach( );
2029 d->m_doc->setBaseURL( KUrl() );
2030 d->m_doc->docLoader()->setShowAnimations( KHTMLGlobal::defaultHTMLSettings()->showAnimations() );
2031 emit docCreated();
2033 d->m_paUseStylesheet->setItems(QStringList());
2034 d->m_paUseStylesheet->setEnabled( false );
2036 setAutoloadImages( KHTMLGlobal::defaultHTMLSettings()->autoLoadImages() );
2037 QString userStyleSheet = KHTMLGlobal::defaultHTMLSettings()->userStyleSheet();
2038 if ( !userStyleSheet.isEmpty() )
2039 setUserStyleSheet( KUrl( userStyleSheet ) );
2041 d->m_doc->setRestoreState(d->m_extension->browserArguments().docState);
2042 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2044 emit d->m_extension->enableAction( "print", true );
2046 d->m_doc->setParsing(true);
2049 void KHTMLPart::write( const char *data, int len )
2051 if ( !d->m_decoder )
2052 d->m_decoder = createDecoder();
2054 if ( len == -1 )
2055 len = strlen( data );
2057 if ( len == 0 )
2058 return;
2060 QString decoded=d->m_decoder->decodeWithBuffering(data,len);
2062 if(decoded.isEmpty())
2063 return;
2065 if(d->m_bFirstData)
2066 onFirstData();
2068 khtml::Tokenizer* t = d->m_doc->tokenizer();
2069 if(t)
2070 t->write( decoded, true );
2073 // ### KDE5: remove
2074 void KHTMLPart::setAlwaysHonourDoctype( bool b )
2076 d->m_bStrictModeQuirk = !b;
2079 void KHTMLPart::write( const QString &str )
2081 if ( str.isNull() )
2082 return;
2084 if(d->m_bFirstData) {
2085 // determine the parse mode
2086 if (d->m_bStrictModeQuirk) {
2087 d->m_doc->setParseMode( DocumentImpl::Strict );
2088 d->m_bFirstData = false;
2089 } else {
2090 onFirstData();
2093 khtml::Tokenizer* t = d->m_doc->tokenizer();
2094 if(t)
2095 t->write( str, true );
2098 void KHTMLPart::end()
2100 if (d->m_doc) {
2101 if (d->m_decoder)
2103 QString decoded=d->m_decoder->flush();
2104 if (d->m_bFirstData)
2105 onFirstData();
2106 if (!decoded.isEmpty())
2107 write(decoded);
2109 d->m_doc->finishParsing();
2113 void KHTMLPart::onFirstData()
2115 assert( d->m_bFirstData );
2117 // determine the parse mode
2118 d->m_doc->determineParseMode();
2119 d->m_bFirstData = false;
2121 // ### this is still quite hacky, but should work a lot better than the old solution
2122 if (d->m_decoder->visuallyOrdered())
2123 d->m_doc->setVisuallyOrdered();
2124 d->m_doc->recalcStyle( NodeImpl::Force );
2127 bool KHTMLPart::doOpenStream( const QString& mimeType )
2129 KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases);
2130 if ( mime && ( mime->is( "text/html" ) || mime->is( "text/xml" ) ) )
2132 begin( url() );
2133 return true;
2135 return false;
2138 bool KHTMLPart::doWriteStream( const QByteArray& data )
2140 write( data.data(), data.size() );
2141 return true;
2144 bool KHTMLPart::doCloseStream()
2146 end();
2147 return true;
2151 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
2153 if (!d->m_view) return;
2154 d->m_view->paint(p, rc, yOff, more);
2157 void KHTMLPart::stopAnimations()
2159 if ( d->m_doc )
2160 d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
2162 ConstFrameIt it = d->m_frames.constBegin();
2163 const ConstFrameIt end = d->m_frames.constEnd();
2164 for (; it != end; ++it )
2165 if ( !(*it)->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
2166 KParts::ReadOnlyPart* const p = ( *it )->m_part;
2167 static_cast<KHTMLPart*>( p )->stopAnimations();
2171 void KHTMLPart::resetFromScript()
2173 closeUrl();
2174 d->m_bComplete = false;
2175 d->m_bLoadEventEmitted = false;
2176 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2177 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2178 d->m_doc->setParsing(true);
2180 emit started( 0L );
2183 void KHTMLPart::slotFinishedParsing()
2185 d->m_doc->setParsing(false);
2186 d->m_doc->dispatchWindowEvent(EventImpl::KHTML_CONTENTLOADED_EVENT, false, false);
2187 checkEmitLoadEvent();
2188 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2190 if (!d->m_view)
2191 return; // We are probably being destructed.
2193 checkCompleted();
2196 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
2198 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
2199 KHTMLPart* p = this;
2200 while ( p ) {
2201 KHTMLPart* const op = p;
2202 ++(p->d->m_totalObjectCount);
2203 p = p->parentPart();
2204 if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount
2205 && !op->d->m_progressUpdateTimer.isActive()) {
2206 op->d->m_progressUpdateTimer.setSingleShot( true );
2207 op->d->m_progressUpdateTimer.start( 200 );
2213 void KHTMLPart::slotLoaderRequestDone( 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_loadedObjects);
2220 p = p->parentPart();
2221 if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount && op->d->m_jobPercent <= 100
2222 && !op->d->m_progressUpdateTimer.isActive()) {
2223 op->d->m_progressUpdateTimer.setSingleShot( true );
2224 op->d->m_progressUpdateTimer.start( 200 );
2229 checkCompleted();
2232 void KHTMLPart::slotProgressUpdate()
2234 int percent;
2235 if ( d->m_loadedObjects < d->m_totalObjectCount )
2236 percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
2237 else
2238 percent = d->m_jobPercent;
2240 if( d->m_bComplete )
2241 percent = 100;
2243 if (d->m_statusMessagesEnabled) {
2244 if( d->m_bComplete )
2245 emit d->m_extension->infoMessage( i18n( "Page loaded." ));
2246 else if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
2247 emit d->m_extension->infoMessage( i18np( "%1 Image of %2 loaded.", "%1 Images of %2 loaded.", d->m_loadedObjects, d->m_totalObjectCount) );
2250 emit d->m_extension->loadingProgress( percent );
2253 void KHTMLPart::slotJobSpeed( KJob* /*job*/, unsigned long speed )
2255 d->m_jobspeed = speed;
2256 if (!parentPart())
2257 setStatusBarText(jsStatusBarText(), BarOverrideText);
2260 void KHTMLPart::slotJobPercent( KJob* /*job*/, unsigned long percent )
2262 d->m_jobPercent = percent;
2264 if ( !parentPart() ) {
2265 d->m_progressUpdateTimer.setSingleShot( true );
2266 d->m_progressUpdateTimer.start( 0 );
2270 void KHTMLPart::slotJobDone( KJob* /*job*/ )
2272 d->m_jobPercent = 100;
2274 if ( !parentPart() ) {
2275 d->m_progressUpdateTimer.setSingleShot( true );
2276 d->m_progressUpdateTimer.start( 0 );
2280 void KHTMLPart::slotUserSheetStatDone( KJob *_job )
2282 using namespace KIO;
2284 if ( _job->error() ) {
2285 showError( _job );
2286 return;
2289 const UDSEntry entry = dynamic_cast<KIO::StatJob *>( _job )->statResult();
2290 const time_t lastModified = entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, -1 );
2292 // If the filesystem supports modification times, only reload the
2293 // user-defined stylesheet if necessary - otherwise always reload.
2294 if ( lastModified != static_cast<time_t>(-1) ) {
2295 if ( d->m_userStyleSheetLastModified >= lastModified ) {
2296 return;
2298 d->m_userStyleSheetLastModified = lastModified;
2301 setUserStyleSheet( KUrl( settings()->userStyleSheet() ) );
2304 void KHTMLPart::checkCompleted()
2306 // kDebug( 6050 ) << this << name();
2307 // kDebug( 6050 ) << " parsing: " << (d->m_doc && d->m_doc->parsing());
2308 // kDebug( 6050 ) << " complete: " << d->m_bComplete;
2310 // restore the cursor position
2311 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
2313 if (d->m_focusNodeNumber >= 0)
2314 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
2316 d->m_focusNodeRestored = true;
2319 bool bPendingChildRedirection = false;
2320 // Any frame that hasn't completed yet ?
2321 ConstFrameIt it = d->m_frames.constBegin();
2322 const ConstFrameIt end = d->m_frames.constEnd();
2323 for (; it != end; ++it ) {
2324 if ( !(*it)->m_bCompleted )
2326 //kDebug( 6050 ) << this << " is waiting for " << (*it)->m_part;
2327 return;
2329 // Check for frames with pending redirections
2330 if ( (*it)->m_bPendingRedirection )
2331 bPendingChildRedirection = true;
2334 // Any object that hasn't completed yet ?
2336 ConstFrameIt oi = d->m_objects.constBegin();
2337 const ConstFrameIt oiEnd = d->m_objects.constEnd();
2339 for (; oi != oiEnd; ++oi )
2340 if ( !(*oi)->m_bCompleted )
2341 return;
2343 // Are we still parsing - or have we done the completed stuff already ?
2344 if ( d->m_bComplete || (d->m_doc && d->m_doc->parsing()) )
2345 return;
2347 // Still waiting for images/scripts from the loader ?
2348 int requests = 0;
2349 if ( d->m_doc && d->m_doc->docLoader() )
2350 requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
2352 if ( requests > 0 )
2354 //kDebug(6050) << "still waiting for images/scripts from the loader - requests:" << requests;
2355 return;
2358 // OK, completed.
2359 // Now do what should be done when we are really completed.
2360 d->m_bComplete = true;
2361 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
2362 d->m_totalObjectCount = 0;
2363 d->m_loadedObjects = 0;
2365 KHTMLPart* p = this;
2366 while ( p ) {
2367 KHTMLPart* op = p;
2368 p = p->parentPart();
2369 if ( !p && !op->d->m_progressUpdateTimer.isActive()) {
2370 op->d->m_progressUpdateTimer.setSingleShot( true );
2371 op->d->m_progressUpdateTimer.start( 0 );
2375 checkEmitLoadEvent(); // if we didn't do it before
2377 bool pendingAction = false;
2379 if ( !d->m_redirectURL.isEmpty() )
2381 // DA: Do not start redirection for frames here! That action is
2382 // deferred until the parent emits a completed signal.
2383 if ( parentPart() == 0 ) {
2384 //kDebug(6050) << this << " starting redirection timer";
2385 d->m_redirectionTimer.setSingleShot( true );
2386 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
2387 } else {
2388 //kDebug(6050) << this << " not toplevel -> not starting redirection timer. Waiting for slotParentCompleted.";
2391 pendingAction = true;
2393 else if ( bPendingChildRedirection )
2395 pendingAction = true;
2398 // the view will emit completed on our behalf,
2399 // either now or at next repaint if one is pending
2401 //kDebug(6050) << this << " asks the view to emit completed. pendingAction=" << pendingAction;
2402 d->m_view->complete( pendingAction );
2404 // find the alternate stylesheets
2405 QStringList sheets;
2406 if (d->m_doc)
2407 sheets = d->m_doc->availableStyleSheets();
2408 sheets.prepend( i18n( "Automatic Detection" ) );
2409 d->m_paUseStylesheet->setItems( sheets );
2411 d->m_paUseStylesheet->setEnabled( sheets.count() > 2);
2412 if (sheets.count() > 2)
2414 d->m_paUseStylesheet->setCurrentItem(qMax(sheets.indexOf(d->m_sheetUsed), 0));
2415 slotUseStylesheet();
2418 setJSDefaultStatusBarText(QString());
2420 #ifdef SPEED_DEBUG
2421 kDebug(6050) << "DONE: " <<d->m_parsetime.elapsed();
2422 #endif
2425 void KHTMLPart::checkEmitLoadEvent()
2427 if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
2429 ConstFrameIt it = d->m_frames.constBegin();
2430 const ConstFrameIt end = d->m_frames.constEnd();
2431 for (; it != end; ++it )
2432 if ( !(*it)->m_bCompleted ) // still got a frame running -> too early
2433 return;
2435 ConstFrameIt oi = d->m_objects.constBegin();
2436 const ConstFrameIt oiEnd = d->m_objects.constEnd();
2438 for (; oi != oiEnd; ++oi )
2439 if ( !(*oi)->m_bCompleted ) // still got a object running -> too early
2440 return;
2442 // Still waiting for images/scripts from the loader ?
2443 // (onload must happen afterwards, #45607)
2444 // ## This makes this method very similar to checkCompleted. A brave soul should try merging them.
2445 int requests = 0;
2446 if ( d->m_doc && d->m_doc->docLoader() )
2447 requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
2449 if ( requests > 0 )
2450 return;
2452 d->m_bLoadEventEmitted = true;
2453 if (d->m_doc)
2454 d->m_doc->close();
2457 const KHTMLSettings *KHTMLPart::settings() const
2459 return d->m_settings;
2462 #ifndef KDE_NO_COMPAT
2463 KUrl KHTMLPart::baseURL() const
2465 if ( !d->m_doc ) return KUrl();
2467 return d->m_doc->baseURL();
2469 #endif
2471 KUrl KHTMLPart::completeURL( const QString &url )
2473 if ( !d->m_doc ) return KUrl( url );
2475 #if 0
2476 if (d->m_decoder)
2477 return KUrl(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
2478 #endif
2480 return KUrl( d->m_doc->completeURL( url ) );
2483 QString KHTMLPartPrivate::codeForJavaScriptURL(const QString &u)
2485 return KUrl::fromPercentEncoding( u.right( u.length() - 11 ).toUtf8() );
2488 void KHTMLPartPrivate::executeJavascriptURL(const QString &u)
2490 QString script = codeForJavaScriptURL(u);
2491 kDebug( 6050 ) << "script=" << script;
2492 QVariant res = q->executeScript( DOM::Node(), script );
2493 if ( res.type() == QVariant::String ) {
2494 q->begin( q->url() );
2495 q->write( res.toString() );
2496 q->end();
2498 emit q->completed();
2501 bool KHTMLPartPrivate::isJavaScriptURL(const QString& url)
2503 return url.indexOf( QLatin1String( "javascript:" ), 0, Qt::CaseInsensitive ) == 0;
2506 // Called by ecma/kjs_window in case of redirections from Javascript,
2507 // and by xml/dom_docimpl.cpp in case of http-equiv meta refresh.
2508 void KHTMLPart::scheduleRedirection( int delay, const QString &url, bool doLockHistory )
2510 kDebug(6050) << "delay=" << delay << " url=" << url;
2511 kDebug(6050) << "current redirectURL=" << d->m_redirectURL << " with delay " << d->m_delayRedirect;
2513 // In case of JS redirections, some, such as jump to anchors, and javascript:
2514 // evaluation should actually be handled immediately, and not waiting until
2515 // the end of the script. (Besides, we don't want to abort the tokenizer for those)
2516 if ( delay == -1 && d->isInPageURL(url) ) {
2517 d->executeInPageURL(url, doLockHistory);
2518 return;
2521 if( delay < 24*60*60 &&
2522 ( d->m_redirectURL.isEmpty() || delay <= d->m_delayRedirect) ) {
2523 d->m_delayRedirect = delay;
2524 d->m_redirectURL = url;
2525 d->m_redirectLockHistory = doLockHistory;
2526 kDebug(6050) << " d->m_bComplete=" << d->m_bComplete;
2528 if ( d->m_bComplete ) {
2529 d->m_redirectionTimer.stop();
2530 d->m_redirectionTimer.setSingleShot( true );
2531 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
2536 void KHTMLPartPrivate::clearRedirection()
2538 m_delayRedirect = 0;
2539 m_redirectURL.clear();
2540 m_redirectionTimer.stop();
2543 void KHTMLPart::slotRedirect()
2545 kDebug(6050) << this;
2546 QString u = d->m_redirectURL;
2547 KUrl url( u );
2548 d->clearRedirection();
2550 if ( d->isInPageURL(u) )
2552 d->executeInPageURL(u, d->m_redirectLockHistory);
2553 return;
2556 KParts::OpenUrlArguments args;
2557 KUrl cUrl( this->url() );
2559 // handle windows opened by JS
2560 if ( openedByJS() && d->m_opener )
2561 cUrl = d->m_opener->url();
2563 if (!KAuthorized::authorizeUrlAction("redirect", cUrl, url))
2565 kWarning(6050) << "KHTMLPart::scheduleRedirection: Redirection from " << cUrl << " to " << url << " REJECTED!";
2566 emit completed();
2567 return;
2570 if ( urlcmp( u, this->url().url(), KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment) )
2572 args.metaData().insert("referrer", d->m_pageReferrer);
2575 // For javascript and META-tag based redirections:
2576 // - We don't take cross-domain-ness in consideration if we are the
2577 // toplevel frame because the new URL may be in a different domain as the current URL
2578 // but that's ok.
2579 // - If we are not the toplevel frame then we check against the toplevelURL()
2580 if (parentPart())
2581 args.metaData().insert("cross-domain", toplevelURL().url());
2583 KParts::BrowserArguments browserArgs;
2584 browserArgs.setLockHistory( d->m_redirectLockHistory );
2585 // _self: make sure we don't use any <base target=>'s
2587 if ( !urlSelected( u, 0, 0, "_self", args, browserArgs ) ) {
2588 // urlSelected didn't open a url, so emit completed ourselves
2589 emit completed();
2593 void KHTMLPart::slotRedirection(KIO::Job*, const KUrl& url)
2595 // the slave told us that we got redirected
2596 //kDebug( 6050 ) << "redirection by KIO to" << url;
2597 emit d->m_extension->setLocationBarUrl( url.prettyUrl() );
2598 d->m_workingURL = url;
2601 bool KHTMLPart::setEncoding( const QString &name, bool override )
2603 d->m_encoding = name;
2604 d->m_haveEncoding = override;
2606 if( !url().isEmpty() ) {
2607 // reload document
2608 closeUrl();
2609 KUrl oldUrl = url();
2610 setUrl(KUrl());
2611 d->m_restored = true;
2612 openUrl(oldUrl);
2613 d->m_restored = false;
2616 return true;
2619 QString KHTMLPart::encoding() const
2621 if(d->m_haveEncoding && !d->m_encoding.isEmpty())
2622 return d->m_encoding;
2624 if(d->m_decoder && d->m_decoder->encoding())
2625 return QString(d->m_decoder->encoding());
2627 return defaultEncoding();
2630 QString KHTMLPart::defaultEncoding() const
2632 QString encoding = settings()->encoding();
2633 if ( !encoding.isEmpty() )
2634 return encoding;
2635 // HTTP requires the default encoding to be latin1, when neither
2636 // the user nor the page requested a particular encoding.
2637 if ( url().protocol().startsWith( "http" ) )
2638 return "iso-8859-1";
2639 else
2640 return KGlobal::locale()->encoding();
2643 void KHTMLPart::setUserStyleSheet(const KUrl &url)
2645 if ( d->m_doc && d->m_doc->docLoader() )
2646 (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
2649 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
2651 if ( d->m_doc )
2652 d->m_doc->setUserStyleSheet( styleSheet );
2655 bool KHTMLPart::gotoAnchor( const QString &name )
2657 if (!d->m_doc)
2658 return false;
2660 HTMLCollectionImpl *anchors =
2661 new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
2662 anchors->ref();
2663 NodeImpl *n = anchors->namedItem(name);
2664 anchors->deref();
2666 if(!n) {
2667 n = d->m_doc->getElementById( name );
2670 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
2672 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2673 bool quirkyName = !n && !d->m_doc->inStrictMode() && (name.isEmpty() || name.toLower() == "top");
2675 if (quirkyName) {
2676 d->m_view->setContentsPos( d->m_view->contentsX(), 0);
2677 return true;
2678 } else if (!n) {
2679 kDebug(6050) << name << "not found";
2680 return false;
2683 int x = 0, y = 0;
2684 int gox, dummy;
2685 HTMLElementImpl *a = static_cast<HTMLElementImpl *>(n);
2687 a->getUpperLeftCorner(x, y);
2688 if (x <= d->m_view->contentsX())
2689 gox = x - 10;
2690 else {
2691 gox = d->m_view->contentsX();
2692 if ( x + 10 > d->m_view->contentsX()+d->m_view->visibleWidth()) {
2693 a->getLowerRightCorner(x, dummy);
2694 gox = x - d->m_view->visibleWidth() + 10;
2698 d->m_view->setContentsPos(gox, y);
2700 return true;
2703 bool KHTMLPart::nextAnchor()
2705 if (!d->m_doc)
2706 return false;
2707 d->m_view->focusNextPrevNode ( true );
2709 return true;
2712 bool KHTMLPart::prevAnchor()
2714 if (!d->m_doc)
2715 return false;
2716 d->m_view->focusNextPrevNode ( false );
2718 return true;
2721 void KHTMLPart::setStandardFont( const QString &name )
2723 d->m_settings->setStdFontName(name);
2726 void KHTMLPart::setFixedFont( const QString &name )
2728 d->m_settings->setFixedFontName(name);
2731 void KHTMLPart::setURLCursor( const QCursor &c )
2733 d->m_linkCursor = c;
2736 QCursor KHTMLPart::urlCursor() const
2738 return d->m_linkCursor;
2741 bool KHTMLPart::onlyLocalReferences() const
2743 return d->m_onlyLocalReferences;
2746 void KHTMLPart::setOnlyLocalReferences(bool enable)
2748 d->m_onlyLocalReferences = enable;
2751 void KHTMLPartPrivate::setFlagRecursively(
2752 bool KHTMLPartPrivate::*flag, bool value)
2754 // first set it on the current one
2755 this->*flag = value;
2757 // descend into child frames recursively
2759 QList<khtml::ChildFrame*>::Iterator it = m_frames.begin();
2760 const QList<khtml::ChildFrame*>::Iterator itEnd = m_frames.end();
2761 for (; it != itEnd; ++it) {
2762 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part );
2763 if (part)
2764 part->d->setFlagRecursively(flag, value);
2765 }/*next it*/
2767 // do the same again for objects
2769 QList<khtml::ChildFrame*>::Iterator it = m_objects.begin();
2770 const QList<khtml::ChildFrame*>::Iterator itEnd = m_objects.end();
2771 for (; it != itEnd; ++it) {
2772 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part );
2773 if (part)
2774 part->d->setFlagRecursively(flag, value);
2775 }/*next it*/
2779 void KHTMLPart::initCaret()
2781 // initialize caret if not used yet
2782 if (d->editor_context.m_selection.state() == Selection::NONE) {
2783 if (d->m_doc) {
2784 NodeImpl *node;
2785 if (d->m_doc->isHTMLDocument()) {
2786 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
2787 node = htmlDoc->body();
2788 } else
2789 node = d->m_doc;
2790 if (!node) return;
2791 d->editor_context.m_selection.moveTo(Position(node, 0));
2792 d->editor_context.m_selection.setNeedsLayout();
2793 d->editor_context.m_selection.needsCaretRepaint();
2798 static void setCaretInvisibleIfNeeded(KHTMLPart *part)
2800 // On contenteditable nodes, don't hide the caret
2801 if (!khtml::KHTMLPartAccessor::caret(part).caretPos().node()->isContentEditable())
2802 part->setCaretVisible(false);
2805 void KHTMLPart::setCaretMode(bool enable)
2807 kDebug(6200) << enable;
2808 if (isCaretMode() == enable) return;
2809 d->setFlagRecursively(&KHTMLPartPrivate::m_caretMode, enable);
2810 // FIXME: this won't work on frames as expected
2811 if (!isEditable()) {
2812 if (enable) {
2813 initCaret();
2814 setCaretVisible(true);
2815 // view()->ensureCaretVisible();
2816 } else {
2817 setCaretInvisibleIfNeeded(this);
2822 bool KHTMLPart::isCaretMode() const
2824 return d->m_caretMode;
2827 void KHTMLPart::setEditable(bool enable)
2829 if (isEditable() == enable) return;
2830 d->setFlagRecursively(&KHTMLPartPrivate::m_designMode, enable);
2831 // FIXME: this won't work on frames as expected
2832 if (!isCaretMode()) {
2833 if (enable) {
2834 initCaret();
2835 setCaretVisible(true);
2836 // view()->ensureCaretVisible();
2837 } else
2838 setCaretInvisibleIfNeeded(this);
2842 bool KHTMLPart::isEditable() const
2844 return d->m_designMode;
2847 khtml::EditorContext *KHTMLPart::editorContext() const {
2848 return &d->editor_context;
2851 void KHTMLPart::setCaretPosition(DOM::Node node, long offset, bool extendSelection)
2853 #ifndef KHTML_NO_CARET
2854 #if 0
2855 kDebug(6200) << "node: " << node.handle() << " nodeName: "
2856 << node.nodeName().string() << " offset: " << offset
2857 << " extendSelection " << extendSelection;
2858 if (view()->moveCaretTo(node.handle(), offset, !extendSelection))
2859 emitSelectionChanged();
2860 view()->ensureCaretVisible();
2861 #endif
2862 #endif // KHTML_NO_CARET
2865 KHTMLPart::CaretDisplayPolicy KHTMLPart::caretDisplayPolicyNonFocused() const
2867 #if 0
2868 #ifndef KHTML_NO_CARET
2869 return (CaretDisplayPolicy)view()->caretDisplayPolicyNonFocused();
2870 #else // KHTML_NO_CARET
2871 return CaretInvisible;
2872 #endif // KHTML_NO_CARET
2873 #endif
2874 return CaretInvisible;
2877 void KHTMLPart::setCaretDisplayPolicyNonFocused(CaretDisplayPolicy policy)
2879 #if 0
2880 #ifndef KHTML_NO_CARET
2881 view()->setCaretDisplayPolicyNonFocused(policy);
2882 #endif // KHTML_NO_CARET
2883 #endif
2886 void KHTMLPart::setCaretVisible(bool show)
2888 if (show) {
2889 NodeImpl *caretNode = d->editor_context.m_selection.caretPos().node();
2890 if (isCaretMode() || (caretNode && caretNode->isContentEditable())) {
2891 invalidateSelection();
2892 enableFindAheadActions(false);
2894 } else {
2896 if (d->editor_context.m_caretBlinkTimer >= 0)
2897 killTimer(d->editor_context.m_caretBlinkTimer);
2898 clearCaretRectIfNeeded();
2903 void KHTMLPart::findTextBegin()
2905 d->m_find.findTextBegin();
2908 bool KHTMLPart::initFindNode( bool selection, bool reverse, bool fromCursor )
2910 return d->m_find.initFindNode(selection, reverse, fromCursor);
2913 void KHTMLPart::slotFind()
2915 KParts::ReadOnlyPart *part = currentFrame();
2916 if (!part)
2917 return;
2918 if (!part->inherits("KHTMLPart") )
2920 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2921 return;
2923 static_cast<KHTMLPart *>( part )->findText();
2926 void KHTMLPart::slotFindNext()
2928 KParts::ReadOnlyPart *part = currentFrame();
2929 if (!part)
2930 return;
2931 if (!part->inherits("KHTMLPart") )
2933 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2934 return;
2936 static_cast<KHTMLPart *>( part )->findTextNext();
2939 void KHTMLPart::slotFindPrev()
2941 KParts::ReadOnlyPart *part = currentFrame();
2942 if (!part)
2943 return;
2944 if (!part->inherits("KHTMLPart") )
2946 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2947 return;
2949 static_cast<KHTMLPart *>( part )->findTextNext( true ); // reverse
2952 void KHTMLPart::slotFindDone()
2954 // ### remove me
2957 void KHTMLPart::slotFindAheadText()
2959 #ifndef KHTML_NO_TYPE_AHEAD_FIND
2960 KParts::ReadOnlyPart *part = currentFrame();
2961 if (!part)
2962 return;
2963 if (!part->inherits("KHTMLPart") )
2965 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2966 return;
2968 static_cast<KHTMLPart *>( part )->view()->startFindAhead( false );
2969 #endif // KHTML_NO_TYPE_AHEAD_FIND
2972 void KHTMLPart::slotFindAheadLink()
2974 #ifndef KHTML_NO_TYPE_AHEAD_FIND
2975 KParts::ReadOnlyPart *part = currentFrame();
2976 if (!part)
2977 return;
2978 if (!part->inherits("KHTMLPart") )
2980 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2981 return;
2983 static_cast<KHTMLPart *>( part )->view()->startFindAhead( true );
2984 #endif // KHTML_NO_TYPE_AHEAD_FIND
2987 void KHTMLPart::enableFindAheadActions( bool enable )
2989 // only the topmost one has shortcuts
2990 KHTMLPart* p = this;
2991 while( p->parentPart())
2992 p = p->parentPart();
2993 p->d->m_paFindAheadText->setEnabled( enable );
2994 p->d->m_paFindAheadLinks->setEnabled( enable );
2997 void KHTMLPart::slotFindDialogDestroyed()
2999 // ### remove me
3002 void KHTMLPart::findText()
3004 if (parentPart())
3005 return parentPart()->findText();
3006 d->m_find.activate();
3009 void KHTMLPart::findText( const QString &str, long options, QWidget *parent, KFindDialog *findDialog )
3011 if (parentPart())
3012 return parentPart()->findText(str, options, parent, findDialog);
3013 d->m_find.createNewKFind(str, options, parent, findDialog );
3016 // New method
3017 bool KHTMLPart::findTextNext( bool reverse )
3019 if (parentPart())
3020 return parentPart()->findTextNext( reverse );
3021 return d->m_find.findTextNext( reverse );
3024 QString KHTMLPart::selectedTextAsHTML() const
3026 const Selection &sel = d->editor_context.m_selection;
3027 if(!hasSelection()) {
3028 kDebug() << "Selection is not valid. Returning empty selection";
3029 return QString();
3031 if(sel.start().offset() < 0 || sel.end().offset() < 0) {
3032 kDebug() << "invalid values for end/startOffset " << sel.start().offset() << " " << sel.end().offset();
3033 return QString();
3035 DOM::Range r = selection();
3036 if(r.isNull() || r.isDetached())
3037 return QString();
3038 int exceptioncode = 0; //ignore the result
3039 return r.handle()->toHTML(exceptioncode).string();
3042 QString KHTMLPart::selectedText() const
3044 bool hasNewLine = true;
3045 bool seenTDTag = false;
3046 QString text;
3047 const Selection &sel = d->editor_context.m_selection;
3048 DOM::Node n = sel.start().node();
3049 while(!n.isNull()) {
3050 if(n.nodeType() == DOM::Node::TEXT_NODE && n.handle()->renderer()) {
3051 DOM::DOMStringImpl *dstr = static_cast<DOM::TextImpl*>(n.handle())->renderString();
3052 QString str(dstr->s, dstr->l);
3053 if(!str.isEmpty()) {
3054 if(seenTDTag) {
3055 text += " ";
3056 seenTDTag = false;
3058 hasNewLine = false;
3059 if(n == sel.start().node() && n == sel.end().node())
3060 text = str.mid(sel.start().offset(), sel.end().offset() - sel.start().offset());
3061 else if(n == sel.start().node())
3062 text = str.mid(sel.start().offset());
3063 else if(n == sel.end().node())
3064 text += str.left(sel.end().offset());
3065 else
3066 text += str;
3069 else {
3070 // This is our simple HTML -> ASCII transformation:
3071 unsigned short id = n.elementId();
3072 switch(id) {
3073 case ID_TEXTAREA:
3074 text += static_cast<HTMLTextAreaElementImpl*>(n.handle())->value().string();
3075 break;
3076 case ID_INPUT:
3077 if (static_cast<HTMLInputElementImpl*>(n.handle())->inputType() != HTMLInputElementImpl::PASSWORD)
3078 text += static_cast<HTMLInputElementImpl*>(n.handle())->value().string();
3079 break;
3080 case ID_SELECT:
3081 text += static_cast<HTMLSelectElementImpl*>(n.handle())->value().string();
3082 break;
3083 case ID_BR:
3084 text += "\n";
3085 hasNewLine = true;
3086 break;
3087 case ID_IMG:
3088 text += static_cast<HTMLImageElementImpl*>(n.handle())->altText().string();
3089 break;
3090 case ID_TD:
3091 break;
3092 case ID_TH:
3093 case ID_HR:
3094 case ID_OL:
3095 case ID_UL:
3096 case ID_LI:
3097 case ID_DD:
3098 case ID_DL:
3099 case ID_DT:
3100 case ID_PRE:
3101 case ID_LISTING:
3102 case ID_BLOCKQUOTE:
3103 case ID_DIV:
3104 if (!hasNewLine)
3105 text += "\n";
3106 hasNewLine = true;
3107 break;
3108 case ID_P:
3109 case ID_TR:
3110 case ID_H1:
3111 case ID_H2:
3112 case ID_H3:
3113 case ID_H4:
3114 case ID_H5:
3115 case ID_H6:
3116 if (!hasNewLine)
3117 text += "\n";
3118 hasNewLine = true;
3119 break;
3122 if(n == sel.end().node()) break;
3123 DOM::Node next = n.firstChild();
3124 if(next.isNull()) next = n.nextSibling();
3125 while( next.isNull() && !n.parentNode().isNull() ) {
3126 n = n.parentNode();
3127 next = n.nextSibling();
3128 unsigned short id = n.elementId();
3129 switch(id) {
3130 case ID_TD:
3131 seenTDTag = true; //Add two spaces after a td if then followed by text.
3132 break;
3133 case ID_TH:
3134 case ID_HR:
3135 case ID_OL:
3136 case ID_UL:
3137 case ID_LI:
3138 case ID_DD:
3139 case ID_DL:
3140 case ID_DT:
3141 case ID_PRE:
3142 case ID_LISTING:
3143 case ID_BLOCKQUOTE:
3144 case ID_DIV:
3145 seenTDTag = false;
3146 if (!hasNewLine)
3147 text += "\n";
3148 hasNewLine = true;
3149 break;
3150 case ID_P:
3151 case ID_TR:
3152 case ID_H1:
3153 case ID_H2:
3154 case ID_H3:
3155 case ID_H4:
3156 case ID_H5:
3157 case ID_H6:
3158 if (!hasNewLine)
3159 text += "\n";
3160 // text += "\n";
3161 hasNewLine = true;
3162 break;
3166 n = next;
3169 if(text.isEmpty())
3170 return QString();
3172 int start = 0;
3173 int end = text.length();
3175 // Strip leading LFs
3176 while ((start < end) && (text[start] == '\n'))
3177 ++start;
3179 // Strip excessive trailing LFs
3180 while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n'))
3181 --end;
3183 return text.mid(start, end-start);
3186 QString KHTMLPart::simplifiedSelectedText() const
3188 QString text = selectedText();
3189 text.replace(QChar(0xa0), ' ');
3190 // remove leading and trailing whitespace
3191 while (!text.isEmpty() && text[0].isSpace())
3192 text = text.mid(1);
3193 while (!text.isEmpty() && text[text.length()-1].isSpace())
3194 text.truncate(text.length()-1);
3195 return text;
3198 bool KHTMLPart::hasSelection() const
3200 return !d->editor_context.m_selection.isEmpty() && !d->editor_context.m_selection.isCollapsed();
3203 DOM::Range KHTMLPart::selection() const
3205 return d->editor_context.m_selection.toRange();
3208 void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const
3210 DOM::Range r = d->editor_context.m_selection.toRange();
3211 s = r.startContainer();
3212 so = r.startOffset();
3213 e = r.endContainer();
3214 eo = r.endOffset();
3217 void KHTMLPart::setSelection( const DOM::Range &r )
3219 setCaret(r);
3222 const Selection &KHTMLPart::caret() const
3224 return d->editor_context.m_selection;
3227 const Selection &KHTMLPart::dragCaret() const
3229 return d->editor_context.m_dragCaret;
3232 void KHTMLPart::setCaret(const Selection &s, bool closeTyping)
3234 if (d->editor_context.m_selection != s) {
3235 clearCaretRectIfNeeded();
3236 setFocusNodeIfNeeded(s);
3237 d->editor_context.m_selection = s;
3238 notifySelectionChanged(closeTyping);
3242 void KHTMLPart::setDragCaret(const DOM::Selection &dragCaret)
3244 if (d->editor_context.m_dragCaret != dragCaret) {
3245 d->editor_context.m_dragCaret.needsCaretRepaint();
3246 d->editor_context.m_dragCaret = dragCaret;
3247 d->editor_context.m_dragCaret.needsCaretRepaint();
3251 void KHTMLPart::clearSelection()
3253 clearCaretRectIfNeeded();
3254 setFocusNodeIfNeeded(d->editor_context.m_selection);
3255 #ifdef APPLE_CHANGES
3256 d->editor_context.m_selection.clear();
3257 #else
3258 d->editor_context.m_selection.collapse();
3259 #endif
3260 notifySelectionChanged();
3263 void KHTMLPart::invalidateSelection()
3265 clearCaretRectIfNeeded();
3266 d->editor_context.m_selection.setNeedsLayout();
3267 selectionLayoutChanged();
3270 void KHTMLPart::setSelectionVisible(bool flag)
3272 if (d->editor_context.m_caretVisible == flag)
3273 return;
3275 clearCaretRectIfNeeded();
3276 setFocusNodeIfNeeded(d->editor_context.m_selection);
3277 d->editor_context.m_caretVisible = flag;
3278 // notifySelectionChanged();
3281 #if 1
3282 void KHTMLPart::slotClearSelection()
3284 if (!isCaretMode()
3285 && d->editor_context.m_selection.state() != Selection::NONE
3286 && !d->editor_context.m_selection.caretPos().node()->isContentEditable())
3287 clearCaretRectIfNeeded();
3288 bool hadSelection = hasSelection();
3289 #ifdef APPLE_CHANGES
3290 d->editor_context.m_selection.clear();
3291 #else
3292 d->editor_context.m_selection.collapse();
3293 #endif
3294 if (hadSelection)
3295 notifySelectionChanged();
3297 #endif
3299 void KHTMLPart::clearCaretRectIfNeeded()
3301 if (d->editor_context.m_caretPaint) {
3302 d->editor_context.m_caretPaint = false;
3303 d->editor_context.m_selection.needsCaretRepaint();
3307 void KHTMLPart::setFocusNodeIfNeeded(const Selection &s)
3309 if (!xmlDocImpl() || s.state() == Selection::NONE)
3310 return;
3312 NodeImpl *n = s.start().node();
3313 NodeImpl *target = (n && n->isContentEditable()) ? n : 0;
3314 if (!target) {
3315 while (n && n != s.end().node()) {
3316 if (n->isContentEditable()) {
3317 target = n;
3318 break;
3320 n = n->traverseNextNode();
3323 assert(target == 0 || target->isContentEditable());
3325 if (target) {
3326 for ( ; target && !target->isFocusable(); target = target->parentNode())
3328 if (target && target->isMouseFocusable())
3329 xmlDocImpl()->setFocusNode(target);
3330 else if (!target || !target->focused())
3331 xmlDocImpl()->setFocusNode(0);
3335 void KHTMLPart::selectionLayoutChanged()
3337 // kill any caret blink timer now running
3338 if (d->editor_context.m_caretBlinkTimer >= 0) {
3339 killTimer(d->editor_context.m_caretBlinkTimer);
3340 d->editor_context.m_caretBlinkTimer = -1;
3343 // see if a new caret blink timer needs to be started
3344 if (d->editor_context.m_caretVisible
3345 && d->editor_context.m_selection.state() != Selection::NONE) {
3346 d->editor_context.m_caretPaint = isCaretMode()
3347 || d->editor_context.m_selection.caretPos().node()->isContentEditable();
3348 if (d->editor_context.m_caretBlinks && d->editor_context.m_caretPaint)
3349 d->editor_context.m_caretBlinkTimer = startTimer(qApp->cursorFlashTime() / 2);
3350 d->editor_context.m_selection.needsCaretRepaint();
3353 if (d->m_doc)
3354 d->m_doc->updateSelection();
3356 // Always clear the x position used for vertical arrow navigation.
3357 // It will be restored by the vertical arrow navigation code if necessary.
3358 d->editor_context.m_xPosForVerticalArrowNavigation = d->editor_context.NoXPosForVerticalArrowNavigation;
3361 void KHTMLPart::notifySelectionChanged(bool closeTyping)
3363 Editor *ed = d->editor_context.m_editor;
3364 selectionLayoutChanged();
3365 if (ed) {
3366 ed->clearTypingStyle();
3368 if (closeTyping)
3369 khtml::TypingCommand::closeTyping(ed->lastEditCommand());
3372 emitSelectionChanged();
3376 void KHTMLPart::timerEvent(QTimerEvent *e)
3378 if (e->timerId() == d->editor_context.m_caretBlinkTimer) {
3379 if (d->editor_context.m_caretBlinks &&
3380 d->editor_context.m_selection.state() != Selection::NONE) {
3381 d->editor_context.m_caretPaint = !d->editor_context.m_caretPaint;
3382 d->editor_context.m_selection.needsCaretRepaint();
3384 } else if (e->timerId() == d->m_DNSPrefetchTimer) {
3385 // kDebug( 6050 ) << "will lookup " << d->m_DNSPrefetchQueue.head() << d->m_numDNSPrefetchedNames;
3386 KIO::HostInfo::prefetchHost( d->m_DNSPrefetchQueue.dequeue() );
3387 if (d->m_DNSPrefetchQueue.isEmpty()) {
3388 killTimer( d->m_DNSPrefetchTimer );
3389 d->m_DNSPrefetchTimer = -1;
3391 } else if (e->timerId() == d->m_DNSTTLTimer) {
3392 foreach (QString name, d->m_lookedupHosts)
3393 d->m_DNSPrefetchQueue.enqueue(name);
3394 if (d->m_DNSPrefetchTimer <= 0)
3395 d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay );
3399 bool KHTMLPart::mayPrefetchHostname( const QString& name )
3401 if (d->m_bDNSPrefetch == DNSPrefetchDisabled)
3402 return false;
3404 if (d->m_numDNSPrefetchedNames >= sMaxDNSPrefetchPerPage)
3405 return false;
3407 if (d->m_bDNSPrefetch == DNSPrefetchOnlyWWWAndSLD) {
3408 int dots = name.count('.');
3409 if (dots > 2 || (dots == 2 && !name.startsWith("www.")))
3410 return false;
3413 if ( d->m_lookedupHosts.contains( name ) )
3414 return false;
3416 d->m_DNSPrefetchQueue.enqueue( name );
3417 d->m_lookedupHosts.insert( name );
3418 d->m_numDNSPrefetchedNames++;
3420 if (d->m_DNSPrefetchTimer < 1)
3421 d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay );
3422 if (d->m_DNSTTLTimer < 1)
3423 d->m_DNSTTLTimer = startTimer( sDNSTTLSeconds*1000 + 1 );
3425 return true;
3428 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
3430 if (d->editor_context.m_caretPaint)
3431 d->editor_context.m_selection.paintCaret(p, rect);
3434 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
3436 d->editor_context.m_dragCaret.paintCaret(p, rect);
3439 DOM::Editor *KHTMLPart::editor() const {
3440 if (!d->editor_context.m_editor)
3441 const_cast<KHTMLPart *>(this)->d->editor_context.m_editor = new DOM::Editor(const_cast<KHTMLPart *>(this));
3442 return d->editor_context.m_editor;
3445 void KHTMLPart::resetHoverText()
3447 if( !d->m_overURL.isEmpty() ) // Only if we were showing a link
3449 d->m_overURL.clear();
3450 d->m_overURLTarget.clear();
3451 emit onURL( QString() );
3452 // revert to default statusbar text
3453 setStatusBarText(QString(), BarHoverText);
3454 emit d->m_extension->mouseOverInfo(KFileItem());
3458 void KHTMLPart::overURL( const QString &url, const QString &target, bool /*shiftPressed*/ )
3460 KUrl u = completeURL(url);
3462 // special case for <a href="">
3463 if ( url.isEmpty() )
3464 u.setFileName( url );
3466 emit onURL( url );
3468 if ( url.isEmpty() ) {
3469 setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText);
3470 return;
3473 if ( d->isJavaScriptURL(url) ) {
3474 QString jscode = d->codeForJavaScriptURL( url );
3475 jscode = KStringHandler::rsqueeze( jscode, 80 ); // truncate if too long
3476 if (url.startsWith("javascript:window.open"))
3477 jscode += i18n(" (In new window)");
3478 setStatusBarText( Qt::escape( jscode ), BarHoverText );
3479 return;
3482 KFileItem item(u, QString(), KFileItem::Unknown);
3483 emit d->m_extension->mouseOverInfo(item);
3485 QString com;
3487 KMimeType::Ptr typ = KMimeType::findByUrl( u );
3489 if ( typ )
3490 com = typ->comment( u );
3492 if ( !u.isValid() ) {
3493 setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText);
3494 return;
3497 if ( u.isLocalFile() )
3499 // TODO : use KIO::stat() and create a KFileItem out of its result,
3500 // to use KFileItem::statusBarText()
3501 QByteArray path = QFile::encodeName( u.path() );
3503 KDE_struct_stat buff;
3504 bool ok = !KDE_stat( path.data(), &buff );
3506 KDE_struct_stat lbuff;
3507 if (ok) ok = !KDE_lstat( path.data(), &lbuff );
3509 QString text = Qt::escape(u.prettyUrl());
3510 QString text2 = text;
3512 if (ok && S_ISLNK( lbuff.st_mode ) )
3514 QString tmp;
3515 if ( com.isNull() )
3516 tmp = i18n( "Symbolic Link");
3517 else
3518 tmp = i18n("%1 (Link)", com);
3519 char buff_two[1024];
3520 text += " -> ";
3521 int n = readlink ( path.data(), buff_two, 1022);
3522 if (n == -1)
3524 text2 += " ";
3525 text2 += tmp;
3526 setStatusBarText(text2, BarHoverText);
3527 return;
3529 buff_two[n] = 0;
3531 text += buff_two;
3532 text += " ";
3533 text += tmp;
3535 else if ( ok && S_ISREG( buff.st_mode ) )
3537 if (buff.st_size < 1024)
3538 text = i18n("%2 (%1 bytes)", (long) buff.st_size, text2); // always put the URL last, in case it contains '%'
3539 else
3541 float d = (float) buff.st_size/1024.0;
3542 text = i18n("%2 (%1 K)", KGlobal::locale()->formatNumber(d, 2), text2); // was %.2f
3544 text += " ";
3545 text += com;
3547 else if ( ok && S_ISDIR( buff.st_mode ) )
3549 text += " ";
3550 text += com;
3552 else
3554 text += " ";
3555 text += com;
3557 setStatusBarText(text, BarHoverText);
3559 else
3561 QString extra;
3562 if (target.toLower() == "_blank")
3564 extra = i18n(" (In new window)");
3566 else if (!target.isEmpty() &&
3567 (target.toLower() != "_top") &&
3568 (target.toLower() != "_self") &&
3569 (target.toLower() != "_parent"))
3571 KHTMLPart *p = this;
3572 while (p->parentPart())
3573 p = p->parentPart();
3574 if (!p->frameExists(target))
3575 extra = i18n(" (In new window)");
3576 else
3577 extra = i18n(" (In other frame)");
3580 if (u.protocol() == QLatin1String("mailto")) {
3581 QString mailtoMsg /* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
3582 mailtoMsg += i18n("Email to: ") + KUrl::fromPercentEncoding(u.path().toLatin1());
3583 const QStringList queries = u.query().mid(1).split('&');
3584 QStringList::ConstIterator it = queries.begin();
3585 const QStringList::ConstIterator itEnd = queries.end();
3586 for (; it != itEnd; ++it)
3587 if ((*it).startsWith(QLatin1String("subject=")))
3588 mailtoMsg += i18n(" - Subject: ") + KUrl::fromPercentEncoding((*it).mid(8).toLatin1());
3589 else if ((*it).startsWith(QLatin1String("cc=")))
3590 mailtoMsg += i18n(" - CC: ") + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
3591 else if ((*it).startsWith(QLatin1String("bcc=")))
3592 mailtoMsg += i18n(" - BCC: ") + KUrl::fromPercentEncoding((*it).mid(4).toLatin1());
3593 mailtoMsg = Qt::escape(mailtoMsg);
3594 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), QString());
3595 setStatusBarText("<qt>"+mailtoMsg, BarHoverText);
3596 return;
3598 // Is this check necessary at all? (Frerich)
3599 #if 0
3600 else if (u.protocol() == QLatin1String("http")) {
3601 DOM::Node hrefNode = nodeUnderMouse().parentNode();
3602 while (hrefNode.nodeName().string() != QLatin1String("A") && !hrefNode.isNull())
3603 hrefNode = hrefNode.parentNode();
3605 if (!hrefNode.isNull()) {
3606 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
3607 if (!hreflangNode.isNull()) {
3608 QString countryCode = hreflangNode.nodeValue().string().toLower();
3609 // Map the language code to an appropriate country code.
3610 if (countryCode == QLatin1String("en"))
3611 countryCode = QLatin1String("gb");
3612 QString flagImg = QLatin1String("<img src=%1>").arg(
3613 locate("locale", QLatin1String("l10n/")
3614 + countryCode
3615 + QLatin1String("/flag.png")));
3616 emit setStatusBarText(flagImg + u.prettyUrl() + extra);
3620 #endif
3621 setStatusBarText(Qt::escape(u.prettyUrl()) + extra, BarHoverText);
3626 // This executes in the active part on a click or other url selection action in
3627 // that active part.
3629 bool KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target, const KParts::OpenUrlArguments& _args, const KParts::BrowserArguments& _browserArgs )
3631 KParts::OpenUrlArguments args = _args;
3632 KParts::BrowserArguments browserArgs = _browserArgs;
3633 bool hasTarget = false;
3635 QString target = _target;
3636 if ( target.isEmpty() && d->m_doc )
3637 target = d->m_doc->baseTarget();
3638 if ( !target.isEmpty() )
3639 hasTarget = true;
3641 if ( d->isJavaScriptURL(url) )
3643 crossFrameExecuteScript( target, d->codeForJavaScriptURL(url) );
3644 return false;
3647 KUrl cURL = completeURL(url);
3648 // special case for <a href=""> (IE removes filename, mozilla doesn't)
3649 if ( url.isEmpty() )
3650 cURL.setFileName( url ); // removes filename
3652 if ( !cURL.isValid() )
3653 // ### ERROR HANDLING
3654 return false;
3656 kDebug(6050) << this << "complete URL:" << cURL.url() << "target=" << target;
3658 if ( state & Qt::ControlModifier )
3660 browserArgs.setNewTab(true);
3661 emit d->m_extension->createNewWindow( cURL, args, browserArgs );
3662 return true;
3665 if ( button == Qt::LeftButton && ( state & Qt::ShiftModifier ) )
3667 KIO::MetaData metaData;
3668 metaData.insert( "referrer", d->m_referrer );
3669 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), cURL, metaData );
3670 return false;
3673 if (!checkLinkSecurity(cURL,
3674 ki18n( "<qt>This untrusted page links to<br /><b>%1</b>.<br />Do you want to follow the link?</qt>" ),
3675 i18n( "Follow" )))
3676 return false;
3678 browserArgs.frameName = target;
3680 args.metaData().insert("main_frame_request",
3681 parentPart() == 0 ? "TRUE":"FALSE");
3682 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
3683 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
3684 args.metaData().insert("PropagateHttpHeader", "true");
3685 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
3686 args.metaData().insert("ssl_activate_warnings", "TRUE");
3688 if ( hasTarget && target != "_self" && target != "_top" && target != "_blank" && target != "_parent" )
3690 // unknown frame names should open in a new window.
3691 khtml::ChildFrame *frame = recursiveFrameRequest( this, cURL, args, browserArgs, false );
3692 if ( frame )
3694 args.metaData()["referrer"] = d->m_referrer;
3695 requestObject( frame, cURL, args, browserArgs );
3696 return true;
3700 if (!d->m_referrer.isEmpty() && !args.metaData().contains("referrer"))
3701 args.metaData()["referrer"] = d->m_referrer;
3703 if ( button == Qt::NoButton && (state & Qt::ShiftModifier) && (state & Qt::ControlModifier) )
3705 emit d->m_extension->createNewWindow( cURL, args, browserArgs );
3706 return true;
3709 if ( state & Qt::ShiftModifier)
3711 KParts::WindowArgs winArgs;
3712 winArgs.setLowerWindow(true);
3713 emit d->m_extension->createNewWindow( cURL, args, browserArgs, winArgs );
3714 return true;
3717 //If we're asked to open up an anchor in the current URL, in current window,
3718 //merely gotoanchor, and do not reload the new page. Note that this does
3719 //not apply if the URL is the same page, but without a ref
3720 if (cURL.hasRef() && (!hasTarget || target == "_self"))
3722 if (d->isLocalAnchorJump(cURL))
3724 d->executeAnchorJump(cURL, browserArgs.lockHistory() );
3725 return false; // we jumped, but we didn't open a URL
3729 if ( !d->m_bComplete && !hasTarget )
3730 closeUrl();
3732 view()->viewport()->unsetCursor();
3733 emit d->m_extension->openUrlRequest( cURL, args, browserArgs );
3734 return true;
3737 void KHTMLPart::slotViewDocumentSource()
3739 KUrl currentUrl(this->url());
3740 bool isTempFile = false;
3741 if (!(currentUrl.isLocalFile()) && KHTMLPageCache::self()->isComplete(d->m_cacheId))
3743 KTemporaryFile sourceFile;
3744 sourceFile.setSuffix(defaultExtension());
3745 sourceFile.setAutoRemove(false);
3746 if (sourceFile.open())
3748 QDataStream stream ( &sourceFile );
3749 KHTMLPageCache::self()->saveData(d->m_cacheId, &stream);
3750 currentUrl = KUrl();
3751 currentUrl.setPath(sourceFile.fileName());
3752 isTempFile = true;
3756 (void) KRun::runUrl( currentUrl, QLatin1String("text/plain"), view(), isTempFile );
3759 void KHTMLPart::slotViewPageInfo()
3761 Ui_KHTMLInfoDlg ui;
3763 QDialog *dlg = new QDialog(0);
3764 dlg->setAttribute(Qt::WA_DeleteOnClose);
3765 dlg->setObjectName("KHTML Page Info Dialog");
3766 ui.setupUi(dlg);
3768 ui._close->setGuiItem(KStandardGuiItem::close());
3770 connect(ui._close, SIGNAL(clicked()), dlg, SLOT(accept()));
3771 if (d->m_doc)
3772 ui._title->setText(d->m_doc->title().string());
3774 // If it's a frame, set the caption to "Frame Information"
3775 if ( parentPart() && d->m_doc && d->m_doc->isHTMLDocument() ) {
3776 dlg->setWindowTitle(i18n("Frame Information"));
3779 QString editStr;
3781 if (!d->m_pageServices.isEmpty())
3782 editStr = i18n(" <a href=\"%1\">[Properties]</a>", d->m_pageServices);
3784 QString squeezedURL = KStringHandler::csqueeze( url().prettyUrl(), 80 );
3785 ui._url->setText("<a href=\"" + url().url() + "\">" + squeezedURL + "</a>" + editStr);
3786 if (lastModified().isEmpty())
3788 ui._lastModified->hide();
3789 ui._lmLabel->hide();
3791 else
3792 ui._lastModified->setText(lastModified());
3794 const QString& enc = encoding();
3795 if (enc.isEmpty()) {
3796 ui._eLabel->hide();
3797 ui._encoding->hide();
3798 } else {
3799 ui._encoding->setText(enc);
3801 /* populate the list view now */
3802 const QStringList headers = d->m_httpHeaders.split("\n");
3804 QStringList::ConstIterator it = headers.begin();
3805 const QStringList::ConstIterator itEnd = headers.end();
3807 for (; it != itEnd; ++it) {
3808 const QStringList header = (*it).split(QRegExp(":[ ]+"));
3809 if (header.count() != 2)
3810 continue;
3811 QTreeWidgetItem *item = new QTreeWidgetItem(ui._headers);
3812 item->setText(0, header[0]);
3813 item->setText(1, header[1]);
3816 dlg->show();
3817 /* put no code here */
3821 void KHTMLPart::slotViewFrameSource()
3823 KParts::ReadOnlyPart *frame = currentFrame();
3824 if ( !frame )
3825 return;
3827 KUrl url = frame->url();
3828 bool isTempFile = false;
3829 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
3831 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
3833 if (KHTMLPageCache::self()->isComplete(cacheId))
3835 KTemporaryFile sourceFile;
3836 sourceFile.setSuffix(defaultExtension());
3837 sourceFile.setAutoRemove(false);
3838 if (sourceFile.open())
3840 QDataStream stream ( &sourceFile );
3841 KHTMLPageCache::self()->saveData(cacheId, &stream);
3842 url = KUrl();
3843 url.setPath(sourceFile.fileName());
3844 isTempFile = true;
3849 (void) KRun::runUrl( url, QLatin1String("text/plain"), view(), isTempFile );
3852 KUrl KHTMLPart::backgroundURL() const
3854 // ### what about XML documents? get from CSS?
3855 if (!d->m_doc || !d->m_doc->isHTMLDocument())
3856 return KUrl();
3858 QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
3860 return KUrl( url(), relURL );
3863 void KHTMLPart::slotSaveBackground()
3865 KIO::MetaData metaData;
3866 metaData["referrer"] = d->m_referrer;
3867 KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save Background Image As"), backgroundURL(), metaData );
3870 void KHTMLPart::slotSaveDocument()
3872 KUrl srcURL( url() );
3874 if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() )
3875 srcURL.setFileName( "index" + defaultExtension() );
3877 KIO::MetaData metaData;
3878 // Referre unknown?
3879 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, "text/html", d->m_cacheId );
3882 void KHTMLPart::slotSecurity()
3884 // kDebug( 6050 ) << "Meta Data:" << endl
3885 // << d->m_ssl_peer_cert_subject
3886 // << endl
3887 // << d->m_ssl_peer_cert_issuer
3888 // << endl
3889 // << d->m_ssl_cipher
3890 // << endl
3891 // << d->m_ssl_cipher_desc
3892 // << endl
3893 // << d->m_ssl_cipher_version
3894 // << endl
3895 // << d->m_ssl_good_from
3896 // << endl
3897 // << d->m_ssl_good_until
3898 // << endl
3899 // << d->m_ssl_cert_state
3900 // << endl;
3902 //### reenable with new signature
3903 #if 0
3904 KSSLInfoDialog *kid = new KSSLInfoDialog(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
3906 const QStringList sl = d->m_ssl_peer_chain.split('\n', QString::SkipEmptyParts);
3907 QList<QSslCertificate> certChain;
3908 bool certChainOk = d->m_ssl_in_use;
3909 if (certChainOk) {
3910 foreach (const QString &s, sl) {
3911 certChain.append(QSslCertificate(s.toAscii())); //or is it toLocal8Bit or whatever?
3912 if (certChain.last().isNull()) {
3913 certChainOk = false;
3914 break;
3918 if (certChainOk) {
3919 kid->setup(certChain,
3920 d->m_ssl_peer_ip,
3921 url().url(),
3922 d->m_ssl_cipher,
3923 d->m_ssl_cipher_desc,
3924 d->m_ssl_cipher_version,
3925 d->m_ssl_cipher_used_bits.toInt(),
3926 d->m_ssl_cipher_bits.toInt(),
3927 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt());
3929 kid->exec();
3930 //the dialog deletes itself on close
3931 #endif
3933 KSSLInfoDialog *kid = new KSSLInfoDialog(0);
3934 //### This is boilerplate code and it's copied from SlaveInterface.
3935 QStringList sl = d->m_ssl_peer_chain.split('\x01', QString::SkipEmptyParts);
3936 QList<QSslCertificate> certChain;
3937 bool decodedOk = true;
3938 foreach (const QString &s, sl) {
3939 certChain.append(QSslCertificate(s.toAscii())); //or is it toLocal8Bit or whatever?
3940 if (certChain.last().isNull()) {
3941 decodedOk = false;
3942 break;
3946 if (decodedOk || true /*H4X*/) {
3947 kid->setSslInfo(certChain,
3948 d->m_ssl_peer_ip,
3949 url().url(),
3950 d->m_ssl_protocol_version,
3951 d->m_ssl_cipher,
3952 d->m_ssl_cipher_used_bits.toInt(),
3953 d->m_ssl_cipher_bits.toInt(),
3954 KSSLInfoDialog::errorsFromString(d->m_ssl_cert_errors));
3955 kDebug(7024) << "Showing SSL Info dialog";
3956 kid->exec();
3957 kDebug(7024) << "SSL Info dialog closed";
3958 } else {
3959 KMessageBox::information(0, i18n("The peer SSL certificate chain "
3960 "appears to be corrupt."),
3961 i18n("SSL"));
3965 void KHTMLPart::slotSaveFrame()
3967 KParts::ReadOnlyPart *frame = currentFrame();
3968 if ( !frame )
3969 return;
3971 KUrl srcURL( frame->url() );
3973 if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() )
3974 srcURL.setFileName( "index" + defaultExtension() );
3976 KIO::MetaData metaData;
3977 // Referrer unknown?
3978 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save Frame As" ), srcURL, metaData, "text/html" );
3981 void KHTMLPart::slotSetEncoding(const QString &enc)
3983 d->m_autoDetectLanguage=KEncodingDetector::None;
3984 setEncoding( enc, true);
3987 void KHTMLPart::slotAutomaticDetectionLanguage(KEncodingDetector::AutoDetectScript scri)
3989 d->m_autoDetectLanguage=scri;
3990 setEncoding( QString(), false );
3993 void KHTMLPart::slotUseStylesheet()
3995 if (d->m_doc)
3997 bool autoselect = (d->m_paUseStylesheet->currentItem() == 0);
3998 d->m_sheetUsed = autoselect ? QString() : d->m_paUseStylesheet->currentText();
3999 d->m_doc->updateStyleSelector();
4003 void KHTMLPart::updateActions()
4005 bool frames = false;
4007 QList<khtml::ChildFrame*>::ConstIterator it = d->m_frames.constBegin();
4008 const QList<khtml::ChildFrame*>::ConstIterator end = d->m_frames.constEnd();
4009 for (; it != end; ++it )
4010 if ( (*it)->m_type == khtml::ChildFrame::Frame )
4012 frames = true;
4013 break;
4016 if (d->m_paViewFrame)
4017 d->m_paViewFrame->setEnabled( frames );
4018 if (d->m_paSaveFrame)
4019 d->m_paSaveFrame->setEnabled( frames );
4021 if ( frames )
4022 d->m_paFind->setText( i18n( "&Find in Frame..." ) );
4023 else
4024 d->m_paFind->setText( i18n( "&Find..." ) );
4026 KParts::Part *frame = 0;
4028 if ( frames )
4029 frame = currentFrame();
4031 bool enableFindAndSelectAll = true;
4033 if ( frame )
4034 enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
4036 d->m_paFind->setEnabled( enableFindAndSelectAll );
4037 d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
4039 bool enablePrintFrame = false;
4041 if ( frame )
4043 QObject *ext = KParts::BrowserExtension::childObject( frame );
4044 if ( ext )
4045 enablePrintFrame = ext->metaObject()->indexOfSlot( "print()" ) != -1;
4048 d->m_paPrintFrame->setEnabled( enablePrintFrame );
4050 QString bgURL;
4052 // ### frames
4053 if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
4054 bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
4056 if (d->m_paSaveBackground)
4057 d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
4059 if ( d->m_paDebugScript )
4060 d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
4063 KParts::LiveConnectExtension *KHTMLPart::liveConnectExtension( const DOM::NodeImpl *frame) {
4064 const ConstFrameIt end = d->m_objects.constEnd();
4065 for(ConstFrameIt it = d->m_objects.constBegin(); it != end; ++it )
4066 if ((*it)->m_partContainerElement == frame)
4067 return (*it)->m_liveconnect;
4068 return 0L;
4071 bool KHTMLPart::requestFrame( DOM::HTMLPartContainerElementImpl *frame, const QString &url,
4072 const QString &frameName, const QStringList &params, bool isIFrame )
4074 //kDebug( 6050 ) << this << " requestFrame( ..., " << url << ", " << frameName << " )";
4075 FrameIt it = d->m_frames.find( frameName );
4076 if ( it == d->m_frames.end() )
4078 khtml::ChildFrame * child = new khtml::ChildFrame;
4079 //kDebug( 6050 ) << "inserting new frame into frame map " << frameName;
4080 child->m_name = frameName;
4081 it = d->m_frames.insert( d->m_frames.end(), child );
4084 (*it)->m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
4085 (*it)->m_partContainerElement = frame;
4086 (*it)->m_params = params;
4088 // Support for <frame src="javascript:string">
4089 if ( d->isJavaScriptURL(url) )
4091 if ( processObjectRequest(*it, KUrl("about:blank"), QString("text/html") ) ) {
4092 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>((*it)->m_part));
4094 // See if we want to replace content with javascript: output..
4095 QVariant res = p->executeScript( DOM::Node(),
4096 d->codeForJavaScriptURL(url) );
4097 if ( res.type() == QVariant::String && p->d->m_redirectURL.isEmpty() ) {
4098 p->begin();
4099 // We recreated the document, so propagate domain again.
4100 d->propagateInitialDomainTo( p );
4101 p->write( res.toString() );
4102 p->end();
4104 return true;
4106 return false;
4108 KUrl u = url.isEmpty() ? KUrl() : completeURL( url );
4109 return requestObject( *it, u );
4112 QString KHTMLPart::requestFrameName()
4114 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
4117 bool KHTMLPart::requestObject( DOM::HTMLPartContainerElementImpl *frame, const QString &url,
4118 const QString &serviceType, const QStringList &params )
4120 //kDebug( 6005 ) << this << "frame=" << frame;
4121 khtml::ChildFrame *child = new khtml::ChildFrame;
4122 FrameIt it = d->m_objects.insert( d->m_objects.end(), child );
4123 (*it)->m_partContainerElement = frame;
4124 (*it)->m_type = khtml::ChildFrame::Object;
4125 (*it)->m_params = params;
4127 KParts::OpenUrlArguments args;
4128 args.setMimeType(serviceType);
4129 if (!requestObject( *it, completeURL( url ), args ) && !(*it)->m_run) {
4130 (*it)->m_bCompleted = true;
4131 return false;
4133 return true;
4136 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KUrl &url, const KParts::OpenUrlArguments &_args,
4137 const KParts::BrowserArguments& browserArgs )
4139 if (!checkLinkSecurity(url))
4141 kDebug(6005) << this << "checkLinkSecurity refused";
4142 return false;
4144 if ( child->m_bPreloaded )
4146 kDebug(6005) << "preload";
4147 if ( child->m_partContainerElement && child->m_part )
4148 child->m_partContainerElement->setWidget( child->m_part->widget() );
4150 child->m_bPreloaded = false;
4151 return true;
4154 //kDebug(6005) << "child=" << child << "child->m_part=" << child->m_part;
4156 KParts::OpenUrlArguments args( _args );
4158 if ( child->m_run )
4159 child->m_run->abort();
4161 if ( child->m_part && !args.reload() && urlcmp( child->m_part->url().url(), url.url(), KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment ) )
4162 args.setMimeType(child->m_serviceType);
4164 child->m_browserArgs = browserArgs;
4165 child->m_args = args;
4166 child->m_args.setReload(d->m_cachePolicy == KIO::CC_Reload);
4167 child->m_serviceName.clear();
4168 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
4169 child->m_args.metaData()["referrer"] = d->m_referrer;
4171 child->m_args.metaData().insert("PropagateHttpHeader", "true");
4172 child->m_args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
4173 child->m_args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
4174 child->m_args.metaData().insert("main_frame_request",
4175 parentPart() == 0 ? "TRUE":"FALSE");
4176 child->m_args.metaData().insert("ssl_was_in_use",
4177 d->m_ssl_in_use ? "TRUE":"FALSE");
4178 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
4179 child->m_args.metaData().insert("cross-domain", toplevelURL().url());
4181 // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
4182 if ((url.isEmpty() || url.url() == "about:blank") && args.mimeType().isEmpty())
4183 args.setMimeType(QLatin1String("text/html"));
4185 if ( args.mimeType().isEmpty() ) {
4186 kDebug(6050) << "Running new KHTMLRun for" << this << "and child=" << child;
4187 child->m_run = new KHTMLRun( this, child, url, child->m_args, child->m_browserArgs, true );
4188 d->m_bComplete = false; // ensures we stop it in checkCompleted...
4189 return false;
4190 } else {
4191 return processObjectRequest( child, url, args.mimeType() );
4195 void KHTMLPart::childLoadFailure( khtml::ChildFrame *child )
4197 child->m_bCompleted = true;
4198 if ( child->m_partContainerElement )
4199 child->m_partContainerElement->partLoadingErrorNotify();
4201 checkCompleted();
4204 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KUrl &_url, const QString &mimetype )
4206 //kDebug( 6050 ) << "trying to create part for" << mimetype;
4208 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
4209 // by an emitting frame part (emit openUrlRequest( blahurl, ... ) . A few lines below we delete the part
4210 // though -> the reference becomes invalid -> crash is likely
4211 KUrl url( _url );
4213 // khtmlrun called us this way to indicate a loading error
4214 if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
4216 childLoadFailure(child);
4217 return true;
4220 if (child->m_bNotify)
4222 child->m_bNotify = false;
4223 if ( !child->m_browserArgs.lockHistory() )
4224 emit d->m_extension->openUrlNotify();
4227 if ( child->m_serviceType != mimetype || !child->m_part || (child->m_run && child->m_run->serverSuggestsSave()))
4229 // We often get here if we didn't know the mimetype in advance, and had to rely
4230 // on KRun to figure it out. In this case, we let the element check if it wants to
4231 // handle this mimetype itself, for e.g. images.
4232 if ( child->m_partContainerElement &&
4233 child->m_partContainerElement->mimetypeHandledInternally(mimetype) ) {
4234 child->m_bCompleted = true;
4235 checkCompleted();
4236 return true;
4239 // Before attempting to load a part, check if the user wants that.
4240 // Many don't like getting ZIP files embedded.
4241 // However we don't want to ask for flash and other plugin things..
4242 if ( child->m_type != khtml::ChildFrame::Object && child->m_type != khtml::ChildFrame::IFrame )
4244 QString suggestedFileName;
4245 int disposition = 0;
4246 if ( child->m_run ) {
4247 suggestedFileName = child->m_run->suggestedFileName();
4248 disposition = (child->m_run->serverSuggestsSave()) ? KParts::BrowserRun::AttachmentDisposition : KParts::BrowserRun::InlineDisposition;
4251 KParts::BrowserRun::AskSaveResult res = KParts::BrowserRun::askEmbedOrSave(
4252 url, mimetype, suggestedFileName, disposition );
4253 switch( res ) {
4254 case KParts::BrowserRun::Save:
4255 KHTMLPopupGUIClient::saveURL( widget(), i18n( "Save As" ), url, child->m_args.metaData(), QString(), 0, suggestedFileName );
4256 // fall-through
4257 case KParts::BrowserRun::Cancel:
4258 child->m_bCompleted = true;
4259 checkCompleted();
4260 return true; // done
4261 default: // Open
4262 break;
4266 KMimeType::Ptr mime = KMimeType::mimeType(mimetype);
4267 if (mime) {
4268 // If KHTMLPart can handle the frame, then let's force using it, even
4269 // if the normally preferred part is another one, so that cross-frame
4270 // scripting can work.
4271 if (mime->is("text/html")
4272 || mime->is("application/xml")) { // this includes xhtml and svg
4273 child->m_serviceName = "khtml";
4277 QStringList dummy; // the list of servicetypes handled by the part is now unused.
4278 KParts::ReadOnlyPart *part = createPart( d->m_view->viewport(), this, mimetype, child->m_serviceName, dummy, child->m_params );
4280 if ( !part )
4282 childLoadFailure(child);
4283 return false;
4286 part->setObjectName( child->m_name );
4288 //CRITICAL STUFF
4289 if ( child->m_part )
4291 if (!qobject_cast<KHTMLPart*>(child->m_part) && child->m_jscript)
4292 child->m_jscript->clear();
4293 partManager()->removePart( (KParts::ReadOnlyPart *)child->m_part );
4294 delete (KParts::ReadOnlyPart *)child->m_part;
4295 if (child->m_liveconnect) {
4296 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 &)));
4297 child->m_liveconnect = 0L;
4301 child->m_serviceType = mimetype;
4302 if ( child->m_partContainerElement && part->widget() )
4303 child->m_partContainerElement->setWidget( part->widget() );
4305 if ( child->m_type != khtml::ChildFrame::Object )
4306 partManager()->addPart( part, false );
4307 // else
4308 // kDebug(6005) << "AH! NO FRAME!!!!!";
4310 child->m_part = part;
4312 if (qobject_cast<KHTMLPart*>(part)) {
4313 static_cast<KHTMLPart*>(part)->d->m_frame = child;
4314 } else if (child->m_partContainerElement) {
4315 child->m_liveconnect = KParts::LiveConnectExtension::childObject(part);
4316 if (child->m_liveconnect)
4317 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 &)));
4319 KParts::StatusBarExtension *sb = KParts::StatusBarExtension::childObject(part);
4320 if (sb)
4321 sb->setStatusBar( d->m_statusBarExtension->statusBar() );
4323 connect( part, SIGNAL( started( KIO::Job *) ),
4324 this, SLOT( slotChildStarted( KIO::Job *) ) );
4325 connect( part, SIGNAL( completed() ),
4326 this, SLOT( slotChildCompleted() ) );
4327 connect( part, SIGNAL( completed(bool) ),
4328 this, SLOT( slotChildCompleted(bool) ) );
4329 connect( part, SIGNAL( setStatusBarText( const QString & ) ),
4330 this, SIGNAL( setStatusBarText( const QString & ) ) );
4331 if ( part->inherits( "KHTMLPart" ) )
4333 connect( this, SIGNAL( completed() ),
4334 part, SLOT( slotParentCompleted() ) );
4335 connect( this, SIGNAL( completed(bool) ),
4336 part, SLOT( slotParentCompleted() ) );
4337 // As soon as the child's document is created, we need to set its domain
4338 // (but we do so only once, so it can't be simply done in the child)
4339 connect( part, SIGNAL( docCreated() ),
4340 this, SLOT( slotChildDocCreated() ) );
4343 child->m_extension = KParts::BrowserExtension::childObject( part );
4345 if ( child->m_extension )
4347 connect( child->m_extension, SIGNAL( openUrlNotify() ),
4348 d->m_extension, SIGNAL( openUrlNotify() ) );
4350 connect( child->m_extension, SIGNAL( openUrlRequestDelayed( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments & ) ),
4351 this, SLOT( slotChildURLRequest( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments & ) ) );
4353 connect( child->m_extension, SIGNAL( createNewWindow( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments &, const KParts::WindowArgs &, KParts::ReadOnlyPart ** ) ),
4354 d->m_extension, SIGNAL( createNewWindow( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments & , const KParts::WindowArgs &, KParts::ReadOnlyPart **) ) );
4356 connect( child->m_extension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)),
4357 d->m_extension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) );
4358 connect( child->m_extension, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)),
4359 d->m_extension, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) );
4361 connect( child->m_extension, SIGNAL( infoMessage( const QString & ) ),
4362 d->m_extension, SIGNAL( infoMessage( const QString & ) ) );
4364 connect( child->m_extension, SIGNAL( requestFocus( KParts::ReadOnlyPart * ) ),
4365 this, SLOT( slotRequestFocus( KParts::ReadOnlyPart * ) ) );
4367 child->m_extension->setBrowserInterface( d->m_extension->browserInterface() );
4370 else if ( child->m_partContainerElement && child->m_part &&
4371 child->m_partContainerElement->childWidget() != child->m_part->widget() )
4372 child->m_partContainerElement->setWidget( child->m_part->widget() );
4374 checkEmitLoadEvent();
4375 // Some JS code in the load event may have destroyed the part
4376 // In that case, abort
4377 if ( !child->m_part )
4378 return false;
4380 if ( child->m_bPreloaded )
4382 if ( child->m_partContainerElement && child->m_part )
4383 child->m_partContainerElement->setWidget( child->m_part->widget() );
4385 child->m_bPreloaded = false;
4386 return true;
4389 child->m_args.setReload(d->m_cachePolicy == KIO::CC_Reload);
4391 // make sure the part has a way to find out about the mimetype.
4392 // we actually set it in child->m_args in requestObject already,
4393 // but it's useless if we had to use a KHTMLRun instance, as the
4394 // point the run object is to find out exactly the mimetype.
4395 child->m_args.setMimeType(mimetype);
4397 // if not a frame set child as completed
4398 child->m_bCompleted = child->m_type == khtml::ChildFrame::Object;
4400 if ( child->m_part ) {
4401 child->m_part->setArguments( child->m_args );
4403 if ( child->m_extension ) {
4404 child->m_extension->setBrowserArguments( child->m_browserArgs );
4407 if(url.protocol() == "javascript" || url.url() == "about:blank") {
4408 if (!child->m_part->inherits("KHTMLPart"))
4409 return false;
4411 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(child->m_part));
4413 p->begin();
4414 if (d->m_doc && p->d->m_doc)
4415 p->d->m_doc->setBaseURL(d->m_doc->baseURL());
4417 // We may have to re-propagate the domain here if we go here due to navigation
4418 d->propagateInitialDomainTo(p);
4420 if (!url.url().startsWith("about:")) {
4421 p->write(url.path());
4422 } else {
4423 p->setUrl(url);
4424 // we need a body element. testcase: <iframe id="a"></iframe><script>alert(a.document.body);</script>
4425 p->write("<HTML><TITLE></TITLE><BODY></BODY></HTML>");
4427 p->end();
4428 return true;
4430 else if ( !url.isEmpty() )
4432 //kDebug( 6050 ) << "opening" << url << "in frame" << child->m_part;
4433 bool b = child->m_part->openUrl( url );
4434 if (child->m_bCompleted)
4435 checkCompleted();
4436 return b;
4438 else
4440 child->m_bCompleted = true;
4441 checkCompleted();
4442 return true;
4446 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget,
4447 QObject *parent, const QString &mimetype,
4448 QString &serviceName, QStringList &serviceTypes,
4449 const QStringList &params )
4451 QString constr;
4452 if ( !serviceName.isEmpty() )
4453 constr.append( QString::fromLatin1( "DesktopEntryName == '%1'" ).arg( serviceName ) );
4455 KService::List offers = KMimeTypeTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr );
4457 if ( offers.isEmpty() ) {
4458 int pos = mimetype.indexOf( "-plugin" );
4459 if (pos < 0)
4460 return 0L;
4461 QString stripped_mime = mimetype.left( pos );
4462 offers = KMimeTypeTrader::self()->query( stripped_mime, "KParts/ReadOnlyPart", constr );
4463 if ( offers.isEmpty() )
4464 return 0L;
4467 KService::List::ConstIterator it = offers.constBegin();
4468 const KService::List::ConstIterator itEnd = offers.constEnd();
4469 for ( ; it != itEnd; ++it )
4471 KService::Ptr service = (*it);
4473 KPluginLoader loader( *service, KHTMLGlobal::componentData() );
4474 KPluginFactory* const factory = loader.factory();
4475 if ( factory ) {
4476 // Turn params into a QVariantList as expected by KPluginFactory
4477 QVariantList variantlist;
4478 Q_FOREACH(const QString& str, params)
4479 variantlist << QVariant(str);
4481 if ( service->serviceTypes().contains( "Browser/View" ) )
4482 variantlist << QString("Browser/View");
4484 KParts::ReadOnlyPart* part = factory->create<KParts::ReadOnlyPart>(parentWidget, parent, QString(), variantlist);
4485 if ( part ) {
4486 serviceTypes = service->serviceTypes();
4487 serviceName = service->name();
4488 return part;
4490 } else {
4491 // TODO KMessageBox::error and i18n, like in KonqFactory::createView?
4492 kWarning() << QString("There was an error loading the module %1.\nThe diagnostics is:\n%2")
4493 .arg(service->name()).arg(loader.errorString());
4496 return 0;
4499 KParts::PartManager *KHTMLPart::partManager()
4501 if ( !d->m_manager && d->m_view )
4503 d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this );
4504 d->m_manager->setObjectName( "khtml part manager" );
4505 d->m_manager->setAllowNestedParts( true );
4506 connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
4507 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
4508 connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ),
4509 this, SLOT( slotPartRemoved( KParts::Part * ) ) );
4512 return d->m_manager;
4515 void KHTMLPart::submitFormAgain()
4517 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
4518 if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
4519 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 );
4521 delete d->m_submitForm;
4522 d->m_submitForm = 0;
4525 void KHTMLPart::submitFormProxy( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
4527 submitForm(action, url, formData, _target, contentType, boundary);
4530 void KHTMLPart::submitForm( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
4532 kDebug(6000) << this << "target=" << _target << "url=" << url;
4533 if (d->m_formNotification == KHTMLPart::Only) {
4534 emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
4535 return;
4536 } else if (d->m_formNotification == KHTMLPart::Before) {
4537 emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
4540 KUrl u = completeURL( url );
4542 if ( !u.isValid() )
4544 // ### ERROR HANDLING!
4545 return;
4548 // Form security checks
4551 * If these form security checks are still in this place in a month or two
4552 * I'm going to simply delete them.
4555 /* This is separate for a reason. It has to be _before_ all script, etc,
4556 * AND I don't want to break anything that uses checkLinkSecurity() in
4557 * other places.
4560 if (!d->m_submitForm) {
4561 if (u.protocol() != "https" && u.protocol() != "mailto") {
4562 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
4563 int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
4564 "\nA third party may be able to intercept and view this information."
4565 "\nAre you sure you wish to continue?"),
4566 i18n("Network Transmission"),KGuiItem(i18n("&Send Unencrypted")));
4567 if (rc == KMessageBox::Cancel)
4568 return;
4569 } else { // Going from nonSSL -> nonSSL
4570 KSSLSettings kss(true);
4571 if (kss.warnOnUnencrypted()) {
4572 int rc = KMessageBox::warningContinueCancel(NULL,
4573 i18n("Warning: Your data is about to be transmitted across the network unencrypted."
4574 "\nAre you sure you wish to continue?"),
4575 i18n("Network Transmission"),
4576 KGuiItem(i18n("&Send Unencrypted")),
4577 KStandardGuiItem::cancel(),
4578 "WarnOnUnencryptedForm");
4579 // Move this setting into KSSL instead
4580 QString grpNotifMsgs = QLatin1String("Notification Messages");
4581 KConfigGroup cg( KGlobal::config(), grpNotifMsgs );
4583 if (!cg.readEntry("WarnOnUnencryptedForm", true)) {
4584 cg.deleteEntry("WarnOnUnencryptedForm");
4585 cg.sync();
4586 kss.setWarnOnUnencrypted(false);
4587 kss.save();
4589 if (rc == KMessageBox::Cancel)
4590 return;
4595 if (u.protocol() == "mailto") {
4596 int rc = KMessageBox::warningContinueCancel(NULL,
4597 i18n("This site is attempting to submit form data via email.\n"
4598 "Do you want to continue?"),
4599 i18n("Network Transmission"),
4600 KGuiItem(i18n("&Send Email")),
4601 KStandardGuiItem::cancel(),
4602 "WarnTriedEmailSubmit");
4604 if (rc == KMessageBox::Cancel) {
4605 return;
4610 // End form security checks
4613 QString urlstring = u.url();
4615 if ( d->isJavaScriptURL(urlstring) ) {
4616 crossFrameExecuteScript( _target, d->codeForJavaScriptURL(urlstring) );
4617 return;
4620 if (!checkLinkSecurity(u,
4621 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>" ),
4622 i18n( "Submit" )))
4623 return;
4625 // OK. We're actually going to submit stuff. Clear any redirections,
4626 // we should win over them
4627 d->clearRedirection();
4629 KParts::OpenUrlArguments args;
4631 if (!d->m_referrer.isEmpty())
4632 args.metaData()["referrer"] = d->m_referrer;
4634 args.metaData().insert("PropagateHttpHeader", "true");
4635 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
4636 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
4637 args.metaData().insert("main_frame_request",
4638 parentPart() == 0 ? "TRUE":"FALSE");
4639 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
4640 args.metaData().insert("ssl_activate_warnings", "TRUE");
4641 //WABA: When we post a form we should treat it as the main url
4642 //the request should never be considered cross-domain
4643 //args.metaData().insert("cross-domain", toplevelURL().url());
4644 KParts::BrowserArguments browserArgs;
4645 browserArgs.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
4647 // Handle mailto: forms
4648 if (u.protocol() == "mailto") {
4649 // 1) Check for attach= and strip it
4650 QString q = u.query().mid(1);
4651 QStringList nvps = q.split("&");
4652 bool triedToAttach = false;
4654 QStringList::Iterator nvp = nvps.begin();
4655 const QStringList::Iterator nvpEnd = nvps.end();
4657 // cannot be a for loop as if something is removed we don't want to do ++nvp, as
4658 // remove returns an iterator pointing to the next item
4660 while (nvp != nvpEnd) {
4661 const QStringList pair = (*nvp).split("=");
4662 if (pair.count() >= 2) {
4663 if (pair.first().toLower() == "attach") {
4664 nvp = nvps.erase(nvp);
4665 triedToAttach = true;
4666 } else {
4667 ++nvp;
4669 } else {
4670 ++nvp;
4674 if (triedToAttach)
4675 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");
4677 // 2) Append body=
4678 QString bodyEnc;
4679 if (contentType.toLower() == "multipart/form-data") {
4680 // FIXME: is this correct? I suspect not
4681 bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(),
4682 formData.size())));
4683 } else if (contentType.toLower() == "text/plain") {
4684 // Convention seems to be to decode, and s/&/\n/
4685 QString tmpbody = QString::fromLatin1(formData.data(),
4686 formData.size());
4687 tmpbody.replace(QRegExp("[&]"), "\n");
4688 tmpbody.replace(QRegExp("[+]"), " ");
4689 tmpbody = KUrl::fromPercentEncoding(tmpbody.toLatin1()); // Decode the rest of it
4690 bodyEnc = QLatin1String( KUrl::toPercentEncoding(tmpbody) ); // Recode for the URL
4691 } else {
4692 bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(),
4693 formData.size())) );
4696 nvps.append(QString("body=%1").arg(bodyEnc));
4697 q = nvps.join("&");
4698 u.setQuery(q);
4701 if ( strcmp( action, "get" ) == 0 ) {
4702 if (u.protocol() != "mailto")
4703 u.setQuery( QString::fromLatin1( formData.data(), formData.size() ) );
4704 browserArgs.setDoPost( false );
4706 else {
4707 browserArgs.postData = formData;
4708 browserArgs.setDoPost( true );
4710 // construct some user headers if necessary
4711 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
4712 browserArgs.setContentType( "Content-Type: application/x-www-form-urlencoded" );
4713 else // contentType must be "multipart/form-data"
4714 browserArgs.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
4717 if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
4718 if( d->m_submitForm ) {
4719 kDebug(6000) << "ABORTING!";
4720 return;
4722 d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
4723 d->m_submitForm->submitAction = action;
4724 d->m_submitForm->submitUrl = url;
4725 d->m_submitForm->submitFormData = formData;
4726 d->m_submitForm->target = _target;
4727 d->m_submitForm->submitContentType = contentType;
4728 d->m_submitForm->submitBoundary = boundary;
4729 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
4731 else
4733 emit d->m_extension->openUrlRequest( u, args, browserArgs );
4737 void KHTMLPart::popupMenu( const QString &linkUrl )
4739 KUrl popupURL;
4740 KUrl linkKUrl;
4741 KParts::OpenUrlArguments args;
4742 KParts::BrowserArguments browserArgs;
4743 QString referrer;
4744 KParts::BrowserExtension::PopupFlags itemflags=KParts::BrowserExtension::ShowBookmark | KParts::BrowserExtension::ShowReload;
4746 if ( linkUrl.isEmpty() ) { // click on background
4747 KHTMLPart* khtmlPart = this;
4748 while ( khtmlPart->parentPart() )
4750 khtmlPart=khtmlPart->parentPart();
4752 popupURL = khtmlPart->url();
4753 referrer = khtmlPart->pageReferrer();
4754 if (hasSelection())
4755 itemflags = KParts::BrowserExtension::ShowTextSelectionItems;
4756 else
4757 itemflags |= KParts::BrowserExtension::ShowNavigationItems;
4758 } else { // click on link
4759 popupURL = completeURL( linkUrl );
4760 linkKUrl = popupURL;
4761 referrer = this->referrer();
4762 itemflags |= KParts::BrowserExtension::IsLink;
4764 if (!(d->m_strSelectedURLTarget).isEmpty() &&
4765 (d->m_strSelectedURLTarget.toLower() != "_top") &&
4766 (d->m_strSelectedURLTarget.toLower() != "_self") &&
4767 (d->m_strSelectedURLTarget.toLower() != "_parent")) {
4768 if (d->m_strSelectedURLTarget.toLower() == "_blank")
4769 browserArgs.setForcesNewWindow(true);
4770 else {
4771 KHTMLPart *p = this;
4772 while (p->parentPart())
4773 p = p->parentPart();
4774 if (!p->frameExists(d->m_strSelectedURLTarget))
4775 browserArgs.setForcesNewWindow(true);
4780 // Danger, Will Robinson. The Popup might stay around for a much
4781 // longer time than KHTMLPart. Deal with it.
4782 KHTMLPopupGUIClient* client = new KHTMLPopupGUIClient( this, linkKUrl );
4783 QPointer<QObject> guard( client );
4785 QString mimetype = QLatin1String( "text/html" );
4786 args.metaData()["referrer"] = referrer;
4788 if (!linkUrl.isEmpty()) // over a link
4790 if (popupURL.isLocalFile()) // safe to do this
4792 mimetype = KMimeType::findByUrl(popupURL,0,true,false)->name();
4794 else // look at "extension" of link
4796 const QString fname(popupURL.fileName(KUrl::ObeyTrailingSlash));
4797 if (!fname.isEmpty() && !popupURL.hasRef() && popupURL.query().isEmpty())
4799 KMimeType::Ptr pmt = KMimeType::findByPath(fname,0,true);
4801 // Further check for mime types guessed from the extension which,
4802 // on a web page, are more likely to be a script delivering content
4803 // of undecidable type. If the mime type from the extension is one
4804 // of these, don't use it. Retain the original type 'text/html'.
4805 if (pmt->name() != KMimeType::defaultMimeType() &&
4806 !pmt->is("application/x-perl") &&
4807 !pmt->is("application/x-perl-module") &&
4808 !pmt->is("application/x-php") &&
4809 !pmt->is("application/x-python-bytecode") &&
4810 !pmt->is("application/x-python") &&
4811 !pmt->is("application/x-shellscript"))
4812 mimetype = pmt->name();
4817 args.setMimeType(mimetype);
4819 emit d->m_extension->popupMenu( QCursor::pos(), popupURL, S_IFREG /*always a file*/,
4820 args, browserArgs, itemflags,
4821 client->actionGroups() );
4823 if ( !guard.isNull() ) {
4824 delete client;
4825 emit popupMenu(linkUrl, QCursor::pos());
4826 d->m_strSelectedURL.clear();
4827 d->m_strSelectedURLTarget.clear();
4831 void KHTMLPart::slotParentCompleted()
4833 //kDebug(6050) << this;
4834 if ( !d->m_redirectURL.isEmpty() && !d->m_redirectionTimer.isActive() )
4836 //kDebug(6050) << this << ": starting timer for child redirection -> " << d->m_redirectURL;
4837 d->m_redirectionTimer.setSingleShot( true );
4838 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
4842 void KHTMLPart::slotChildStarted( KIO::Job *job )
4844 khtml::ChildFrame *child = frame( sender() );
4846 assert( child );
4848 child->m_bCompleted = false;
4850 if ( d->m_bComplete )
4852 #if 0
4853 // WABA: Looks like this belongs somewhere else
4854 if ( !parentPart() ) // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes
4856 emit d->m_extension->openURLNotify();
4858 #endif
4859 d->m_bComplete = false;
4860 emit started( job );
4864 void KHTMLPart::slotChildCompleted()
4866 slotChildCompleted( false );
4869 void KHTMLPart::slotChildCompleted( bool pendingAction )
4871 khtml::ChildFrame *child = frame( sender() );
4873 if ( child ) {
4874 kDebug(6050) << this << "child=" << child << "m_partContainerElement=" << child->m_partContainerElement;
4875 child->m_bCompleted = true;
4876 child->m_bPendingRedirection = pendingAction;
4877 child->m_args = KParts::OpenUrlArguments();
4878 child->m_browserArgs = KParts::BrowserArguments();
4879 // dispatch load event
4880 if (!qobject_cast<KHTMLPart*>(child->m_part))
4881 QTimer::singleShot(0, child->m_partContainerElement, SLOT(slotEmitLoadEvent()));
4883 checkCompleted();
4886 void KHTMLPart::slotChildDocCreated()
4888 // Set domain to the frameset's domain
4889 // This must only be done when loading the frameset initially (#22039),
4890 // not when following a link in a frame (#44162).
4891 if (KHTMLPart* htmlFrame = qobject_cast<KHTMLPart*>(sender()))
4892 d->propagateInitialDomainTo( htmlFrame );
4894 // So it only happens once
4895 disconnect( sender(), SIGNAL( docCreated() ), this, SLOT( slotChildDocCreated() ) );
4898 void KHTMLPartPrivate::propagateInitialDomainTo(KHTMLPart* kid)
4900 // This method is used to propagate our domain information for
4901 // child frames, potentially widening to have less periods, and also
4902 // to provide a domain for about: or JavaScript: URLs altogether.
4903 // Note that DocumentImpl:;setDomain does the checking.
4904 if ( m_doc && kid->d->m_doc )
4905 kid->d->m_doc->setDomain( m_doc->domain() );
4908 void KHTMLPart::slotChildURLRequest( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs )
4910 khtml::ChildFrame *child = frame( sender()->parent() );
4911 KHTMLPart *callingHtmlPart = const_cast<KHTMLPart *>(dynamic_cast<const KHTMLPart *>(sender()->parent()));
4913 // TODO: handle child target correctly! currently the script are always executed for the parent
4914 QString urlStr = url.url();
4915 if ( d->isJavaScriptURL(urlStr) ) {
4916 executeScript( DOM::Node(), d->codeForJavaScriptURL(urlStr) );
4917 return;
4920 QString frameName = browserArgs.frameName.toLower();
4921 if ( !frameName.isEmpty() ) {
4922 if ( frameName == QLatin1String( "_top" ) )
4924 emit d->m_extension->openUrlRequest( url, args, browserArgs );
4925 return;
4927 else if ( frameName == QLatin1String( "_blank" ) )
4929 emit d->m_extension->createNewWindow( url, args, browserArgs );
4930 return;
4932 else if ( frameName == QLatin1String( "_parent" ) )
4934 KParts::BrowserArguments newBrowserArgs( browserArgs );
4935 newBrowserArgs.frameName.clear();
4936 emit d->m_extension->openUrlRequest( url, args, newBrowserArgs );
4937 return;
4939 else if ( frameName != QLatin1String( "_self" ) )
4941 khtml::ChildFrame *_frame = recursiveFrameRequest( callingHtmlPart, url, args, browserArgs );
4943 if ( !_frame )
4945 emit d->m_extension->openUrlRequest( url, args, browserArgs );
4946 return;
4949 child = _frame;
4953 if ( child && child->m_type != khtml::ChildFrame::Object ) {
4954 // Inform someone that we are about to show something else.
4955 child->m_bNotify = true;
4956 requestObject( child, url, args, browserArgs );
4957 } else if ( frameName== "_self" ) // this is for embedded objects (via <object>) which want to replace the current document
4959 KParts::BrowserArguments newBrowserArgs( browserArgs );
4960 newBrowserArgs.frameName.clear();
4961 emit d->m_extension->openUrlRequest( url, args, newBrowserArgs );
4965 void KHTMLPart::slotRequestFocus( KParts::ReadOnlyPart * )
4967 emit d->m_extension->requestFocus(this);
4970 khtml::ChildFrame *KHTMLPart::frame( const QObject *obj )
4972 assert( obj->inherits( "KParts::ReadOnlyPart" ) );
4973 const KParts::ReadOnlyPart* const part = static_cast<const KParts::ReadOnlyPart *>( obj );
4975 FrameIt it = d->m_frames.begin();
4976 const FrameIt end = d->m_frames.end();
4977 for (; it != end; ++it )
4978 if ( (KParts::ReadOnlyPart *)(*it)->m_part == part )
4979 return *it;
4981 FrameIt oi = d->m_objects.begin();
4982 const FrameIt oiEnd = d->m_objects.end();
4983 for (; oi != oiEnd; ++oi )
4984 if ( (KParts::ReadOnlyPart *)(*oi)->m_part == part )
4985 return *oi;
4987 return 0L;
4990 //#define DEBUG_FINDFRAME
4992 bool KHTMLPart::checkFrameAccess(KHTMLPart *callingHtmlPart)
4994 if (callingHtmlPart == this)
4995 return true; // trivial
4997 if (!xmlDocImpl()) {
4998 #ifdef DEBUG_FINDFRAME
4999 kDebug(6050) << "Empty part" << this << "URL = " << url();
5000 #endif
5001 return false; // we are empty?
5004 // now compare the domains
5005 if (callingHtmlPart && callingHtmlPart->xmlDocImpl() && xmlDocImpl()) {
5006 DOM::DOMString actDomain = callingHtmlPart->xmlDocImpl()->domain();
5007 DOM::DOMString destDomain = xmlDocImpl()->domain();
5009 #ifdef DEBUG_FINDFRAME
5010 kDebug(6050) << "actDomain =" << actDomain.string() << "destDomain =" << destDomain.string();
5011 #endif
5013 if (actDomain == destDomain)
5014 return true;
5016 #ifdef DEBUG_FINDFRAME
5017 else
5019 kDebug(6050) << "Unknown part/domain" << callingHtmlPart << "tries to access part" << this;
5021 #endif
5022 return false;
5025 KHTMLPart *
5026 KHTMLPart::findFrameParent( KParts::ReadOnlyPart *callingPart, const QString &f, khtml::ChildFrame **childFrame )
5028 #ifdef DEBUG_FINDFRAME
5029 kDebug(6050) << this << "URL =" << url() << "name =" << name() << "findFrameParent(" << f << ")";
5030 #endif
5031 // Check access
5032 KHTMLPart* const callingHtmlPart = dynamic_cast<KHTMLPart *>(callingPart);
5034 if (!checkFrameAccess(callingHtmlPart))
5035 return 0;
5037 if (!childFrame && !parentPart() && (objectName() == f))
5038 return this;
5040 FrameIt it = d->m_frames.find( f );
5041 const FrameIt end = d->m_frames.end();
5042 if ( it != end )
5044 #ifdef DEBUG_FINDFRAME
5045 kDebug(6050) << "FOUND!";
5046 #endif
5047 if (childFrame)
5048 *childFrame = *it;
5049 return this;
5052 it = d->m_frames.begin();
5053 for (; it != end; ++it )
5055 KParts::ReadOnlyPart* const p = (*it)->m_part;
5056 if ( p && p->inherits( "KHTMLPart" ))
5058 KHTMLPart* const frameParent = static_cast<KHTMLPart*>(p)->findFrameParent(callingPart, f, childFrame);
5059 if (frameParent)
5060 return frameParent;
5063 return 0;
5067 KHTMLPart *KHTMLPart::findFrame( const QString &f )
5069 khtml::ChildFrame *childFrame;
5070 KHTMLPart *parentFrame = findFrameParent(this, f, &childFrame);
5071 if (parentFrame)
5073 KParts::ReadOnlyPart *p = childFrame->m_part;
5074 if ( p && p->inherits( "KHTMLPart" ))
5075 return static_cast<KHTMLPart *>(p);
5077 return 0;
5080 KParts::ReadOnlyPart *KHTMLPart::findFramePart(const QString &f)
5082 khtml::ChildFrame *childFrame;
5083 return findFrameParent(this, f, &childFrame) ? static_cast<KParts::ReadOnlyPart *>(childFrame->m_part) : 0L;
5086 KParts::ReadOnlyPart *KHTMLPart::currentFrame() const
5088 KParts::ReadOnlyPart* part = (KParts::ReadOnlyPart*)(this);
5089 // Find active part in our frame manager, in case we are a frameset
5090 // and keep doing that (in case of nested framesets).
5091 // Just realized we could also do this recursively, calling part->currentFrame()...
5092 while ( part && part->inherits("KHTMLPart") &&
5093 static_cast<KHTMLPart *>(part)->d->m_frames.count() > 0 ) {
5094 KHTMLPart* frameset = static_cast<KHTMLPart *>(part);
5095 part = static_cast<KParts::ReadOnlyPart *>(frameset->partManager()->activePart());
5096 if ( !part ) return frameset;
5098 return part;
5101 bool KHTMLPart::frameExists( const QString &frameName )
5103 FrameIt it = d->m_frames.find( frameName );
5104 if ( it == d->m_frames.end() )
5105 return false;
5107 // WABA: We only return true if the child actually has a frame
5108 // set. Otherwise we might find our preloaded-selve.
5109 // This happens when we restore the frameset.
5110 return (!(*it)->m_partContainerElement.isNull());
5113 KJSProxy *KHTMLPart::framejScript(KParts::ReadOnlyPart *framePart)
5115 KHTMLPart* const kp = qobject_cast<KHTMLPart*>(framePart);
5116 if (kp)
5117 return kp->jScript();
5119 FrameIt it = d->m_frames.begin();
5120 const FrameIt itEnd = d->m_frames.end();
5122 for (; it != itEnd; ++it)
5123 if (framePart == (*it)->m_part) {
5124 if (!(*it)->m_jscript)
5125 createJScript(*it);
5126 return (*it)->m_jscript;
5128 return 0L;
5131 KHTMLPart *KHTMLPart::parentPart()
5133 return qobject_cast<KHTMLPart*>( parent() );
5136 khtml::ChildFrame *KHTMLPart::recursiveFrameRequest( KHTMLPart *callingHtmlPart, const KUrl &url,
5137 const KParts::OpenUrlArguments &args,
5138 const KParts::BrowserArguments &browserArgs, bool callParent )
5140 #ifdef DEBUG_FINDFRAME
5141 kDebug( 6050 ) << this << "frame = " << args.frameName << "url = " << url;
5142 #endif
5143 khtml::ChildFrame *childFrame;
5144 KHTMLPart *childPart = findFrameParent(callingHtmlPart, browserArgs.frameName, &childFrame);
5145 if (childPart)
5147 if (childPart == this)
5148 return childFrame;
5150 childPart->requestObject( childFrame, url, args, browserArgs );
5151 return 0;
5154 if ( parentPart() && callParent )
5156 khtml::ChildFrame *res = parentPart()->recursiveFrameRequest( callingHtmlPart, url, args, browserArgs, callParent );
5158 if ( res )
5159 parentPart()->requestObject( res, url, args, browserArgs );
5162 return 0L;
5165 #ifdef DEBUG_SAVESTATE
5166 static int s_saveStateIndentLevel = 0;
5167 #endif
5169 void KHTMLPart::saveState( QDataStream &stream )
5171 #ifdef DEBUG_SAVESTATE
5172 QString indent= QString().leftJustified( s_saveStateIndentLevel * 4, ' ' );
5173 const int indentLevel = s_saveStateIndentLevel++;
5174 kDebug( 6050 ) << indent << "saveState this=" << this << " '" << objectName() << "' saving URL " << url().url();
5175 #endif
5177 stream << url() << (qint32)d->m_view->contentsX() << (qint32)d->m_view->contentsY()
5178 << (qint32) d->m_view->contentsWidth() << (qint32) d->m_view->contentsHeight() << (qint32) d->m_view->marginWidth() << (qint32) d->m_view->marginHeight();
5180 // save link cursor position
5181 int focusNodeNumber;
5182 if (!d->m_focusNodeRestored)
5183 focusNodeNumber = d->m_focusNodeNumber;
5184 else if (d->m_doc && d->m_doc->focusNode())
5185 focusNodeNumber = d->m_doc->nodeAbsIndex(d->m_doc->focusNode());
5186 else
5187 focusNodeNumber = -1;
5188 stream << focusNodeNumber;
5190 // Save the doc's cache id.
5191 stream << d->m_cacheId;
5193 // Save the state of the document (Most notably the state of any forms)
5194 QStringList docState;
5195 if (d->m_doc)
5197 docState = d->m_doc->docState();
5199 stream << d->m_encoding << d->m_sheetUsed << docState;
5201 stream << d->m_zoomFactor;
5202 stream << d->m_fontScaleFactor;
5204 stream << d->m_httpHeaders;
5205 stream << d->m_pageServices;
5206 stream << d->m_pageReferrer;
5208 // Save ssl data
5209 stream << d->m_ssl_in_use
5210 << d->m_ssl_peer_chain
5211 << d->m_ssl_peer_ip
5212 << d->m_ssl_cipher
5213 << d->m_ssl_protocol_version
5214 << d->m_ssl_cipher_used_bits
5215 << d->m_ssl_cipher_bits
5216 << d->m_ssl_cert_errors
5217 << d->m_ssl_parent_ip
5218 << d->m_ssl_parent_cert;
5221 QStringList frameNameLst, frameServiceTypeLst, frameServiceNameLst;
5222 KUrl::List frameURLLst;
5223 QList<QByteArray> frameStateBufferLst;
5224 QList<int> frameTypeLst;
5226 ConstFrameIt it = d->m_frames.constBegin();
5227 const ConstFrameIt end = d->m_frames.constEnd();
5228 for (; it != end; ++it )
5230 if ( !(*it)->m_part )
5231 continue;
5233 frameNameLst << (*it)->m_name;
5234 frameServiceTypeLst << (*it)->m_serviceType;
5235 frameServiceNameLst << (*it)->m_serviceName;
5236 frameURLLst << (*it)->m_part->url();
5238 QByteArray state;
5239 QDataStream frameStream( &state, QIODevice::WriteOnly );
5241 if ( (*it)->m_extension )
5242 (*it)->m_extension->saveState( frameStream );
5244 frameStateBufferLst << state;
5246 frameTypeLst << int( (*it)->m_type );
5249 // Save frame data
5250 stream << (quint32) frameNameLst.count();
5251 stream << frameNameLst << frameServiceTypeLst << frameServiceNameLst << frameURLLst << frameStateBufferLst << frameTypeLst;
5252 #ifdef DEBUG_SAVESTATE
5253 s_saveStateIndentLevel = indentLevel;
5254 #endif
5257 void KHTMLPart::restoreState( QDataStream &stream )
5259 KUrl u;
5260 qint32 xOffset, yOffset, wContents, hContents, mWidth, mHeight;
5261 quint32 frameCount;
5262 QStringList frameNames, frameServiceTypes, docState, frameServiceNames;
5263 QList<int> frameTypes;
5264 KUrl::List frameURLs;
5265 QList<QByteArray> frameStateBuffers;
5266 QList<int> fSizes;
5267 QString encoding, sheetUsed;
5268 long old_cacheId = d->m_cacheId;
5270 stream >> u >> xOffset >> yOffset >> wContents >> hContents >> mWidth >> mHeight;
5272 d->m_view->setMarginWidth( mWidth );
5273 d->m_view->setMarginHeight( mHeight );
5275 // restore link cursor position
5276 // nth node is active. value is set in checkCompleted()
5277 stream >> d->m_focusNodeNumber;
5278 d->m_focusNodeRestored = false;
5280 stream >> d->m_cacheId;
5282 stream >> encoding >> sheetUsed >> docState;
5284 d->m_encoding = encoding;
5285 d->m_sheetUsed = sheetUsed;
5287 int zoomFactor;
5288 stream >> zoomFactor;
5289 setZoomFactor(zoomFactor);
5291 int fontScaleFactor;
5292 stream >> fontScaleFactor;
5293 setFontScaleFactor(fontScaleFactor);
5295 stream >> d->m_httpHeaders;
5296 stream >> d->m_pageServices;
5297 stream >> d->m_pageReferrer;
5299 // Restore ssl data
5300 stream >> d->m_ssl_in_use
5301 >> d->m_ssl_peer_chain
5302 >> d->m_ssl_peer_ip
5303 >> d->m_ssl_cipher
5304 >> d->m_ssl_protocol_version
5305 >> d->m_ssl_cipher_used_bits
5306 >> d->m_ssl_cipher_bits
5307 >> d->m_ssl_cert_errors
5308 >> d->m_ssl_parent_ip
5309 >> d->m_ssl_parent_cert;
5311 setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
5313 stream >> frameCount >> frameNames >> frameServiceTypes >> frameServiceNames
5314 >> frameURLs >> frameStateBuffers >> frameTypes;
5316 d->m_bComplete = false;
5317 d->m_bLoadEventEmitted = false;
5319 // kDebug( 6050 ) << "docState.count() = " << docState.count();
5320 // kDebug( 6050 ) << "m_url " << url().url() << " <-> " << u.url();
5321 // kDebug( 6050 ) << "m_frames.count() " << d->m_frames.count() << " <-> " << frameCount;
5323 if (d->m_cacheId == old_cacheId)
5325 // Partial restore
5326 d->m_redirectionTimer.stop();
5328 FrameIt fIt = d->m_frames.begin();
5329 const FrameIt fEnd = d->m_frames.end();
5331 for (; fIt != fEnd; ++fIt )
5332 (*fIt)->m_bCompleted = false;
5334 fIt = d->m_frames.begin();
5336 QStringList::ConstIterator fNameIt = frameNames.constBegin();
5337 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin();
5338 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin();
5339 KUrl::List::ConstIterator fURLIt = frameURLs.constBegin();
5340 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin();
5341 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin();
5343 for (; fIt != fEnd; ++fIt, ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt )
5345 khtml::ChildFrame* const child = *fIt;
5347 // kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt;
5349 if ( child->m_name != *fNameIt || child->m_serviceType != *fServiceTypeIt )
5351 child->m_bPreloaded = true;
5352 child->m_name = *fNameIt;
5353 child->m_serviceName = *fServiceNameIt;
5354 child->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt);
5355 processObjectRequest( child, *fURLIt, *fServiceTypeIt );
5357 if ( child->m_part )
5359 child->m_bCompleted = false;
5360 if ( child->m_extension && !(*fBufferIt).isEmpty() )
5362 QDataStream frameStream( *fBufferIt );
5363 child->m_extension->restoreState( frameStream );
5365 else
5366 child->m_part->openUrl( *fURLIt );
5370 KParts::OpenUrlArguments args( arguments() );
5371 args.setXOffset(xOffset);
5372 args.setYOffset(yOffset);
5373 setArguments(args);
5375 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
5376 browserArgs.docState = docState;
5377 d->m_extension->setBrowserArguments(browserArgs);
5379 d->m_view->resizeContents( wContents, hContents );
5380 d->m_view->setContentsPos( xOffset, yOffset );
5382 setUrl(u);
5384 else
5386 // Full restore.
5387 closeUrl();
5388 // We must force a clear because we want to be sure to delete all
5389 // frames.
5390 d->m_bCleared = false;
5391 clear();
5392 d->m_encoding = encoding;
5393 d->m_sheetUsed = sheetUsed;
5395 QStringList::ConstIterator fNameIt = frameNames.constBegin();
5396 const QStringList::ConstIterator fNameEnd = frameNames.constEnd();
5398 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin();
5399 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin();
5400 KUrl::List::ConstIterator fURLIt = frameURLs.constBegin();
5401 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin();
5402 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin();
5404 for (; fNameIt != fNameEnd; ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt )
5406 khtml::ChildFrame* const newChild = new khtml::ChildFrame;
5407 newChild->m_bPreloaded = true;
5408 newChild->m_name = *fNameIt;
5409 newChild->m_serviceName = *fServiceNameIt;
5410 newChild->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt);
5412 // kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt;
5414 const FrameIt childFrame = d->m_frames.insert( d->m_frames.end(), newChild );
5416 processObjectRequest( *childFrame, *fURLIt, *fServiceTypeIt );
5418 (*childFrame)->m_bPreloaded = true;
5420 if ( (*childFrame)->m_part )
5422 if ( (*childFrame)->m_extension && !(*fBufferIt).isEmpty() )
5424 QDataStream frameStream( *fBufferIt );
5425 (*childFrame)->m_extension->restoreState( frameStream );
5427 else
5428 (*childFrame)->m_part->openUrl( *fURLIt );
5432 KParts::OpenUrlArguments args( arguments() );
5433 args.setXOffset(xOffset);
5434 args.setYOffset(yOffset);
5435 setArguments(args);
5437 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
5438 browserArgs.docState = docState;
5439 d->m_extension->setBrowserArguments(browserArgs);
5441 if (!KHTMLPageCache::self()->isComplete(d->m_cacheId))
5443 d->m_restored = true;
5444 openUrl( u );
5445 d->m_restored = false;
5447 else
5449 restoreURL( u );
5455 void KHTMLPart::show()
5457 if ( d->m_view )
5458 d->m_view->show();
5461 void KHTMLPart::hide()
5463 if ( d->m_view )
5464 d->m_view->hide();
5467 DOM::Node KHTMLPart::nodeUnderMouse() const
5469 return d->m_view->nodeUnderMouse();
5472 DOM::Node KHTMLPart::nonSharedNodeUnderMouse() const
5474 return d->m_view->nonSharedNodeUnderMouse();
5477 void KHTMLPart::emitSelectionChanged()
5479 emit d->m_extension->enableAction( "copy", hasSelection() );
5481 emit d->m_extension->selectionInfo( selectedText() );
5482 emit selectionChanged();
5485 int KHTMLPart::zoomFactor() const
5487 return d->m_zoomFactor;
5490 // ### make the list configurable ?
5491 static const int zoomSizes[] = { 20, 40, 60, 80, 90, 95, 100, 105, 110, 120, 140, 160, 180, 200, 250, 300 };
5492 static const int zoomSizeCount = (sizeof(zoomSizes) / sizeof(int));
5493 static const int minZoom = 20;
5494 static const int maxZoom = 300;
5496 // My idea of useful stepping ;-) (LS)
5497 extern const int KDE_NO_EXPORT fastZoomSizes[] = { 20, 50, 75, 90, 100, 120, 150, 200, 300 };
5498 extern const int KDE_NO_EXPORT fastZoomSizeCount = sizeof fastZoomSizes / sizeof fastZoomSizes[0];
5500 void KHTMLPart::slotIncZoom()
5502 zoomIn(zoomSizes, zoomSizeCount);
5505 void KHTMLPart::slotDecZoom()
5507 zoomOut(zoomSizes, zoomSizeCount);
5510 void KHTMLPart::slotIncZoomFast()
5512 zoomIn(fastZoomSizes, fastZoomSizeCount);
5515 void KHTMLPart::slotDecZoomFast()
5517 zoomOut(fastZoomSizes, fastZoomSizeCount);
5520 void KHTMLPart::zoomIn(const int stepping[], int count)
5522 int zoomFactor = d->m_zoomFactor;
5524 if (zoomFactor < maxZoom) {
5525 // find the entry nearest to the given zoomsizes
5526 for (int i = 0; i < count; ++i)
5527 if (stepping[i] > zoomFactor) {
5528 zoomFactor = stepping[i];
5529 break;
5531 setZoomFactor(zoomFactor);
5535 void KHTMLPart::zoomOut(const int stepping[], int count)
5537 int zoomFactor = d->m_zoomFactor;
5538 if (zoomFactor > minZoom) {
5539 // find the entry nearest to the given zoomsizes
5540 for (int i = count-1; i >= 0; --i)
5541 if (stepping[i] < zoomFactor) {
5542 zoomFactor = stepping[i];
5543 break;
5545 setZoomFactor(zoomFactor);
5549 void KHTMLPart::setZoomFactor (int percent)
5551 // ### zooming under 100% is majorly botched,
5552 // so disable that for now.
5553 if (percent < 100) percent = 100;
5554 // ### if (percent < minZoom) percent = minZoom;
5556 if (percent > maxZoom) percent = maxZoom;
5557 if (d->m_zoomFactor == percent) return;
5558 d->m_zoomFactor = percent;
5560 if(d->m_view) {
5561 QApplication::setOverrideCursor( Qt::WaitCursor );
5562 d->m_view->setZoomLevel( d->m_zoomFactor );
5563 QApplication::restoreOverrideCursor();
5566 ConstFrameIt it = d->m_frames.constBegin();
5567 const ConstFrameIt end = d->m_frames.constEnd();
5568 for (; it != end; ++it )
5569 if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
5570 KParts::ReadOnlyPart* const p = ( *it )->m_part;
5571 static_cast<KHTMLPart*>( p )->setZoomFactor(d->m_zoomFactor);
5574 if ( d->m_guiProfile == BrowserViewGUI ) {
5575 d->m_paDecZoomFactor->setEnabled( d->m_zoomFactor > minZoom );
5576 d->m_paIncZoomFactor->setEnabled( d->m_zoomFactor < maxZoom );
5579 void KHTMLPart::slotIncFontSize()
5581 incFontSize(zoomSizes, zoomSizeCount);
5584 void KHTMLPart::slotDecFontSize()
5586 decFontSize(zoomSizes, zoomSizeCount);
5589 void KHTMLPart::slotIncFontSizeFast()
5591 incFontSize(fastZoomSizes, fastZoomSizeCount);
5594 void KHTMLPart::slotDecFontSizeFast()
5596 decFontSize(fastZoomSizes, fastZoomSizeCount);
5599 void KHTMLPart::incFontSize(const int stepping[], int count)
5601 int zoomFactor = d->m_fontScaleFactor;
5603 if (zoomFactor < maxZoom) {
5604 // find the entry nearest to the given zoomsizes
5605 for (int i = 0; i < count; ++i)
5606 if (stepping[i] > zoomFactor) {
5607 zoomFactor = stepping[i];
5608 break;
5610 setFontScaleFactor(zoomFactor);
5614 void KHTMLPart::decFontSize(const int stepping[], int count)
5616 int zoomFactor = d->m_fontScaleFactor;
5617 if (zoomFactor > minZoom) {
5618 // find the entry nearest to the given zoomsizes
5619 for (int i = count-1; i >= 0; --i)
5620 if (stepping[i] < zoomFactor) {
5621 zoomFactor = stepping[i];
5622 break;
5624 setFontScaleFactor(zoomFactor);
5628 void KHTMLPart::setFontScaleFactor(int percent)
5630 if (percent < minZoom) percent = minZoom;
5631 if (percent > maxZoom) percent = maxZoom;
5632 if (d->m_fontScaleFactor == percent) return;
5633 d->m_fontScaleFactor = percent;
5635 if (d->m_view && d->m_doc) {
5636 QApplication::setOverrideCursor( Qt::WaitCursor );
5637 if (d->m_doc->styleSelector())
5638 d->m_doc->styleSelector()->computeFontSizes(d->m_doc->logicalDpiY(), d->m_fontScaleFactor);
5639 d->m_doc->recalcStyle( NodeImpl::Force );
5640 QApplication::restoreOverrideCursor();
5643 ConstFrameIt it = d->m_frames.constBegin();
5644 const ConstFrameIt end = d->m_frames.constEnd();
5645 for (; it != end; ++it )
5646 if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
5647 KParts::ReadOnlyPart* const p = ( *it )->m_part;
5648 static_cast<KHTMLPart*>( p )->setFontScaleFactor(d->m_fontScaleFactor);
5652 int KHTMLPart::fontScaleFactor() const
5654 return d->m_fontScaleFactor;
5657 void KHTMLPart::slotZoomView( int delta )
5659 if ( delta < 0 )
5660 slotIncZoom();
5661 else
5662 slotDecZoom();
5665 void KHTMLPart::setStatusBarText( const QString& text, StatusBarPriority p)
5667 if (!d->m_statusMessagesEnabled)
5668 return;
5670 d->m_statusBarText[p] = text;
5672 // shift handling ?
5673 QString tobe = d->m_statusBarText[BarHoverText];
5674 if (tobe.isEmpty())
5675 tobe = d->m_statusBarText[BarOverrideText];
5676 if (tobe.isEmpty()) {
5677 tobe = d->m_statusBarText[BarDefaultText];
5678 if (!tobe.isEmpty() && d->m_jobspeed)
5679 tobe += " ";
5680 if (d->m_jobspeed)
5681 tobe += i18n( "(%1/s)" , KIO::convertSize( d->m_jobspeed ) );
5683 tobe = "<qt>"+tobe;
5685 emit ReadOnlyPart::setStatusBarText(tobe);
5689 void KHTMLPart::setJSStatusBarText( const QString &text )
5691 setStatusBarText(text, BarOverrideText);
5694 void KHTMLPart::setJSDefaultStatusBarText( const QString &text )
5696 setStatusBarText(text, BarDefaultText);
5699 QString KHTMLPart::jsStatusBarText() const
5701 return d->m_statusBarText[BarOverrideText];
5704 QString KHTMLPart::jsDefaultStatusBarText() const
5706 return d->m_statusBarText[BarDefaultText];
5709 QString KHTMLPart::referrer() const
5711 return d->m_referrer;
5714 QString KHTMLPart::pageReferrer() const
5716 KUrl referrerURL = KUrl( d->m_pageReferrer );
5717 if (referrerURL.isValid())
5719 QString protocol = referrerURL.protocol();
5721 if ((protocol == "http") ||
5722 ((protocol == "https") && (url().protocol() == "https")))
5724 referrerURL.setRef(QString());
5725 referrerURL.setUser(QString());
5726 referrerURL.setPass(QString());
5727 return referrerURL.url();
5731 return QString();
5735 QString KHTMLPart::lastModified() const
5737 if ( d->m_lastModified.isEmpty() && url().isLocalFile() ) {
5738 // Local file: set last-modified from the file's mtime.
5739 // Done on demand to save time when this isn't needed - but can lead
5740 // to slightly wrong results if updating the file on disk w/o reloading.
5741 QDateTime lastModif = QFileInfo( url().path() ).lastModified();
5742 d->m_lastModified = lastModif.toString( Qt::LocalDate );
5744 //kDebug(6050) << d->m_lastModified;
5745 return d->m_lastModified;
5748 void KHTMLPart::slotLoadImages()
5750 if (d->m_doc )
5751 d->m_doc->docLoader()->setAutoloadImages( !d->m_doc->docLoader()->autoloadImages() );
5753 ConstFrameIt it = d->m_frames.constBegin();
5754 const ConstFrameIt end = d->m_frames.constEnd();
5755 for (; it != end; ++it )
5756 if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
5757 KParts::ReadOnlyPart* const p = ( *it )->m_part;
5758 static_cast<KHTMLPart*>( p )->slotLoadImages();
5762 void KHTMLPart::reparseConfiguration()
5764 KHTMLSettings *settings = KHTMLGlobal::defaultHTMLSettings();
5765 settings->init();
5767 setAutoloadImages( settings->autoLoadImages() );
5768 if (d->m_doc)
5769 d->m_doc->docLoader()->setShowAnimations( settings->showAnimations() );
5771 d->m_bOpenMiddleClick = settings->isOpenMiddleClickEnabled();
5772 d->m_bBackRightClick = settings->isBackRightClickEnabled();
5773 d->m_bJScriptEnabled = settings->isJavaScriptEnabled(url().host());
5774 setDebugScript( settings->isJavaScriptDebugEnabled() );
5775 d->m_bJavaEnabled = settings->isJavaEnabled(url().host());
5776 d->m_bPluginsEnabled = settings->isPluginsEnabled(url().host());
5777 d->m_metaRefreshEnabled = settings->isAutoDelayedActionsEnabled ();
5779 delete d->m_settings;
5780 d->m_settings = new KHTMLSettings(*KHTMLGlobal::defaultHTMLSettings());
5782 QApplication::setOverrideCursor( Qt::WaitCursor );
5783 khtml::CSSStyleSelector::reparseConfiguration();
5784 if(d->m_doc) d->m_doc->updateStyleSelector();
5785 QApplication::restoreOverrideCursor();
5787 if (d->m_view) {
5788 KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling();
5789 if (ssm == KHTMLSettings::KSmoothScrollingDisabled)
5790 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled);
5791 else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient)
5792 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient);
5793 else
5794 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled);
5797 if (KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled())
5798 runAdFilter();
5801 QStringList KHTMLPart::frameNames() const
5803 QStringList res;
5805 ConstFrameIt it = d->m_frames.constBegin();
5806 const ConstFrameIt end = d->m_frames.constEnd();
5807 for (; it != end; ++it )
5808 if (!(*it)->m_bPreloaded && (*it)->m_part)
5809 res += (*it)->m_name;
5811 return res;
5814 QList<KParts::ReadOnlyPart*> KHTMLPart::frames() const
5816 QList<KParts::ReadOnlyPart*> res;
5818 ConstFrameIt it = d->m_frames.constBegin();
5819 const ConstFrameIt end = d->m_frames.constEnd();
5820 for (; it != end; ++it )
5821 if (!(*it)->m_bPreloaded && (*it)->m_part) // ### TODO: make sure that we always create an empty
5822 // KHTMLPart for frames so this never happens.
5823 res.append( (*it)->m_part );
5825 return res;
5828 bool KHTMLPart::openUrlInFrame( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs)
5830 kDebug( 6050 ) << this << url;
5831 FrameIt it = d->m_frames.find( browserArgs.frameName );
5833 if ( it == d->m_frames.end() )
5834 return false;
5836 // Inform someone that we are about to show something else.
5837 if ( !browserArgs.lockHistory() )
5838 emit d->m_extension->openUrlNotify();
5840 requestObject( *it, url, args, browserArgs );
5842 return true;
5845 void KHTMLPart::setDNDEnabled( bool b )
5847 d->m_bDnd = b;
5850 bool KHTMLPart::dndEnabled() const
5852 return d->m_bDnd;
5855 void KHTMLPart::customEvent( QEvent *event )
5857 if ( khtml::MousePressEvent::test( event ) )
5859 khtmlMousePressEvent( static_cast<khtml::MousePressEvent *>( event ) );
5860 return;
5863 if ( khtml::MouseDoubleClickEvent::test( event ) )
5865 khtmlMouseDoubleClickEvent( static_cast<khtml::MouseDoubleClickEvent *>( event ) );
5866 return;
5869 if ( khtml::MouseMoveEvent::test( event ) )
5871 khtmlMouseMoveEvent( static_cast<khtml::MouseMoveEvent *>( event ) );
5872 return;
5875 if ( khtml::MouseReleaseEvent::test( event ) )
5877 khtmlMouseReleaseEvent( static_cast<khtml::MouseReleaseEvent *>( event ) );
5878 return;
5881 if ( khtml::DrawContentsEvent::test( event ) )
5883 khtmlDrawContentsEvent( static_cast<khtml::DrawContentsEvent *>( event ) );
5884 return;
5887 KParts::ReadOnlyPart::customEvent( event );
5890 bool KHTMLPart::isPointInsideSelection(int x, int y)
5892 // Treat a collapsed selection like no selection.
5893 if (d->editor_context.m_selection.state() == Selection::CARET)
5894 return false;
5895 if (!xmlDocImpl()->renderer())
5896 return false;
5898 khtml::RenderObject::NodeInfo nodeInfo(true, true);
5899 xmlDocImpl()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y);
5900 NodeImpl *innerNode = nodeInfo.innerNode();
5901 if (!innerNode || !innerNode->renderer())
5902 return false;
5904 return innerNode->isPointInsideSelection(x, y, d->editor_context.m_selection);
5907 /** returns the position of the first inline text box of the line at
5908 * coordinate y in renderNode
5910 * This is a helper function for line-by-line text selection.
5912 static bool firstRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
5914 for (khtml::RenderObject *n = renderNode; n; n = n->nextSibling()) {
5915 if (n->isText()) {
5916 khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
5917 for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
5918 if (box->m_y == y && textRenderer->element()) {
5919 startNode = textRenderer->element();
5920 startOffset = box->m_start;
5921 return true;
5926 if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
5927 return true;
5931 return false;
5934 /** returns the position of the last inline text box of the line at
5935 * coordinate y in renderNode
5937 * This is a helper function for line-by-line text selection.
5939 static bool lastRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
5941 khtml::RenderObject *n = renderNode;
5942 if (!n) {
5943 return false;
5945 khtml::RenderObject *next;
5946 while ((next = n->nextSibling())) {
5947 n = next;
5950 while (1) {
5951 if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
5952 return true;
5955 if (n->isText()) {
5956 khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
5957 for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
5958 if (box->m_y == y && textRenderer->element()) {
5959 endNode = textRenderer->element();
5960 endOffset = box->m_start + box->m_len;
5961 return true;
5966 if (n == renderNode) {
5967 return false;
5970 n = n->previousSibling();
5974 void KHTMLPart::handleMousePressEventDoubleClick(khtml::MouseDoubleClickEvent *event)
5976 QMouseEvent *mouse = event->qmouseEvent();
5977 DOM::Node innerNode = event->innerNode();
5979 Selection selection;
5981 if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() &&
5982 innerNode.handle()->renderer()->shouldSelect()) {
5983 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()));
5984 if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
5985 selection.moveTo(pos);
5986 selection.expandUsingGranularity(Selection::WORD);
5990 if (selection.state() != Selection::CARET) {
5991 d->editor_context.beginSelectingText(Selection::WORD);
5994 setCaret(selection);
5995 startAutoScroll();
5998 void KHTMLPart::handleMousePressEventTripleClick(khtml::MouseDoubleClickEvent *event)
6000 QMouseEvent *mouse = event->qmouseEvent();
6001 DOM::Node innerNode = event->innerNode();
6003 Selection selection;
6005 if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() &&
6006 innerNode.handle()->renderer()->shouldSelect()) {
6007 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()));
6008 if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
6009 selection.moveTo(pos);
6010 selection.expandUsingGranularity(Selection::LINE);
6014 if (selection.state() != Selection::CARET) {
6015 d->editor_context.beginSelectingText(Selection::LINE);
6018 setCaret(selection);
6019 startAutoScroll();
6022 void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event)
6024 QMouseEvent *mouse = event->qmouseEvent();
6025 DOM::Node innerNode = event->innerNode();
6027 if (mouse->button() == Qt::LeftButton) {
6028 Selection sel;
6030 if (!innerNode.isNull() && innerNode.handle()->renderer() &&
6031 innerNode.handle()->renderer()->shouldSelect()) {
6032 bool extendSelection = mouse->modifiers() & Qt::ShiftModifier;
6034 // Don't restart the selection when the mouse is pressed on an
6035 // existing selection so we can allow for text dragging.
6036 if (!extendSelection && isPointInsideSelection(event->x(), event->y())) {
6037 return;
6039 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()));
6040 if (pos.isEmpty())
6041 pos = Position(innerNode.handle(), innerNode.handle()->caretMinOffset());
6043 sel = caret();
6044 if (extendSelection && sel.notEmpty()) {
6045 sel.clearModifyBias();
6046 sel.setExtent(pos);
6047 if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
6048 sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
6050 d->editor_context.m_beganSelectingText = true;
6051 } else {
6052 sel = pos;
6053 d->editor_context.m_selectionGranularity = Selection::CHARACTER;
6057 setCaret(sel);
6058 startAutoScroll();
6062 void KHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent *event )
6064 DOM::DOMString url = event->url();
6065 QMouseEvent *_mouse = event->qmouseEvent();
6066 DOM::Node innerNode = event->innerNode();
6067 d->m_mousePressNode = innerNode;
6069 d->m_dragStartPos = QPoint(event->x(), event->y());
6071 if ( !event->url().isNull() ) {
6072 d->m_strSelectedURL = event->url().string();
6073 d->m_strSelectedURLTarget = event->target().string();
6075 else {
6076 d->m_strSelectedURL.clear();
6077 d->m_strSelectedURLTarget.clear();
6080 if ( _mouse->button() == Qt::LeftButton ||
6081 _mouse->button() == Qt::MidButton )
6083 d->m_bMousePressed = true;
6085 #ifdef KHTML_NO_SELECTION
6086 d->m_dragLastPos = _mouse->globalPos();
6087 #else
6088 if ( _mouse->button() == Qt::LeftButton )
6090 if ( (!d->m_strSelectedURL.isNull() && !isEditable())
6091 || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) )
6092 return;
6094 d->editor_context.m_beganSelectingText = false;
6096 handleMousePressEventSingleClick(event);
6098 #endif
6101 if ( _mouse->button() == Qt::RightButton && parentPart() != 0 && d->m_bBackRightClick )
6103 d->m_bRightMousePressed = true;
6104 } else if ( _mouse->button() == Qt::RightButton )
6106 popupMenu( d->m_strSelectedURL );
6107 // might be deleted, don't touch "this"
6111 void KHTMLPart::khtmlMouseDoubleClickEvent( khtml::MouseDoubleClickEvent *event )
6113 QMouseEvent *_mouse = event->qmouseEvent();
6114 if ( _mouse->button() == Qt::LeftButton )
6116 d->m_bMousePressed = true;
6117 d->editor_context.m_beganSelectingText = false;
6119 if (event->clickCount() == 2) {
6120 handleMousePressEventDoubleClick(event);
6121 return;
6124 if (event->clickCount() >= 3) {
6125 handleMousePressEventTripleClick(event);
6126 return;
6131 #ifndef KHTML_NO_SELECTION
6132 bool KHTMLPart::isExtendingSelection() const
6134 // This is it, the whole detection. khtmlMousePressEvent only sets this
6135 // on LMB or MMB, but never on RMB. As text selection doesn't work for MMB,
6136 // it's sufficient to only rely on this flag to detect selection extension.
6137 return d->editor_context.m_beganSelectingText;
6140 void KHTMLPart::extendSelectionTo(int x, int y, const DOM::Node &innerNode)
6142 // handle making selection
6143 Position pos(innerNode.handle()->positionForCoordinates(x, y));
6145 // Don't modify the selection if we're not on a node.
6146 if (pos.isEmpty())
6147 return;
6149 // Restart the selection if this is the first mouse move. This work is usually
6150 // done in khtmlMousePressEvent, but not if the mouse press was on an existing selection.
6151 Selection sel = caret();
6152 sel.clearModifyBias();
6153 if (!d->editor_context.m_beganSelectingText) {
6154 // We are beginning a selection during press-drag, when the original click
6155 // wasn't appropriate for one. Make sure to set the granularity.
6156 d->editor_context.beginSelectingText(Selection::CHARACTER);
6157 sel.moveTo(pos);
6160 sel.setExtent(pos);
6161 if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
6162 sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
6164 setCaret(sel);
6167 #endif // KHTML_NO_SELECTION
6169 bool KHTMLPart::handleMouseMoveEventDrag(khtml::MouseMoveEvent *event)
6171 #ifdef QT_NO_DRAGANDDROP
6172 return false;
6173 #else
6174 DOM::Node innerNode = event->innerNode();
6176 if( (d->m_bMousePressed &&
6177 ( (!d->m_strSelectedURL.isEmpty() && !isEditable())
6178 || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) ) )
6179 && ( d->m_dragStartPos - QPoint(event->x(), event->y()) ).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
6181 DOM::DOMString url = event->url();
6183 QPixmap pix;
6184 HTMLImageElementImpl *img = 0L;
6185 KUrl u;
6187 // qDebug("****************** Event URL: %s", url.string().toLatin1().constData());
6188 // qDebug("****************** Event Target: %s", target.string().toLatin1().constData());
6190 // Normal image...
6191 if ( url.length() == 0 && innerNode.handle() && innerNode.handle()->id() == ID_IMG )
6193 img = static_cast<HTMLImageElementImpl *>(innerNode.handle());
6194 u = KUrl( completeURL( khtml::parseURL(img->getAttribute(ATTR_SRC)).string() ) );
6195 pix = KIconLoader::global()->loadIcon("image-x-generic", KIconLoader::Desktop);
6197 else
6199 // Text or image link...
6200 u = completeURL( d->m_strSelectedURL );
6201 pix = KIO::pixmapForUrl(u, 0, KIconLoader::Desktop, KIconLoader::SizeMedium);
6204 u.setPass(QString());
6206 QDrag *drag = new QDrag( d->m_view->viewport() );
6207 QMap<QString, QString> metaDataMap;
6208 if ( !d->m_referrer.isEmpty() )
6209 metaDataMap.insert( "referrer", d->m_referrer );
6210 QMimeData* mimeData = new QMimeData();
6211 u.populateMimeData( mimeData, metaDataMap );
6212 drag->setMimeData( mimeData );
6214 if( img && img->complete() )
6215 drag->mimeData()->setImageData( img->currentImage() );
6217 if ( !pix.isNull() )
6218 drag->setPixmap( pix );
6220 stopAutoScroll();
6221 drag->start();
6223 // when we finish our drag, we need to undo our mouse press
6224 d->m_bMousePressed = false;
6225 d->m_strSelectedURL.clear();
6226 d->m_strSelectedURLTarget.clear();
6227 return true;
6229 return false;
6230 #endif // QT_NO_DRAGANDDROP
6233 bool KHTMLPart::handleMouseMoveEventOver(khtml::MouseMoveEvent *event)
6235 // Mouse clicked -> do nothing
6236 if ( d->m_bMousePressed ) return false;
6238 DOM::DOMString url = event->url();
6240 // The mouse is over something
6241 if ( url.length() )
6243 DOM::DOMString target = event->target();
6244 QMouseEvent *_mouse = event->qmouseEvent();
6245 DOM::Node innerNode = event->innerNode();
6247 bool shiftPressed = ( _mouse->modifiers() & Qt::ShiftModifier );
6249 // Image map
6250 if ( !innerNode.isNull() && innerNode.elementId() == ID_IMG )
6252 HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
6253 if ( i && i->isServerMap() )
6255 khtml::RenderObject *r = i->renderer();
6256 if(r)
6258 int absx, absy;
6259 r->absolutePosition(absx, absy);
6260 int x(event->x() - absx), y(event->y() - absy);
6262 d->m_overURL = url.string() + QString("?%1,%2").arg(x).arg(y);
6263 d->m_overURLTarget = target.string();
6264 overURL( d->m_overURL, target.string(), shiftPressed );
6265 return true;
6270 // normal link
6271 if ( d->m_overURL.isEmpty() || d->m_overURL != url || d->m_overURLTarget != target )
6273 d->m_overURL = url.string();
6274 d->m_overURLTarget = target.string();
6275 overURL( d->m_overURL, target.string(), shiftPressed );
6278 else // Not over a link...
6280 if( !d->m_overURL.isEmpty() ) // and we were over a link -> reset to "default statusbar text"
6282 // reset to "default statusbar text"
6283 resetHoverText();
6286 return true;
6289 void KHTMLPart::handleMouseMoveEventSelection(khtml::MouseMoveEvent *event)
6291 // Mouse not pressed. Do nothing.
6292 if (!d->m_bMousePressed)
6293 return;
6295 #ifdef KHTML_NO_SELECTION
6296 if (d->m_doc && d->m_view) {
6297 QPoint diff( mouse->globalPos() - d->m_dragLastPos );
6299 if (abs(diff.x()) > 64 || abs(diff.y()) > 64) {
6300 d->m_view->scrollBy(-diff.x(), -diff.y());
6301 d->m_dragLastPos = mouse->globalPos();
6304 #else
6306 QMouseEvent *mouse = event->qmouseEvent();
6307 DOM::Node innerNode = event->innerNode();
6309 if ( (mouse->buttons() & Qt::LeftButton) == 0 || !innerNode.handle() || !innerNode.handle()->renderer() ||
6310 !innerNode.handle()->renderer()->shouldSelect())
6311 return;
6313 // handle making selection
6314 extendSelectionTo(event->x(), event->y(), innerNode);
6315 #endif // KHTML_NO_SELECTION
6318 void KHTMLPart::khtmlMouseMoveEvent( khtml::MouseMoveEvent *event )
6320 if (handleMouseMoveEventDrag(event))
6321 return;
6323 if (handleMouseMoveEventOver(event))
6324 return;
6326 handleMouseMoveEventSelection(event);
6329 void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
6331 DOM::Node innerNode = event->innerNode();
6332 d->m_mousePressNode = DOM::Node();
6334 if ( d->m_bMousePressed ) {
6335 setStatusBarText(QString(), BarHoverText);
6336 stopAutoScroll();
6339 // Used to prevent mouseMoveEvent from initiating a drag before
6340 // the mouse is pressed again.
6341 d->m_bMousePressed = false;
6343 QMouseEvent *_mouse = event->qmouseEvent();
6344 if ( _mouse->button() == Qt::RightButton && parentPart() != 0 && d->m_bBackRightClick )
6346 d->m_bRightMousePressed = false;
6347 KParts::BrowserInterface *tmp_iface = d->m_extension->browserInterface();
6348 if( tmp_iface ) {
6349 tmp_iface->callMethod( "goHistory", -1 );
6352 #ifndef QT_NO_CLIPBOARD
6353 if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == Qt::MidButton) && (event->url().isNull())) {
6354 kDebug( 6050 ) << "MMB shouldOpen=" << d->m_bOpenMiddleClick;
6356 if (d->m_bOpenMiddleClick) {
6357 KHTMLPart *p = this;
6358 while (p->parentPart()) p = p->parentPart();
6359 p->d->m_extension->pasteRequest();
6362 #endif
6364 #ifndef KHTML_NO_SELECTION
6367 // Clear the selection if the mouse didn't move after the last mouse press.
6368 // We do this so when clicking on the selection, the selection goes away.
6369 // However, if we are editing, place the caret.
6370 if (!d->editor_context.m_beganSelectingText
6371 && d->m_dragStartPos.x() == event->x()
6372 && d->m_dragStartPos.y() == event->y()
6373 && d->editor_context.m_selection.state() == Selection::RANGE) {
6374 Selection selection;
6375 #ifdef APPLE_CHANGES
6376 if (d->editor_context.m_selection.base().node()->isContentEditable())
6377 #endif
6378 selection.moveTo(d->editor_context.m_selection.base().node()->positionForCoordinates(event->x(), event->y()));
6379 setCaret(selection);
6381 // get selected text and paste to the clipboard
6382 #ifndef QT_NO_CLIPBOARD
6383 QString text = selectedText();
6384 text.replace(QChar(0xa0), ' ');
6385 if (!text.isEmpty()) {
6386 disconnect( qApp->clipboard(), SIGNAL( selectionChanged()), this, SLOT( slotClearSelection()));
6387 qApp->clipboard()->setText(text,QClipboard::Selection);
6388 connect( qApp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
6390 #endif
6391 //kDebug( 6000 ) << "selectedText = " << text;
6392 emitSelectionChanged();
6393 //kDebug(6000) << "rel2: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << "), caretOfs " << d->caretOffset();
6395 #endif
6398 void KHTMLPart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * )
6402 void KHTMLPart::guiActivateEvent( KParts::GUIActivateEvent *event )
6404 if ( event->activated() )
6406 emitSelectionChanged();
6407 emit d->m_extension->enableAction( "print", d->m_doc != 0 );
6409 if ( !d->m_settings->autoLoadImages() && d->m_paLoadImages )
6411 QList<QAction*> lst;
6412 lst.append( d->m_paLoadImages );
6413 plugActionList( "loadImages", lst );
6418 void KHTMLPart::slotPrintFrame()
6420 if ( d->m_frames.count() == 0 )
6421 return;
6423 KParts::ReadOnlyPart *frame = currentFrame();
6424 if (!frame)
6425 return;
6427 KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject( frame );
6429 if ( !ext )
6430 return;
6433 const QMetaObject *mo = ext->metaObject();
6436 if (mo->indexOfSlot( "print()") != -1)
6437 QMetaObject::invokeMethod(ext, "print()", Qt::DirectConnection);
6440 void KHTMLPart::slotSelectAll()
6442 KParts::ReadOnlyPart *part = currentFrame();
6443 if (part && part->inherits("KHTMLPart"))
6444 static_cast<KHTMLPart *>(part)->selectAll();
6447 void KHTMLPart::startAutoScroll()
6449 connect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ));
6450 d->m_scrollTimer.setSingleShot(false);
6451 d->m_scrollTimer.start(100);
6454 void KHTMLPart::stopAutoScroll()
6456 disconnect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ));
6457 if (d->m_scrollTimer.isActive())
6458 d->m_scrollTimer.stop();
6462 void KHTMLPart::slotAutoScroll()
6464 if (d->m_view)
6465 d->m_view->doAutoScroll();
6466 else
6467 stopAutoScroll(); // Safety
6470 void KHTMLPart::runAdFilter()
6472 if ( parentPart() )
6473 parentPart()->runAdFilter();
6475 if ( !d->m_doc )
6476 return;
6478 QSetIterator<khtml::CachedObject*> it( d->m_doc->docLoader()->m_docObjects );
6479 while (it.hasNext())
6481 khtml::CachedObject* obj = it.next();
6482 if ( obj->type() == khtml::CachedObject::Image ) {
6483 khtml::CachedImage *image = static_cast<khtml::CachedImage *>(obj);
6484 bool wasBlocked = image->m_wasBlocked;
6485 image->m_wasBlocked = KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( image->url().string() ) );
6486 if ( image->m_wasBlocked != wasBlocked )
6487 image->do_notify(QRect(QPoint(0,0), image->pixmap_size()));
6491 if ( KHTMLGlobal::defaultHTMLSettings()->isHideAdsEnabled() ) {
6492 for ( NodeImpl *nextNode, *node = d->m_doc; node; node = nextNode ) {
6494 // We might be deleting 'node' shortly.
6495 nextNode = node->traverseNextNode();
6497 if ( node->id() == ID_IMG ||
6498 node->id() == ID_IFRAME ||
6499 (node->id() == ID_INPUT && static_cast<HTMLInputElementImpl *>(node)->inputType() == HTMLInputElementImpl::IMAGE ))
6501 if ( KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( static_cast<ElementImpl *>(node)->getAttribute(ATTR_SRC).string() ) ) )
6503 // We found an IMG, IFRAME or INPUT (of type IMAGE) matching a filter.
6504 node->ref();
6505 NodeImpl *parent = node->parent();
6506 if( parent )
6508 int exception = 0;
6509 parent->removeChild(node, exception);
6511 node->deref();
6518 void KHTMLPart::selectAll()
6520 if (!d->m_doc) return;
6522 NodeImpl *first;
6523 if (d->m_doc->isHTMLDocument())
6524 first = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
6525 else
6526 first = d->m_doc;
6527 NodeImpl *next;
6529 // Look for first text/cdata node that has a renderer,
6530 // or first childless replaced element
6531 while ( first && !(first->renderer()
6532 && ((first->nodeType() == Node::TEXT_NODE || first->nodeType() == Node::CDATA_SECTION_NODE)
6533 || (first->renderer()->isReplaced() && !first->renderer()->firstChild()))))
6535 next = first->firstChild();
6536 if ( !next ) next = first->nextSibling();
6537 while( first && !next )
6539 first = first->parentNode();
6540 if ( first )
6541 next = first->nextSibling();
6543 first = next;
6546 NodeImpl *last;
6547 if (d->m_doc->isHTMLDocument())
6548 last = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
6549 else
6550 last = d->m_doc;
6551 // Look for last text/cdata node that has a renderer,
6552 // or last childless replaced element
6553 // ### Instead of changing this loop, use findLastSelectableNode
6554 // in render_table.cpp (LS)
6555 while ( last && !(last->renderer()
6556 && ((last->nodeType() == Node::TEXT_NODE || last->nodeType() == Node::CDATA_SECTION_NODE)
6557 || (last->renderer()->isReplaced() && !last->renderer()->lastChild()))))
6559 next = last->lastChild();
6560 if ( !next ) next = last->previousSibling();
6561 while ( last && !next )
6563 last = last->parentNode();
6564 if ( last )
6565 next = last->previousSibling();
6567 last = next;
6570 if ( !first || !last )
6571 return;
6572 Q_ASSERT(first->renderer());
6573 Q_ASSERT(last->renderer());
6574 d->editor_context.m_selection.moveTo(Position(first, 0), Position(last, last->nodeValue().length()));
6575 d->m_doc->updateSelection();
6577 emitSelectionChanged();
6580 bool KHTMLPart::checkLinkSecurity(const KUrl &linkURL,const KLocalizedString &message, const QString &button)
6582 bool linkAllowed = true;
6584 if ( d->m_doc )
6585 linkAllowed = KAuthorized::authorizeUrlAction("redirect", url(), linkURL);
6587 if ( !linkAllowed ) {
6588 khtml::Tokenizer *tokenizer = d->m_doc->tokenizer();
6589 if (tokenizer)
6590 tokenizer->setOnHold(true);
6592 int response = KMessageBox::Cancel;
6593 if (!message.isEmpty())
6595 response = KMessageBox::warningContinueCancel( 0,
6596 message.subs(Qt::escape(linkURL.prettyUrl())).toString(),
6597 i18n( "Security Warning" ),
6598 KGuiItem(button));
6600 else
6602 KMessageBox::error( 0,
6603 i18n( "<qt>Access by untrusted page to<br /><b>%1</b><br /> denied.</qt>", Qt::escape(linkURL.prettyUrl())),
6604 i18n( "Security Alert" ));
6607 if (tokenizer)
6608 tokenizer->setOnHold(false);
6609 return (response==KMessageBox::Continue);
6611 return true;
6614 void KHTMLPart::slotPartRemoved( KParts::Part *part )
6616 // kDebug(6050) << part;
6617 if ( part == d->m_activeFrame )
6619 d->m_activeFrame = 0L;
6620 if ( !part->inherits( "KHTMLPart" ) )
6622 if (factory()) {
6623 factory()->removeClient( part );
6625 if (childClients().contains(part)) {
6626 removeChildClient( part );
6632 void KHTMLPart::slotActiveFrameChanged( KParts::Part *part )
6634 // kDebug(6050) << this << "part=" << part;
6635 if ( part == this )
6637 kError(6050) << "strange error! we activated ourselves";
6638 assert( false );
6639 return;
6641 // kDebug(6050) << "d->m_activeFrame=" << d->m_activeFrame;
6642 if ( d->m_activeFrame && d->m_activeFrame->widget() && d->m_activeFrame->widget()->inherits( "QFrame" ) )
6644 QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
6645 if (frame->frameStyle() != QFrame::NoFrame)
6647 frame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken);
6648 frame->repaint();
6652 if( d->m_activeFrame && !d->m_activeFrame->inherits( "KHTMLPart" ) )
6654 if (factory()) {
6655 factory()->removeClient( d->m_activeFrame );
6657 removeChildClient( d->m_activeFrame );
6659 if( part && !part->inherits( "KHTMLPart" ) )
6661 if (factory()) {
6662 factory()->addClient( part );
6664 insertChildClient( part );
6668 d->m_activeFrame = part;
6670 if ( d->m_activeFrame && d->m_activeFrame->widget()->inherits( "QFrame" ) )
6672 QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
6673 if (frame->frameStyle() != QFrame::NoFrame)
6675 frame->setFrameStyle( QFrame::StyledPanel | QFrame::Plain);
6676 frame->repaint();
6678 kDebug(6050) << "new active frame " << d->m_activeFrame;
6681 updateActions();
6683 // (note: childObject returns 0 if the argument is 0)
6684 d->m_extension->setExtensionProxy( KParts::BrowserExtension::childObject( d->m_activeFrame ) );
6687 void KHTMLPart::setActiveNode(const DOM::Node &node)
6689 if (!d->m_doc || !d->m_view)
6690 return;
6692 // Set the document's active node
6693 d->m_doc->setFocusNode(node.handle());
6695 // Scroll the view if necessary to ensure that the new focus node is visible
6696 QRect rect = node.handle()->getRect();
6697 d->m_view->ensureVisible(rect.right(), rect.bottom());
6698 d->m_view->ensureVisible(rect.left(), rect.top());
6701 DOM::Node KHTMLPart::activeNode() const
6703 return DOM::Node(d->m_doc?d->m_doc->focusNode():0);
6706 DOM::EventListener *KHTMLPart::createHTMLEventListener( QString code, QString name, NodeImpl* node, bool svg )
6708 KJSProxy *proxy = jScript();
6710 if (!proxy)
6711 return 0;
6713 return proxy->createHTMLEventHandler( url().url(), name, code, node, svg );
6716 KHTMLPart *KHTMLPart::opener()
6718 return d->m_opener;
6721 void KHTMLPart::setOpener(KHTMLPart *_opener)
6723 d->m_opener = _opener;
6726 bool KHTMLPart::openedByJS()
6728 return d->m_openedByJS;
6731 void KHTMLPart::setOpenedByJS(bool _openedByJS)
6733 d->m_openedByJS = _openedByJS;
6736 void KHTMLPart::preloadStyleSheet(const QString &url, const QString &stylesheet)
6738 khtml::Cache::preloadStyleSheet(url, stylesheet);
6741 void KHTMLPart::preloadScript(const QString &url, const QString &script)
6743 khtml::Cache::preloadScript(url, script);
6746 long KHTMLPart::cacheId() const
6748 return d->m_cacheId;
6751 bool KHTMLPart::restored() const
6753 return d->m_restored;
6756 bool KHTMLPart::pluginPageQuestionAsked(const QString& mimetype) const
6758 // parentPart() should be const!
6759 KHTMLPart* parent = const_cast<KHTMLPart *>(this)->parentPart();
6760 if ( parent )
6761 return parent->pluginPageQuestionAsked(mimetype);
6763 return d->m_pluginPageQuestionAsked.contains(mimetype);
6766 void KHTMLPart::setPluginPageQuestionAsked(const QString& mimetype)
6768 if ( parentPart() )
6769 parentPart()->setPluginPageQuestionAsked(mimetype);
6771 d->m_pluginPageQuestionAsked.append(mimetype);
6774 KEncodingDetector *KHTMLPart::createDecoder()
6776 KEncodingDetector *dec = new KEncodingDetector();
6777 if( !d->m_encoding.isNull() )
6778 dec->setEncoding( d->m_encoding.toLatin1().constData(),
6779 d->m_haveEncoding ? KEncodingDetector::UserChosenEncoding : KEncodingDetector::EncodingFromHTTPHeader);
6780 else {
6781 // Inherit the default encoding from the parent frame if there is one.
6782 QByteArray defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
6783 ? QByteArray( parentPart()->d->m_decoder->encoding() ) : settings()->encoding().toLatin1();
6784 dec->setEncoding(defaultEncoding.constData(), KEncodingDetector::DefaultEncoding);
6786 #ifdef APPLE_CHANGES
6787 if (d->m_doc)
6788 d->m_doc->setDecoder(d->m_decoder);
6789 #endif
6790 dec->setAutoDetectLanguage( d->m_autoDetectLanguage );
6791 return dec;
6794 void KHTMLPart::emitCaretPositionChanged(const DOM::Position &pos) {
6795 // pos must not be already converted to range-compliant coordinates
6796 Position rng_pos = pos.equivalentRangeCompliantPosition();
6797 Node node = rng_pos.node();
6798 emit caretPositionChanged(node, rng_pos.offset());
6801 void KHTMLPart::restoreScrollPosition()
6803 const KParts::OpenUrlArguments args( arguments() );
6805 if ( url().hasRef() && !d->m_restoreScrollPosition && !args.reload()) {
6806 if ( !d->m_doc || !d->m_doc->parsing() )
6807 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
6808 if ( !gotoAnchor(url().encodedHtmlRef()) )
6809 gotoAnchor(url().htmlRef());
6810 return;
6813 // Check whether the viewport has become large enough to encompass the stored
6814 // offsets. If the document has been fully loaded, force the new coordinates,
6815 // even if the canvas is too short (can happen when user resizes the window
6816 // during loading).
6817 if (d->m_view->contentsHeight() - d->m_view->visibleHeight() >= args.yOffset()
6818 || d->m_bComplete) {
6819 d->m_view->setContentsPos(args.xOffset(), args.yOffset());
6820 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
6825 void KHTMLPart::openWallet(DOM::HTMLFormElementImpl *form)
6827 #ifndef KHTML_NO_WALLET
6828 KHTMLPart *p;
6830 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
6833 if (p) {
6834 p->openWallet(form);
6835 return;
6838 if (onlyLocalReferences()) { // avoid triggering on local apps, thumbnails
6839 return;
6842 if (d->m_wallet) {
6843 if (d->m_bWalletOpened) {
6844 if (d->m_wallet->isOpen()) {
6845 form->walletOpened(d->m_wallet);
6846 return;
6848 d->m_wallet->deleteLater();
6849 d->m_wallet = 0L;
6850 d->m_bWalletOpened = false;
6854 if (!d->m_wq) {
6855 KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
6856 d->m_wq = new KHTMLWalletQueue(this);
6857 d->m_wq->wallet = wallet;
6858 connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
6859 connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
6861 assert(form);
6862 d->m_wq->callers.append(KHTMLWalletQueue::Caller(form, form->document()));
6863 #endif // KHTML_NO_WALLET
6867 void KHTMLPart::saveToWallet(const QString& key, const QMap<QString,QString>& data)
6869 #ifndef KHTML_NO_WALLET
6870 KHTMLPart *p;
6872 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
6875 if (p) {
6876 p->saveToWallet(key, data);
6877 return;
6880 if (d->m_wallet) {
6881 if (d->m_bWalletOpened) {
6882 if (d->m_wallet->isOpen()) {
6883 if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder())) {
6884 d->m_wallet->createFolder(KWallet::Wallet::FormDataFolder());
6886 d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder());
6887 d->m_wallet->writeMap(key, data);
6888 return;
6890 d->m_wallet->deleteLater();
6891 d->m_wallet = 0L;
6892 d->m_bWalletOpened = false;
6896 if (!d->m_wq) {
6897 KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
6898 d->m_wq = new KHTMLWalletQueue(this);
6899 d->m_wq->wallet = wallet;
6900 connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
6901 connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
6903 d->m_wq->savers.append(qMakePair(key, data));
6904 #endif // KHTML_NO_WALLET
6908 void KHTMLPart::dequeueWallet(DOM::HTMLFormElementImpl *form) {
6909 #ifndef KHTML_NO_WALLET
6910 KHTMLPart *p;
6912 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
6915 if (p) {
6916 p->dequeueWallet(form);
6917 return;
6920 if (d->m_wq) {
6921 d->m_wq->callers.removeAll(KHTMLWalletQueue::Caller(form, form->document()));
6923 #endif // KHTML_NO_WALLET
6927 void KHTMLPart::walletOpened(KWallet::Wallet *wallet) {
6928 #ifndef KHTML_NO_WALLET
6929 assert(!d->m_wallet);
6930 assert(d->m_wq);
6932 d->m_wq->deleteLater(); // safe?
6933 d->m_wq = 0L;
6935 if (!wallet) {
6936 d->m_bWalletOpened = false;
6937 return;
6940 d->m_wallet = wallet;
6941 d->m_bWalletOpened = true;
6942 connect(d->m_wallet, SIGNAL(walletClosed()), SLOT(slotWalletClosed()));
6944 if (!d->m_statusBarWalletLabel) {
6945 d->m_statusBarWalletLabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
6946 d->m_statusBarWalletLabel->setFixedHeight(KHTMLGlobal::iconLoader()->currentSize(KIconLoader::Small));
6947 d->m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
6948 d->m_statusBarWalletLabel->setUseCursor(false);
6949 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarWalletLabel, 0, false);
6950 d->m_statusBarWalletLabel->setPixmap(SmallIcon("wallet-open"));
6951 connect(d->m_statusBarWalletLabel, SIGNAL(leftClickedUrl()), SLOT(launchWalletManager()));
6952 connect(d->m_statusBarWalletLabel, SIGNAL(rightClickedUrl()), SLOT(walletMenu()));
6954 d->m_statusBarWalletLabel->setToolTip(i18n("The wallet '%1' is open and being used for form data and passwords.", KWallet::Wallet::NetworkWallet()));
6955 #endif // KHTML_NO_WALLET
6959 KWallet::Wallet *KHTMLPart::wallet()
6961 #ifndef KHTML_NO_WALLET
6962 KHTMLPart *p;
6964 for (p = parentPart(); p && p->parentPart(); p = p->parentPart())
6967 if (p)
6968 return p->wallet();
6970 return d->m_wallet;
6971 #else
6972 return 0;
6973 #endif // !KHTML_NO_WALLET
6977 void KHTMLPart::slotWalletClosed()
6979 #ifndef KHTML_NO_WALLET
6980 if (d->m_wallet) {
6981 d->m_wallet->deleteLater();
6982 d->m_wallet = 0L;
6984 d->m_bWalletOpened = false;
6985 if (d->m_statusBarWalletLabel) {
6986 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarWalletLabel);
6987 delete d->m_statusBarWalletLabel;
6988 d->m_statusBarWalletLabel = 0L;
6990 #endif // KHTML_NO_WALLET
6993 void KHTMLPart::launchWalletManager()
6995 #ifndef KHTML_NO_WALLET
6996 QDBusInterface r("org.kde.kwalletmanager", "/kwalletmanager/MainWindow_1",
6997 "org.kde.KMainWindow");
6998 if (!r.isValid()) {
6999 KToolInvocation::startServiceByDesktopName("kwalletmanager_show");
7000 } else {
7001 r.call(QDBus::NoBlock, "show");
7002 r.call(QDBus::NoBlock, "raise");
7004 #endif // KHTML_NO_WALLET
7007 void KHTMLPart::walletMenu()
7009 #ifndef KHTML_NO_WALLET
7010 KMenu *m = new KMenu(0L);
7011 m->addAction(i18n("&Close Wallet"), this, SLOT(slotWalletClosed()));
7012 m->popup(QCursor::pos());
7013 #endif // KHTML_NO_WALLET
7016 void KHTMLPart::slotToggleCaretMode()
7018 setCaretMode(d->m_paToggleCaretMode->isChecked());
7021 void KHTMLPart::setFormNotification(KHTMLPart::FormNotification fn) {
7022 d->m_formNotification = fn;
7025 KHTMLPart::FormNotification KHTMLPart::formNotification() const {
7026 return d->m_formNotification;
7029 KUrl KHTMLPart::toplevelURL()
7031 KHTMLPart* part = this;
7032 while (part->parentPart())
7033 part = part->parentPart();
7035 if (!part)
7036 return KUrl();
7038 return part->url();
7041 bool KHTMLPart::isModified() const
7043 if ( !d->m_doc )
7044 return false;
7046 return d->m_doc->unsubmittedFormChanges();
7049 void KHTMLPart::setDebugScript( bool enable )
7051 unplugActionList( "debugScriptList" );
7052 if ( enable ) {
7053 if (!d->m_paDebugScript) {
7054 d->m_paDebugScript = new KAction( i18n( "JavaScript &Debugger" ), this );
7055 actionCollection()->addAction( "debugScript", d->m_paDebugScript );
7056 connect( d->m_paDebugScript, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugScript() ) );
7058 d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
7059 QList<QAction*> lst;
7060 lst.append( d->m_paDebugScript );
7061 plugActionList( "debugScriptList", lst );
7063 d->m_bJScriptDebugEnabled = enable;
7066 void KHTMLPart::setSuppressedPopupIndicator( bool enable, KHTMLPart *originPart )
7068 if ( parentPart() ) {
7069 parentPart()->setSuppressedPopupIndicator( enable, originPart );
7070 return;
7073 if ( enable && originPart ) {
7074 d->m_openableSuppressedPopups++;
7075 if ( d->m_suppressedPopupOriginParts.indexOf( originPart ) == -1 )
7076 d->m_suppressedPopupOriginParts.append( originPart );
7079 if ( enable && !d->m_statusBarPopupLabel ) {
7080 d->m_statusBarPopupLabel = new KUrlLabel( d->m_statusBarExtension->statusBar() );
7081 d->m_statusBarPopupLabel->setFixedHeight( KHTMLGlobal::iconLoader()->currentSize( KIconLoader::Small) );
7082 d->m_statusBarPopupLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ));
7083 d->m_statusBarPopupLabel->setUseCursor( false );
7084 d->m_statusBarExtension->addStatusBarItem( d->m_statusBarPopupLabel, 0, false );
7085 d->m_statusBarPopupLabel->setPixmap( SmallIcon( "window-suppressed") );
7087 d->m_statusBarPopupLabel->setToolTip(i18n("This page was prevented from opening a new window via JavaScript." ) );
7089 connect(d->m_statusBarPopupLabel, SIGNAL(leftClickedUrl()), SLOT(suppressedPopupMenu()));
7090 if (d->m_settings->jsPopupBlockerPassivePopup()) {
7091 QPixmap px;
7092 px = MainBarIcon( "window-suppressed" );
7093 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);
7095 } else if ( !enable && d->m_statusBarPopupLabel ) {
7096 d->m_statusBarPopupLabel->setToolTip("" );
7097 d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarPopupLabel );
7098 delete d->m_statusBarPopupLabel;
7099 d->m_statusBarPopupLabel = 0L;
7103 void KHTMLPart::suppressedPopupMenu() {
7104 KMenu *m = new KMenu(0L);
7105 if ( d->m_openableSuppressedPopups )
7106 m->addAction(i18np("&Show Blocked Popup Window","&Show %1 Blocked Popup Windows", d->m_openableSuppressedPopups), this, SLOT(showSuppressedPopups()));
7107 QAction *a = m->addAction(i18n("Show Blocked Window Passive Popup &Notification"), this, SLOT(togglePopupPassivePopup()));
7108 a->setChecked(d->m_settings->jsPopupBlockerPassivePopup());
7109 m->addAction(i18n("&Configure JavaScript New Window Policies..."), this, SLOT(launchJSConfigDialog()));
7110 m->popup(QCursor::pos());
7113 void KHTMLPart::togglePopupPassivePopup() {
7114 // Same hack as in disableJSErrorExtension()
7115 d->m_settings->setJSPopupBlockerPassivePopup( !d->m_settings->jsPopupBlockerPassivePopup() );
7116 emit configurationChanged();
7119 void KHTMLPart::showSuppressedPopups() {
7120 foreach ( KHTMLPart* part, d->m_suppressedPopupOriginParts ) {
7121 if (part) {
7122 KJS::Window *w = KJS::Window::retrieveWindow( part );
7123 if (w) {
7124 w->showSuppressedWindows();
7125 w->forgetSuppressedWindows();
7129 setSuppressedPopupIndicator( false );
7130 d->m_openableSuppressedPopups = 0;
7131 d->m_suppressedPopupOriginParts.clear();
7134 // Extension to use for "view document source", "save as" etc.
7135 // Using the right extension can help the viewer get into the right mode (#40496)
7136 QString KHTMLPart::defaultExtension() const
7138 if ( !d->m_doc )
7139 return ".html";
7140 if ( !d->m_doc->isHTMLDocument() )
7141 return ".xml";
7142 return d->m_doc->htmlMode() == DOM::DocumentImpl::XHtml ? ".xhtml" : ".html";
7145 bool KHTMLPart::inProgress() const
7147 if (!d->m_bComplete || d->m_runningScripts || (d->m_doc && d->m_doc->parsing()))
7148 return true;
7150 // Any frame that hasn't completed yet ?
7151 ConstFrameIt it = d->m_frames.constBegin();
7152 const ConstFrameIt end = d->m_frames.constEnd();
7153 for (; it != end; ++it ) {
7154 if ((*it)->m_run || !(*it)->m_bCompleted)
7155 return true;
7158 return d->m_submitForm || !d->m_redirectURL.isEmpty() || d->m_redirectionTimer.isActive() || d->m_job;
7161 using namespace KParts;
7162 #include "khtml_part.moc"
7163 #include "khtmlpart_p.moc"
7164 #ifndef KHTML_NO_WALLET
7165 #include "khtml_wallet_p.moc"
7166 #endif