1 // -*- c-basic-offset: 2 -*-
2 /* This file is part of the KDE project
4 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
5 * 1999 Lars Knoll <knoll@kde.org>
6 * 1999 Antti Koivisto <koivisto@kde.org>
7 * 2000 Simon Hausmann <hausmann@kde.org>
8 * 2000 Stefan Schimanski <1Stein@gmx.de>
9 * 2001 George Staikos <staikos@kde.org>
10 * Copyright (C) 2004 Apple Computer, Inc.
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
28 #include "khtml_part.h"
31 #define DIRECT_LINKAGE_TO_ECMA
32 #define QT_NO_CLIPBOARD
33 #define QT_NO_DRAGANDDROP
36 #include "khtml_pagecache.h"
38 #include "css/csshelper.h"
39 #include "css/cssproperties.h"
40 #include "css/cssstyleselector.h"
41 #include "css/css_computedstyle.h"
42 #include "css/css_valueimpl.h"
43 #include "dom/dom_string.h"
44 #include "editing/markup.h"
45 #include "editing/htmlediting.h"
46 #include "editing/selection.h"
47 #include "editing/visible_position.h"
48 #include "editing/visible_text.h"
49 #include "editing/visible_units.h"
50 #include "html/html_documentimpl.h"
51 #include "html/html_baseimpl.h"
52 #include "html/html_miscimpl.h"
53 #include "html/html_imageimpl.h"
54 #include "html/html_objectimpl.h"
55 #include "rendering/render_block.h"
56 #include "rendering/render_text.h"
57 #include "rendering/render_frames.h"
58 #include "misc/htmlhashes.h"
59 #include "misc/loader.h"
60 #include "xml/dom2_eventsimpl.h"
61 #include "xml/dom2_rangeimpl.h"
62 #include "xml/xml_tokenizer.h"
66 #include "khtmlview.h"
67 #include <kparts/partmanager.h>
68 #include "ecma/kjs_proxy.h"
69 #include "khtml_settings.h"
71 #include <sys/types.h>
75 #include <kstandarddirs.h>
77 #include <kio/global.h>
79 #include <kiconloader.h>
81 #include <kcharsets.h>
82 #include <kmessagebox.h>
83 #include <kstdaction.h>
84 #include <kfiledialog.h>
86 #include <kdatastream.h>
87 #include <ktempfile.h>
88 #include <kglobalsettings.h>
90 #include <kapplication.h>
91 #if !defined(QT_NO_DRAGANDDROP)
92 #include <kmultipledrag.h>
95 #include <ksslcertchain.h>
96 #include <ksslinfodlg.h>
98 #include <qclipboard.h>
100 #include <qmetaobject.h>
101 #include <qptrlist.h>
102 #include <private/qucomextra_p.h>
104 #include "khtmlpart_p.h"
106 #if !KHTML_NO_CPLUSPLUS_DOM
107 #include "dom/html_document.h"
111 #include <CoreServices/CoreServices.h>
114 using khtml::ApplyStyleCommand;
115 using khtml::CHARACTER;
116 using khtml::ChildFrame;
117 using khtml::Decoder;
118 using khtml::EAffinity;
119 using khtml::EditAction;
120 using khtml::EditCommandPtr;
121 using khtml::ETextGranularity;
122 using khtml::FormData;
123 using khtml::InlineTextBox;
124 using khtml::isEndOfDocument;
125 using khtml::isStartOfDocument;
126 using khtml::PARAGRAPH;
127 using khtml::plainText;
128 using khtml::RenderObject;
129 using khtml::RenderText;
130 using khtml::RenderWidget;
131 using khtml::Selection;
132 using khtml::Tokenizer;
133 using khtml::TypingCommand;
134 using khtml::VisiblePosition;
137 using KParts::BrowserInterface;
139 const int CARET_BLINK_FREQUENCY = 500;
142 class PartStyleSheetLoader : public CachedObjectClient
145 PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
148 m_cachedSheet = Cache::requestStyleSheet(dl, url );
150 m_cachedSheet->ref( this );
152 virtual ~PartStyleSheetLoader()
154 if ( m_cachedSheet ) m_cachedSheet->deref(this);
156 virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet)
159 m_part->setUserStyleSheet( sheet.string() );
163 QGuardedPtr<KHTMLPart> m_part;
164 khtml::CachedCSSStyleSheet *m_cachedSheet;
168 FrameList::Iterator FrameList::find( const QString &name )
170 Iterator it = begin();
174 if ( (*it).m_name==name )
180 KHTMLPart::KHTMLPart( QWidget *parentWidget, const char *widgetname, QObject *parent, const char *name,
182 : KParts::ReadOnlyPart( parent, name )
185 KHTMLFactory::registerPart( this );
186 setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
188 init( new KHTMLView( this, parentWidget, widgetname ), prof );
194 KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, const char *name, GUIProfile prof )
195 : KParts::ReadOnlyPart( parent, name )
198 KHTMLFactory::registerPart( this );
199 setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
204 #endif // APPLE_CHANGES
206 void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
208 AtomicString::init();
209 if ( prof == DefaultGUI )
210 setXMLFile( "khtml.rc" );
211 else if ( prof == BrowserViewGUI )
212 setXMLFile( "khtml_browser.rc" );
216 d = new KHTMLPartPrivate(parent());
219 setWidget( d->m_view );
222 d->m_guiProfile = prof;
224 d->m_extension = new KHTMLPartBrowserExtension( this );
225 d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
227 d->m_bSecurityInQuestion = false;
228 d->m_bMousePressed = false;
230 d->m_paLoadImages = 0;
231 d->m_paViewDocument = new KAction( i18n( "View Document Source" ), 0, this, SLOT( slotViewDocumentSource() ), actionCollection(), "viewDocumentSource" );
232 d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), 0, this, SLOT( slotViewFrameSource() ), actionCollection(), "viewFrameSource" );
233 d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), 0, this, SLOT( slotSaveBackground() ), actionCollection(), "saveBackground" );
234 d->m_paSaveDocument = new KAction( i18n( "&Save As..." ), CTRL+Key_S, this, SLOT( slotSaveDocument() ), actionCollection(), "saveDocument" );
236 d->m_paSaveDocument->setShortcut( KShortcut() ); // avoid clashes
237 d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), 0, this, SLOT( slotSaveFrame() ), actionCollection(), "saveFrame" );
238 d->m_paSecurity = new KAction( i18n( "Security..." ), "decrypted", 0, this, SLOT( slotSecurity() ), actionCollection(), "security" );
239 d->m_paDebugRenderTree = new KAction( "print rendering tree to stdout", 0, this, SLOT( slotDebugRenderTree() ), actionCollection(), "debugRenderTree" );
240 d->m_paDebugDOMTree = new KAction( "print DOM tree to stdout", 0, this, SLOT( slotDebugDOMTree() ), actionCollection(), "debugDOMTree" );
242 QString foo1 = i18n("Show Images");
243 QString foo2 = i18n("Show Animated Images");
244 QString foo3 = i18n("Stop Animated Images");
246 d->m_paSetEncoding = new KSelectAction( i18n( "Set &Encoding" ), 0, this, SLOT( slotSetEncoding() ), actionCollection(), "setEncoding" );
247 QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames();
248 encodings.prepend( i18n( "Auto" ) );
249 d->m_paSetEncoding->setItems( encodings );
250 d->m_paSetEncoding->setCurrentItem(0);
252 d->m_paUseStylesheet = new KSelectAction( i18n( "&Use Stylesheet"), 0, this, SLOT( slotUseStylesheet() ), actionCollection(), "useStylesheet" );
254 d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, i18n( "Increase Font Sizes" ), "viewmag+", this, SLOT( slotIncZoom() ), actionCollection(), "incFontSizes" );
255 d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, i18n( "Decrease Font Sizes" ), "viewmag-", this, SLOT( slotDecZoom() ), actionCollection(), "decFontSizes" );
257 d->m_paFind = KStdAction::find( this, SLOT( slotFind() ), actionCollection(), "find" );
259 d->m_paFind->setShortcut( KShortcut() ); // avoid clashes
261 d->m_paPrintFrame = new KAction( i18n( "Print Frame" ), "frameprint", 0, this, SLOT( slotPrintFrame() ), actionCollection(), "printFrame" );
263 d->m_paSelectAll = KStdAction::selectAll( this, SLOT( slotSelectAll() ), actionCollection(), "selectAll" );
265 d->m_paSelectAll->setShortcut( KShortcut() ); // avoid clashes
269 // set the default java(script) flags according to the current host.
270 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled();
271 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
272 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled();
273 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled();
275 // The java, javascript, and plugin settings will be set after the settings
276 // have been initialized.
277 d->m_bJScriptEnabled = true;
278 d->m_bJScriptDebugEnabled = true;
279 d->m_bJavaEnabled = true;
280 d->m_bPluginsEnabled = true;
284 connect( this, SIGNAL( completed() ),
285 this, SLOT( updateActions() ) );
286 connect( this, SIGNAL( completed( bool ) ),
287 this, SLOT( updateActions() ) );
288 connect( this, SIGNAL( started( KIO::Job * ) ),
289 this, SLOT( updateActions() ) );
291 d->m_popupMenuXML = KXMLGUIFactory::readConfigFile( locate( "data", "khtml/khtml_popupmenu.rc", KHTMLFactory::instance() ) );
294 connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
295 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
296 connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
297 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
298 connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
299 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
302 findTextBegin(); //reset find variables
305 connect( &d->m_redirectionTimer, SIGNAL( timeout() ),
306 this, SLOT( slotRedirect() ) );
308 connect(&d->m_lifeSupportTimer, SIGNAL(timeout()), this, SLOT(slotEndLifeSupport()));
311 d->m_dcopobject = new KHTMLPartIface(this);
315 KHTMLPart::~KHTMLPart()
317 //kdDebug(6050) << "KHTMLPart::~KHTMLPart " << this << endl;
319 if ( d->m_findDialog )
320 disconnect( d->m_findDialog, SIGNAL( destroyed() ),
321 this, SLOT( slotFindDialogDestroyed() ) );
325 d->m_manager->setActivePart( 0 );
326 // Shouldn't we delete d->m_manager here ? (David)
327 // No need to, I would say. We specify "this" as parent qobject
328 // in ::partManager() (Simon)
338 disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
339 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
340 disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
341 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
342 disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
343 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
350 d->m_view->viewport()->hide();
351 d->m_view->m_part = 0;
355 delete d->m_hostExtension;
359 KHTMLFactory::deregisterPart( this );
362 bool KHTMLPart::restoreURL( const KURL &url )
364 kdDebug( 6050 ) << "KHTMLPart::restoreURL " << url.url() << endl;
369 * That's not a good idea as it will call closeURL() on all
370 * child frames, preventing them from further loading. This
371 * method gets called from restoreState() in case of a full frameset
372 * restoral, and restoreState() calls closeURL() before restoring
374 kdDebug( 6050 ) << "closing old URL" << endl;
378 d->m_bComplete = false;
379 d->m_bLoadEventEmitted = false;
380 d->m_workingURL = url;
382 // set the java(script) flags according to the current host.
384 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
385 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
386 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
387 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
389 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
390 d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled();
391 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
392 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
397 KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &)));
406 bool KHTMLPart::didOpenURL(const KURL &url)
408 bool KHTMLPart::openURL( const KURL &url )
411 kdDebug( 6050 ) << "KHTMLPart(" << this << ")::openURL " << url.url() << endl;
413 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
414 // We're about to get a redirect that happened before the document was
415 // created. This can happen when one frame may change the location of a
422 // clear last edit command
423 d->m_lastEditCommand = EditCommandPtr();
425 KWQ(this)->clearUndoRedoOperations();
429 // check to see if this is an "error://" URL. This is caused when an error
430 // occurs before this part was loaded (e.g. KonqRun), and is passed to
431 // khtmlpart so that it can display the error.
432 if ( url.protocol() == "error" && url.hasSubURL() ) {
435 * The format of the error url is that two variables are passed in the query:
436 * error = int kio error code, errText = QString error text from kio
437 * and the URL where the error happened is passed as a sub URL.
439 KURL::List urls = KURL::split( url );
440 //kdDebug() << "Handling error URL. URL count:" << urls.count() << endl;
442 if ( urls.count() > 1 ) {
443 KURL mainURL = urls.first();
444 int error = mainURL.queryItem( "error" ).toInt();
445 // error=0 isn't a valid error code, so 0 means it's missing from the URL
446 if ( error == 0 ) error = KIO::ERR_UNKNOWN;
447 QString errorText = mainURL.queryItem( "errText" );
449 d->m_workingURL = KURL::join( urls );
450 //kdDebug() << "Emitting fixed URL " << d->m_workingURL.prettyURL() << endl;
451 emit d->m_extension->setLocationBarURL( d->m_workingURL.prettyURL() );
452 htmlError( error, errorText, d->m_workingURL );
456 #endif // APPLE_CHANGES
458 KParts::URLArgs args( d->m_extension->urlArgs() );
461 // in case we have a) no frameset (don't test m_frames.count(), iframes get in there)
462 // b) the url is identical with the currently
463 // displayed one (except for the htmlref!) , c) the url request is not a POST
464 // operation and d) the caller did not request to reload the page we try to
465 // be smart and instead of reloading the whole document we just jump to the
466 // request html anchor
468 bool isFrameSet = false;
469 if ( d->m_doc->isHTMLDocument() ) {
470 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
471 isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET);
474 urlcmp( url.url(), m_url.url(), true, true ) &&
475 url.hasRef() && !args.doPost() && !args.reload )
477 kdDebug( 6050 ) << "KHTMLPart::openURL, jumping to anchor. m_url = " << url.url() << endl;
483 d->m_bComplete = true;
484 d->m_doc->setParsing(false);
486 kdDebug( 6050 ) << "completed..." << endl;
491 #endif // APPLE_CHANGES
495 kdDebug( 6050 ) << "closing old URL" << endl;
500 args.metaData().insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" );
501 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" );
502 args.metaData().insert("ssl_activate_warnings", "TRUE" );
506 d->m_cachePolicy = KIO::CC_Cache;
507 else if (args.reload)
508 d->m_cachePolicy = KIO::CC_Refresh;
510 d->m_cachePolicy = KIO::CC_Verify;
512 if ( args.doPost() && (url.protocol().startsWith("http")) )
514 d->m_job = KIO::http_post( url, args.postData, false );
515 d->m_job->addMetaData("content-type", args.contentType() );
519 d->m_job = KIO::get( url, false, false );
520 d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
523 d->m_job->addMetaData(args.metaData());
525 connect( d->m_job, SIGNAL( result( KIO::Job * ) ),
526 SLOT( slotFinished( KIO::Job * ) ) );
528 connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray &)),
529 SLOT( slotData( KIO::Job*, const QByteArray &)));
532 connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KURL&) ),
533 SLOT( slotRedirection(KIO::Job*,const KURL&) ) );
535 d->m_bComplete = false;
536 d->m_bLoadingMainResource = true;
537 d->m_bLoadEventEmitted = false;
539 // delete old status bar msg's from kjs (if it _was_ activated on last URL)
540 if( d->m_bJScriptEnabled )
542 d->m_kjsStatusBarText = QString::null;
543 d->m_kjsDefaultStatusBarText = QString::null;
546 // set the javascript flags according to the current url
548 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
549 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
550 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
552 d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled();
553 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
554 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
557 // 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
558 // data arrives) (Simon)
560 if(m_url.protocol().startsWith( "http" ) && !m_url.host().isEmpty() &&
561 m_url.path().isEmpty()) {
563 emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
565 // copy to m_workingURL after fixing m_url above
566 d->m_workingURL = m_url;
568 kdDebug( 6050 ) << "KHTMLPart::openURL now (before started) m_url = " << m_url.url() << endl;
570 connect( d->m_job, SIGNAL( speed( KIO::Job*, unsigned long ) ),
571 this, SLOT( slotJobSpeed( KIO::Job*, unsigned long ) ) );
573 connect( d->m_job, SIGNAL( percent( KIO::Job*, unsigned long ) ),
574 this, SLOT( slotJobPercent( KIO::Job*, unsigned long ) ) );
581 void KHTMLPart::didExplicitOpen()
583 d->m_bComplete = false;
584 d->m_bLoadEventEmitted = false;
588 bool KHTMLPart::closeURL()
590 if (d->m_doc && d->m_doc->tokenizer()) {
591 d->m_doc->tokenizer()->stopParsing();
596 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
601 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
602 HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
604 if ( hdoc->body() && d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted ) {
605 hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false );
607 d->m_doc->updateRendering();
608 d->m_bUnloadEventEmitted = true;
612 d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
613 d->m_bLoadingMainResource = false;
614 d->m_bLoadEventEmitted = true; // don't want that one either
615 d->m_cachePolicy = KIO::CC_Verify; // Why here?
617 KHTMLPageCache::self()->cancelFetch(this);
618 if ( d->m_doc && d->m_doc->parsing() )
620 kdDebug( 6050 ) << " was still parsing... calling end " << endl;
621 slotFinishedParsing();
622 d->m_doc->setParsing(false);
625 if ( !d->m_workingURL.isEmpty() )
627 // Aborted before starting to render
628 kdDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << m_url.prettyURL() << endl;
629 emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
632 d->m_workingURL = KURL();
634 if ( d->m_doc && d->m_doc->docLoader() )
635 khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() );
637 // tell all subframes to stop as well
638 ConstFrameIt it = d->m_frames.begin();
639 ConstFrameIt end = d->m_frames.end();
640 for (; it != end; ++it )
641 if ( !( *it ).m_part.isNull() )
642 ( *it ).m_part->closeURL();
644 d->m_bPendingChildRedirection = false;
646 // Stop any started redirections as well!! (DA)
649 #if !KHTML_NO_CPLUSPLUS_DOM
650 // null node activated.
651 emit nodeActivated(Node());
657 #if !KHTML_NO_CPLUSPLUS_DOM
659 DOM::HTMLDocument KHTMLPart::htmlDocument() const
661 if (d->m_doc && d->m_doc->isHTMLDocument())
662 return static_cast<HTMLDocumentImpl*>(d->m_doc);
664 return static_cast<HTMLDocumentImpl*>(0);
667 DOM::Document KHTMLPart::document() const
674 KParts::BrowserExtension *KHTMLPart::browserExtension() const
676 return d->m_extension;
679 KHTMLView *KHTMLPart::view() const
684 void KHTMLPart::setJScriptEnabled( bool enable )
686 if ( !enable && jScriptEnabled() && d->m_jscript ) {
687 d->m_jscript->clear();
689 d->m_bJScriptForce = enable;
690 d->m_bJScriptOverride = true;
693 bool KHTMLPart::jScriptEnabled() const
695 if ( d->m_bJScriptOverride )
696 return d->m_bJScriptForce;
697 return d->m_bJScriptEnabled;
700 void KHTMLPart::setMetaRefreshEnabled( bool enable )
702 d->m_metaRefreshEnabled = enable;
705 bool KHTMLPart::metaRefreshEnabled() const
707 return d->m_metaRefreshEnabled;
710 // Define this to disable dlopening kjs_html, when directly linking to it.
711 // You need to edit khtml/Makefile.am to add ./ecma/libkjs_html.la to LIBADD
712 // and to edit khtml/ecma/Makefile.am to s/kjs_html/libkjs_html/, remove libkhtml from LIBADD,
713 // remove LDFLAGS line, and replace kde_module with either lib (shared) or noinst (static)
714 //#define DIRECT_LINKAGE_TO_ECMA
716 #ifdef DIRECT_LINKAGE_TO_ECMA
717 extern "C" { KJSProxy *kjs_html_init(KHTMLPart *khtmlpart); }
720 KJSProxy *KHTMLPart::jScript()
722 if (!jScriptEnabled()){
728 #ifndef DIRECT_LINKAGE_TO_ECMA
729 KLibrary *lib = KLibLoader::self()->library("kjs_html");
731 setJScriptEnabled( false );
734 // look for plain C init function
735 void *sym = lib->symbol("kjs_html_init");
738 setJScriptEnabled( false );
741 typedef KJSProxy* (*initFunction)(KHTMLPart *);
742 initFunction initSym = (initFunction) sym;
743 d->m_jscript = (*initSym)(this);
746 d->m_jscript = kjs_html_init(this);
747 // d->m_kjs_lib remains 0L.
749 if (d->m_bJScriptDebugEnabled)
750 d->m_jscript->setDebugEnabled(true);
756 void KHTMLPart::replaceContentsWithScriptResult( const KURL &url )
758 QString script = KURL::decode_string(url.url().mid(strlen("javascript:")));
759 QVariant ret = executeScript(script);
761 if (ret.type() == QVariant::String) {
763 write(ret.asString());
768 QVariant KHTMLPart::executeScript( const QString &script, bool forceUserGesture )
770 return executeScript( 0, script, forceUserGesture );
773 //Enable this to see all JS scripts being executed
774 //#define KJS_VERBOSE
776 #if !KHTML_NO_CPLUSPLUS_DOM
778 QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script, bool forceUserGesture )
780 return executeScript(n.handle(), script, forceUserGesture);
785 QVariant KHTMLPart::executeScript( DOM::NodeImpl *n, const QString &script, bool forceUserGesture )
788 kdDebug(6070) << "KHTMLPart::executeScript n=" << n.nodeName().string().latin1() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " << script << endl;
790 KJSProxy *proxy = jScript();
792 if (!proxy || proxy->paused())
794 d->m_runningScripts++;
795 // If forceUserGesture is true, then make the script interpreter
796 // treat it as if triggered by a user gesture even if there is no
797 // current DOM event being processed.
798 QVariant ret = proxy->evaluate( forceUserGesture ? QString::null : m_url.url(), 0, script, n );
799 d->m_runningScripts--;
800 if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
802 DocumentImpl::updateDocumentsRendering();
805 kdDebug(6070) << "KHTMLPart::executeScript - done" << endl;
810 bool KHTMLPart::scheduleScript(DOM::NodeImpl *n, const QString& script)
812 //kdDebug(6050) << "KHTMLPart::scheduleScript "<< script << endl;
814 d->scheduledScript = script;
815 d->scheduledScriptNode.reset(n);
820 QVariant KHTMLPart::executeScheduledScript()
822 if( d->scheduledScript.isEmpty() )
825 //kdDebug(6050) << "executing delayed " << d->scheduledScript << endl;
827 QVariant ret = executeScript( d->scheduledScriptNode.get(), d->scheduledScript );
828 d->scheduledScript = QString();
829 d->scheduledScriptNode.reset();
834 void KHTMLPart::setJavaEnabled( bool enable )
836 d->m_bJavaForce = enable;
837 d->m_bJavaOverride = true;
840 bool KHTMLPart::javaEnabled() const
843 if( d->m_bJavaOverride )
844 return d->m_bJavaForce;
845 return d->m_bJavaEnabled;
851 KJavaAppletContext *KHTMLPart::javaContext()
854 return d->m_javaContext;
860 KJavaAppletContext *KHTMLPart::createJavaContext()
863 if ( !d->m_javaContext ) {
865 d->m_javaContext = new KJavaAppletContext(d->m_dcopobject, this);
867 d->m_javaContext = new KJavaAppletContext(d->m_dcopobject);
868 connect( d->m_javaContext, SIGNAL(showStatus(const QString&)),
869 this, SIGNAL(setStatusBarText(const QString&)) );
870 connect( d->m_javaContext, SIGNAL(showDocument(const QString&, const QString&)),
871 this, SLOT(slotShowDocument(const QString&, const QString&)) );
875 return d->m_javaContext;
881 void KHTMLPart::setPluginsEnabled( bool enable )
883 d->m_bPluginsForce = enable;
884 d->m_bPluginsOverride = true;
887 bool KHTMLPart::pluginsEnabled() const
889 if ( d->m_bPluginsOverride )
890 return d->m_bPluginsForce;
891 return d->m_bPluginsEnabled;
896 void KHTMLPart::slotShowDocument( const QString &url, const QString &target )
898 // this is mostly copied from KHTMLPart::slotChildURLRequest. The better approach
899 // would be to put those functions into a single one.
900 khtml::ChildFrame *child = 0;
901 KParts::URLArgs args;
902 args.frameName = target;
904 QString frameName = args.frameName.lower();
905 if ( !frameName.isEmpty() )
907 if ( frameName == QString::fromLatin1( "_top" ) )
909 emit d->m_extension->openURLRequest( url, args );
912 else if ( frameName == QString::fromLatin1( "_blank" ) )
914 emit d->m_extension->createNewWindow( url, args );
917 else if ( frameName == QString::fromLatin1( "_parent" ) )
919 KParts::URLArgs newArgs( args );
920 newArgs.frameName = QString::null;
922 emit d->m_extension->openURLRequest( url, newArgs );
925 else if ( frameName != QString::fromLatin1( "_self" ) )
927 khtml::ChildFrame *_frame = recursiveFrameRequest( url, args );
931 emit d->m_extension->openURLRequest( url, args );
939 // TODO: handle child target correctly! currently the script are always executed fur the parent
940 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
941 executeScript( KURL::decode_string( url.right( url.length() - 11) ) );
946 requestObject( child, KURL(url), args );
947 } else if ( frameName==QString::fromLatin1("_self") ) // this is for embedded objects (via <object>) which want to replace the current document
949 KParts::URLArgs newArgs( args );
950 newArgs.frameName = QString::null;
951 emit d->m_extension->openURLRequest( KURL(url), newArgs );
955 #endif // APPLE_CHANGES
957 void KHTMLPart::slotDebugDOMTree()
959 if ( d->m_doc && d->m_doc->firstChild() )
960 qDebug("%s", createMarkup(d->m_doc->firstChild()).latin1());
963 void KHTMLPart::slotDebugRenderTree()
967 d->m_doc->renderer()->printTree();
971 void KHTMLPart::setAutoloadImages( bool enable )
973 if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
977 d->m_doc->docLoader()->setAutoloadImages( enable );
980 unplugActionList( "loadImages" );
983 delete d->m_paLoadImages;
984 d->m_paLoadImages = 0;
986 else if ( !d->m_paLoadImages )
987 d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), "images_display", 0, this, SLOT( slotLoadImages() ), actionCollection(), "loadImages" );
989 if ( d->m_paLoadImages ) {
990 QPtrList<KAction> lst;
991 lst.append( d->m_paLoadImages );
992 plugActionList( "loadImages", lst );
997 bool KHTMLPart::autoloadImages() const
1000 return d->m_doc->docLoader()->autoloadImages();
1005 void KHTMLPart::clear()
1007 if ( d->m_bCleared )
1009 d->m_bCleared = true;
1011 d->m_bClearing = true;
1015 ConstFrameIt it = d->m_frames.begin();
1016 ConstFrameIt end = d->m_frames.end();
1017 for(; it != end; ++it )
1019 // Stop HTMLRun jobs for frames
1021 (*it).m_run->abort();
1026 QValueList<khtml::ChildFrame>::ConstIterator it = d->m_objects.begin();
1027 QValueList<khtml::ChildFrame>::ConstIterator end = d->m_objects.end();
1028 for(; it != end; ++it )
1030 // Stop HTMLRun jobs for objects
1032 (*it).m_run->abort();
1037 findTextBegin(); // resets d->m_findNode and d->m_findPos
1040 d->m_mousePressNode.reset();
1046 // Moving past doc so that onUnload works.
1048 d->m_jscript->clear();
1053 // do not dereference the document before the jscript and view are cleared, as some destructors
1054 // might still try to access the document.
1060 d->m_decoder->deref();
1064 ConstFrameIt it = d->m_frames.begin();
1065 ConstFrameIt end = d->m_frames.end();
1066 for(; it != end; ++it )
1070 disconnectChild(&*it);
1072 partManager()->removePart( (*it).m_part );
1074 (*it).m_part->deref();
1078 d->m_frames.clear();
1081 ConstFrameIt it = d->m_objects.begin();
1082 ConstFrameIt end = d->m_objects.end();
1083 for(; it != end; ++it )
1088 partManager()->removePart( (*it).m_part );
1090 (*it).m_part->deref();
1094 d->m_objects.clear();
1097 delete d->m_javaContext;
1098 d->m_javaContext = 0;
1101 d->m_scheduledRedirection = noRedirectionScheduled;
1102 d->m_delayRedirect = 0;
1103 d->m_redirectURL = QString::null;
1104 d->m_redirectReferrer = QString::null;
1105 d->m_redirectLockHistory = true;
1106 d->m_redirectUserGesture = false;
1107 d->m_bHTTPRefresh = false;
1108 d->m_bClearing = false;
1109 d->m_frameNameId = 1;
1110 d->m_bFirstData = true;
1112 d->m_bMousePressed = false;
1114 #ifndef QT_NO_CLIPBOARD
1115 connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
1119 d->m_totalObjectCount = 0;
1120 d->m_loadedObjects = 0;
1121 d->m_jobPercent = 0;
1124 if ( !d->m_haveEncoding )
1125 d->m_encoding = QString::null;
1127 d->m_parsetime.restart();
1131 bool KHTMLPart::openFile()
1136 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
1143 void KHTMLPart::replaceDocImpl(DocumentImpl* newDoc)
1156 /*bool KHTMLPart::isSSLInUse() const
1158 return d->m_ssl_in_use;
1161 void KHTMLPart::receivedFirstData()
1163 // Leave indented one extra for easier merging.
1165 //kdDebug( 6050 ) << "begin!" << endl;
1167 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1170 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
1171 d->m_workingURL = KURL();
1173 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
1175 // When the first data arrives, the metadata has just been made available
1179 d->m_bSecurityInQuestion = false;
1180 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
1181 kdDebug(6050) << "SSL in use? " << d->m_job->queryMetaData("ssl_in_use") << endl;
1184 KHTMLPart *p = parentPart();
1185 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
1186 while (p->parentPart()) p = p->parentPart();
1188 p->d->m_paSecurity->setIcon( "halfencrypted" );
1189 p->d->m_bSecurityInQuestion = true;
1190 kdDebug(6050) << "parent setIcon half done." << endl;
1194 d->m_paSecurity->setIcon( d->m_ssl_in_use ? "encrypted" : "decrypted" );
1195 kdDebug(6050) << "setIcon " << ( d->m_ssl_in_use ? "encrypted" : "decrypted" ) << " done." << endl;
1197 // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
1199 d->m_ssl_peer_certificate = d->m_job->queryMetaData("ssl_peer_certificate");
1200 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
1201 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
1202 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
1203 d->m_ssl_cipher_desc = d->m_job->queryMetaData("ssl_cipher_desc");
1204 d->m_ssl_cipher_version = d->m_job->queryMetaData("ssl_cipher_version");
1205 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
1206 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
1207 d->m_ssl_cert_state = d->m_job->queryMetaData("ssl_cert_state");
1209 // Check for charset meta-data
1210 QString qData = d->m_job->queryMetaData("charset");
1211 if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
1212 d->m_encoding = qData;
1213 #endif // APPLE_CHANGES
1215 // Support for http-refresh
1216 qData = d->m_job->queryMetaData("http-refresh");
1217 if( !qData.isEmpty() && d->m_metaRefreshEnabled )
1219 kdDebug(6050) << "HTTP Refresh Request: " << qData << endl;
1221 int pos = qData.find( ';' );
1223 pos = qData.find( ',' );
1227 delay = qData.stripWhiteSpace().toDouble();
1229 // We want a new history item if the refresh timeout > 1 second
1230 scheduleRedirection( delay, m_url.url(), delay <= 1);
1232 scheduleRedirection( delay, m_url.url());
1237 int end_pos = qData.length();
1238 delay = qData.left(pos).stripWhiteSpace().toDouble();
1239 while ( qData[++pos] == ' ' );
1240 if ( qData.find( "url", pos, false ) == pos )
1243 while (qData[pos] == ' ' || qData[pos] == '=' )
1245 if ( qData[pos] == '"' )
1248 int index = end_pos-1;
1249 while( index > pos )
1251 if ( qData[index] == '"' )
1260 // We want a new history item if the refresh timeout > 1 second
1261 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ), delay <= 1);
1263 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ));
1266 d->m_bHTTPRefresh = true;
1269 // Support for http last-modified
1270 d->m_lastModified = d->m_job->queryMetaData("modified");
1271 //kdDebug() << "KHTMLPart::slotData metadata modified: " << d->m_lastModified << endl;
1276 void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
1278 assert ( d->m_job == kio_job );
1280 //kdDebug( 6050 ) << "slotData: " << data.size() << endl;
1282 if ( !d->m_workingURL.isEmpty() )
1283 receivedFirstData( );
1285 KHTMLPageCache::self()->addData(d->m_cacheId, data);
1286 write( data.data(), data.size() );
1289 void KHTMLPart::slotRestoreData(const QByteArray &data )
1292 if ( !d->m_workingURL.isEmpty() )
1294 long saveCacheId = d->m_cacheId;
1295 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1296 d->m_cacheId = saveCacheId;
1297 d->m_workingURL = KURL();
1300 //kdDebug( 6050 ) << "slotRestoreData: " << data.size() << endl;
1301 write( data.data(), data.size() );
1303 if (data.size() == 0)
1305 //kdDebug( 6050 ) << "slotRestoreData: <<end of data>>" << endl;
1307 if (d->m_doc && d->m_doc->parsing())
1308 end(); //will emit completed()
1312 void KHTMLPart::showError( KIO::Job* job )
1314 kdDebug() << "KHTMLPart::showError d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
1315 << " d->m_bCleared=" << d->m_bCleared << endl;
1317 if (job->error() == KIO::ERR_NO_CONTENT)
1320 if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
1321 job->showErrorDialog( /*d->m_view*/ );
1324 htmlError( job->error(), job->errorText(), d->m_workingURL );
1328 // This is a protected method, placed here because of it's relevance to showError
1329 void KHTMLPart::htmlError( int errorCode, const QString& text, const KURL& reqUrl )
1331 kdDebug(6050) << "KHTMLPart::htmlError errorCode=" << errorCode << " text=" << text << endl;
1332 // make sure we're not executing any embedded JS
1333 bool bJSFO = d->m_bJScriptForce;
1334 bool bJSOO = d->m_bJScriptOverride;
1335 d->m_bJScriptForce = false;
1336 d->m_bJScriptOverride = true;
1338 QString errText = QString::fromLatin1( "<HTML><HEAD><TITLE>" );
1339 errText += i18n( "Error while loading %1" ).arg( reqUrl.htmlURL() );
1340 errText += QString::fromLatin1( "</TITLE></HEAD><BODY><P>" );
1341 errText += i18n( "An error occured while loading <B>%1</B>:" ).arg( reqUrl.htmlURL() );
1342 errText += QString::fromLatin1( "</P><P>" );
1343 QString kioErrString = KIO::buildErrorString( errorCode, text );
1345 kioErrString.replace(QRegExp("&"), QString("&"));
1346 kioErrString.replace(QRegExp("<"), QString("<"));
1347 kioErrString.replace(QRegExp(">"), QString(">"));
1349 // In case the error string has '\n' in it, replace with <BR/>
1350 kioErrString.replace( QRegExp("\n"), "<BR/>" );
1352 errText += kioErrString;
1353 errText += QString::fromLatin1( "</P></BODY></HTML>" );
1357 d->m_bJScriptForce = bJSFO;
1358 d->m_bJScriptOverride = bJSOO;
1360 // make the working url the current url, so that reload works and
1361 // emit the progress signals to advance one step in the history
1362 // (so that 'back' works)
1363 m_url = reqUrl; // same as d->m_workingURL
1364 d->m_workingURL = KURL();
1368 // following disabled until 3.1
1370 QString errorName, techName, description;
1371 QStringList causes, solutions;
1373 QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
1374 QDataStream stream(raw, IO_ReadOnly);
1376 stream >> errorName >> techName >> description >> causes >> solutions;
1378 QString url, protocol, datetime;
1379 url = reqUrl.prettyURL();
1380 protocol = reqUrl.protocol();
1381 datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
1384 QString doc = QString::fromLatin1( "<html><head><title>" );
1385 doc += i18n( "Error: " );
1387 doc += QString::fromLatin1( " - %1</title></head><body><h1>" ).arg( url );
1388 doc += i18n( "The requested operation could not be completed" );
1389 doc += QString::fromLatin1( "</h1><h2>" );
1391 doc += QString::fromLatin1( "</h2>" );
1392 if ( techName != QString::null ) {
1393 doc += QString::fromLatin1( "<h2>" );
1394 doc += i18n( "Technical Reason: " );
1396 doc += QString::fromLatin1( "</h2>" );
1398 doc += QString::fromLatin1( "<h3>" );
1399 doc += i18n( "Details of the Request:" );
1400 doc += QString::fromLatin1( "</h3><ul><li>" );
1401 doc += i18n( "URL: %1" ).arg( url );
1402 doc += QString::fromLatin1( "</li><li>" );
1403 if ( protocol != QString::null ) {
1404 // uncomment for 3.1... i18n change
1405 // doc += i18n( "Protocol: %1" ).arg( protocol ).arg( protocol );
1406 doc += QString::fromLatin1( "</li><li>" );
1408 doc += i18n( "Date and Time: %1" ).arg( datetime );
1409 doc += QString::fromLatin1( "</li><li>" );
1410 doc += i18n( "Additional Information: %1" ).arg( text );
1411 doc += QString::fromLatin1( "</li></ul><h3>" );
1412 doc += i18n( "Description:" );
1413 doc += QString::fromLatin1( "</h3><p>" );
1415 doc += QString::fromLatin1( "</p>" );
1416 if ( causes.count() ) {
1417 doc += QString::fromLatin1( "<h3>" );
1418 doc += i18n( "Possible Causes:" );
1419 doc += QString::fromLatin1( "</h3><ul><li>" );
1420 doc += causes.join( "</li><li>" );
1421 doc += QString::fromLatin1( "</li></ul>" );
1423 if ( solutions.count() ) {
1424 doc += QString::fromLatin1( "<h3>" );
1425 doc += i18n( "Possible Solutions:" );
1426 doc += QString::fromLatin1( "</h3><ul><li>" );
1427 doc += solutions.join( "</li><li>" );
1428 doc += QString::fromLatin1( "</li></ul>" );
1430 doc += QString::fromLatin1( "</body></html>" );
1438 void KHTMLPart::slotFinished( KIO::Job * job )
1442 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
1445 emit canceled( job->errorString() );
1447 // TODO: what else ?
1454 //kdDebug( 6050 ) << "slotFinished" << endl;
1456 KHTMLPageCache::self()->endData(d->m_cacheId);
1458 if ( d->m_doc && d->m_doc->docLoader()->expireDate() && m_url.protocol().lower().startsWith("http"))
1459 KIO::http_update_cache(m_url, false, d->m_doc->docLoader()->expireDate());
1461 d->m_workingURL = KURL();
1464 if (d->m_doc->parsing())
1465 end(); //will emit completed()
1469 void KHTMLPart::childBegin()
1471 // We need to do this when the child is created so as to avoid the bogus state of the parent's
1472 // child->m_bCompleted being false but the child's m_bComplete being true. If the child gets
1473 // an error early on, we had trouble where checkingComplete on the child was a NOP because
1474 // it thought it was already complete, and thus the parent was never signaled, and never set
1475 // its child->m_bComplete.
1476 d->m_bComplete = false;
1480 void KHTMLPart::begin( const KURL &url, int xOffset, int yOffset )
1483 // If we aren't loading an actual URL, then we need to make sure
1484 // that we have at least an empty document. createEmptyDocument will
1485 // do that if we don't have a document already.
1486 if (d->m_workingURL.isEmpty()) {
1487 KWQ(this)->createEmptyDocument();
1494 KWQ(this)->partClearedInBegin();
1497 // Only do this after clearing the part, so that JavaScript can
1498 // clean up properly if it was on for the last load.
1500 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
1502 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
1505 d->m_bCleared = false;
1507 d->m_bComplete = false;
1508 d->m_bLoadEventEmitted = false;
1509 d->m_bLoadingMainResource = true;
1513 KHTMLFactory::vLinks()->insert( KWQ(this)->requestedURLString() );
1515 QString urlString = url.url();
1516 KHTMLFactory::vLinks()->insert( urlString );
1517 QString urlString2 = url.prettyURL();
1518 if ( urlString != urlString2 ) {
1519 KHTMLFactory::vLinks()->insert( urlString2 );
1527 KParts::URLArgs args( d->m_extension->urlArgs() );
1528 args.xOffset = xOffset;
1529 args.yOffset = yOffset;
1530 d->m_extension->setURLArgs( args );
1533 ref.setUser(QSTRING_NULL);
1534 ref.setPass(QSTRING_NULL);
1535 ref.setRef(QSTRING_NULL);
1536 d->m_referrer = ref.url();
1541 // We don't need KDE chained URI handling or window caption setting
1542 if ( !m_url.isEmpty() )
1547 if ( !m_url.isEmpty() )
1549 KURL::List lst = KURL::split( m_url );
1550 if ( !lst.isEmpty() )
1551 baseurl = *lst.begin();
1553 KURL title( baseurl );
1554 title.setRef( QString::null );
1555 title.setQuery( QString::null );
1556 emit setWindowCaption( title.url() );
1559 emit setWindowCaption( i18n( "no title", "* Unknown *" ) );
1562 if (args.serviceType == "text/xml" || args.serviceType == "application/xml" || args.serviceType == "application/xhtml+xml" ||
1563 args.serviceType == "text/xsl" || args.serviceType == "application/rss+xml" || args.serviceType == "application/atom+xml")
1564 d->m_doc = DOMImplementationImpl::instance()->createDocument( d->m_view );
1566 d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
1569 if (!d->m_doc->attached())
1570 d->m_doc->attach( );
1571 d->m_doc->setURL( m_url.url() );
1572 // We prefer m_baseURL over m_url because m_url changes when we are
1573 // about to load a new page.
1574 d->m_doc->setBaseURL( baseurl.url() );
1577 d->m_doc->setDecoder(d->m_decoder);
1580 d->m_doc->docLoader()->setShowAnimations( KHTMLFactory::defaultHTMLSettings()->showAnimations() );
1582 d->m_doc->docLoader()->setShowAnimations( d->m_settings->showAnimations() );
1586 KWQ(this)->updatePolicyBaseURL();
1590 d->m_paUseStylesheet->setItems(QStringList());
1591 d->m_paUseStylesheet->setEnabled( false );
1595 setAutoloadImages( KHTMLFactory::defaultHTMLSettings()->autoLoadImages() );
1596 QString userStyleSheet = KHTMLFactory::defaultHTMLSettings()->userStyleSheet();
1598 setAutoloadImages( d->m_settings->autoLoadImages() );
1599 QString userStyleSheet = d->m_settings->userStyleSheet();
1602 if ( !userStyleSheet.isEmpty() )
1603 setUserStyleSheet( KURL( userStyleSheet ) );
1606 KWQ(this)->restoreDocumentState();
1608 d->m_doc->setRestoreState(args.docState);
1611 d->m_doc->implicitOpen();
1614 d->m_view->resizeContents( 0, 0 );
1615 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
1618 emit d->m_extension->enableAction( "print", true );
1622 void KHTMLPart::write( const char *str, int len )
1624 if ( !d->m_decoder ) {
1625 d->m_decoder = new Decoder;
1626 if (!d->m_encoding.isNull())
1627 d->m_decoder->setEncoding(d->m_encoding.latin1(),
1628 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
1630 // Inherit the default encoding from the parent frame if there is one.
1631 const char *defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
1632 ? parentPart()->d->m_decoder->encoding() : settings()->encoding().latin1();
1633 d->m_decoder->setEncoding(defaultEncoding, Decoder::DefaultEncoding);
1637 d->m_doc->setDecoder(d->m_decoder);
1644 len = strlen( str );
1646 QString decoded = d->m_decoder->decode( str, len );
1648 if(decoded.isEmpty()) return;
1650 if(d->m_bFirstData) {
1651 // determine the parse mode
1652 d->m_doc->determineParseMode( decoded );
1653 d->m_bFirstData = false;
1655 //kdDebug(6050) << "KHTMLPart::write haveEnc = " << d->m_haveEncoding << endl;
1656 // ### this is still quite hacky, but should work a lot better than the old solution
1657 if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
1658 d->m_doc->recalcStyle( NodeImpl::Force );
1662 jScript()->appendSourceFile(m_url.url(),decoded);
1663 Tokenizer* t = d->m_doc->tokenizer();
1666 t->write( decoded, true );
1669 void KHTMLPart::write( const QString &str )
1674 if(d->m_bFirstData) {
1675 // determine the parse mode
1676 d->m_doc->setParseMode( DocumentImpl::Strict );
1677 d->m_bFirstData = false;
1680 jScript()->appendSourceFile(m_url.url(),str);
1681 Tokenizer* t = d->m_doc->tokenizer();
1683 t->write( str, true );
1686 void KHTMLPart::end()
1688 d->m_bLoadingMainResource = false;
1692 void KHTMLPart::endIfNotLoading()
1694 if (d->m_bLoadingMainResource)
1697 // make sure nothing's left in there...
1699 write(d->m_decoder->flush());
1701 d->m_doc->finishParsing();
1703 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
1704 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1705 // become true. An example is when a subframe is a pure text doc, and that subframe is the
1706 // last one to complete.
1710 void KHTMLPart::stop()
1712 // make sure nothing's left in there...
1713 Tokenizer* t = d->m_doc ? d->m_doc->tokenizer() : 0;
1717 d->m_doc->finishParsing();
1719 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
1720 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1721 // become true. An example is when a subframe is a pure text doc, and that subframe is the
1722 // last one to complete.
1728 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
1730 if (!d->m_view) return;
1731 d->m_view->paint(p, rc, yOff, more);
1736 void KHTMLPart::stopAnimations()
1739 d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
1741 ConstFrameIt it = d->m_frames.begin();
1742 ConstFrameIt end = d->m_frames.end();
1743 for (; it != end; ++it )
1744 if ( !( *it ).m_part.isNull() && ( *it ).m_part->inherits( "KHTMLPart" ) ) {
1745 KParts::ReadOnlyPart* p = ( *it ).m_part;
1746 static_cast<KHTMLPart*>( p )->stopAnimations();
1750 void KHTMLPart::gotoAnchor()
1752 if (m_url.hasRef()) {
1753 QString ref = m_url.encodedHtmlRef();
1754 if (!gotoAnchor(ref)) {
1755 // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
1756 // Decoding here has to match encoding in completeURL, which means it has to use the
1757 // page's encoding rather than UTF-8.
1760 gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()->mibEnum()));
1762 gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()));
1768 void KHTMLPart::slotFinishedParsing()
1770 d->m_doc->setParsing(false);
1773 return; // We are probably being destructed.
1778 return; // We are being destroyed by something checkCompleted called.
1780 // check if the scrollbars are really needed for the content
1781 // if not, remove them, relayout, and repaint
1783 d->m_view->restoreScrollBar();
1787 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
1790 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1791 KHTMLPart* p = this;
1794 p->d->m_totalObjectCount++;
1795 p = p->parentPart();
1796 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount )
1797 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1803 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
1806 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1807 KHTMLPart* p = this;
1810 p->d->m_loadedObjects++;
1811 p = p->parentPart();
1812 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount && d->m_jobPercent >= 100 )
1813 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1817 // We really only need to call checkCompleted when our own resources are done loading.
1818 // So we should check that d->m_doc->docLoader() == dl here.
1819 // That might help with performance by skipping some unnecessary work, but it's too
1820 // risky to make that change right now (2005-02-07), because we might be accidentally
1821 // depending on the extra checkCompleted calls.
1829 void KHTMLPart::slotProgressUpdate()
1832 if ( d->m_loadedObjects < d->m_totalObjectCount )
1833 percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
1835 percent = d->m_jobPercent;
1837 if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
1838 emit d->m_extension->infoMessage( i18n( "%1 of 1 Image loaded", "%1 of %n Images loaded", d->m_totalObjectCount ).arg( d->m_loadedObjects ) );
1840 emit d->m_extension->loadingProgress( percent );
1843 void KHTMLPart::slotJobSpeed( KIO::Job* /*job*/, unsigned long speed )
1845 emit d->m_extension->speedProgress( speed );
1848 void KHTMLPart::slotJobPercent( KIO::Job* /*job*/, unsigned long percent )
1850 d->m_jobPercent = percent;
1852 if ( !parentPart() )
1853 QTimer::singleShot( 0, this, SLOT( slotProgressUpdate() ) );
1858 void KHTMLPart::checkCompleted()
1860 // kdDebug( 6050 ) << "KHTMLPart::checkCompleted() parsing: " << d->m_doc->parsing() << endl;
1861 // kdDebug( 6050 ) << " complete: " << d->m_bComplete << endl;
1864 // restore the cursor position
1865 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
1867 if (d->m_focusNodeNumber >= 0)
1868 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
1870 d->m_doc->setFocusNode(0);
1871 d->m_focusNodeRestored = true;
1875 // Any frame that hasn't completed yet ?
1876 ConstFrameIt it = d->m_frames.begin();
1877 ConstFrameIt end = d->m_frames.end();
1878 for (; it != end; ++it )
1879 if ( !(*it).m_bCompleted )
1882 // Have we completed before?
1883 if ( d->m_bComplete )
1886 // Are we still parsing?
1887 if ( d->m_doc && d->m_doc->parsing() )
1890 // Still waiting for images/scripts from the loader ?
1892 if ( d->m_doc && d->m_doc->docLoader() )
1893 requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
1899 // Now do what should be done when we are really completed.
1900 d->m_bComplete = true;
1902 checkEmitLoadEvent(); // if we didn't do it before
1905 // check that the view has not been moved by the user
1906 if ( !m_url.hasRef() && d->m_view->contentsY() == 0 )
1907 d->m_view->setContentsPos( d->m_extension->urlArgs().xOffset,
1908 d->m_extension->urlArgs().yOffset );
1911 if ( d->m_scheduledRedirection != noRedirectionScheduled )
1913 // Do not start redirection for frames here! That action is
1914 // deferred until the parent emits a completed signal.
1915 if ( parentPart() == 0 )
1916 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1918 emit completed( true );
1922 if ( d->m_bPendingChildRedirection )
1923 emit completed ( true );
1929 // find the alternate stylesheets
1932 sheets = d->m_doc->availableStyleSheets();
1933 d->m_paUseStylesheet->setItems( sheets );
1934 d->m_paUseStylesheet->setEnabled( !sheets.isEmpty() );
1935 if (!sheets.isEmpty())
1937 d->m_paUseStylesheet->setCurrentItem(kMax(sheets.findIndex(d->m_sheetUsed), 0));
1938 slotUseStylesheet();
1942 emit setStatusBarText(i18n("Done."));
1946 kdDebug(6050) << "DONE: " <<d->m_parsetime.elapsed() << endl;
1950 void KHTMLPart::checkEmitLoadEvent()
1952 if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
1954 ConstFrameIt it = d->m_frames.begin();
1955 ConstFrameIt end = d->m_frames.end();
1956 for (; it != end; ++it )
1957 if ( !(*it).m_bCompleted ) // still got a frame running -> too early
1961 // All frames completed -> set their domain to the frameset's domain
1962 // This must only be done when loading the frameset initially (#22039),
1963 // not when following a link in a frame (#44162).
1966 DOMString domain = d->m_doc->domain();
1967 ConstFrameIt it = d->m_frames.begin();
1968 ConstFrameIt end = d->m_frames.end();
1969 for (; it != end; ++it )
1971 KParts::ReadOnlyPart *p = (*it).m_part;
1972 if ( p && p->inherits( "KHTMLPart" ))
1974 KHTMLPart* htmlFrame = static_cast<KHTMLPart *>(p);
1975 if (htmlFrame->d->m_doc)
1977 kdDebug() << "KHTMLPart::checkCompleted setting frame domain to " << domain.string() << endl;
1978 htmlFrame->d->m_doc->setDomain( domain );
1984 d->m_bLoadEventEmitted = true;
1985 d->m_bUnloadEventEmitted = false;
1987 d->m_doc->implicitClose();
1990 const KHTMLSettings *KHTMLPart::settings() const
1992 return d->m_settings;
1995 #ifndef KDE_NO_COMPAT
1996 KURL KHTMLPart::baseURL() const
1998 if ( !d->m_doc ) return KURL();
2000 return d->m_doc->baseURL();
2003 QString KHTMLPart::baseTarget() const
2005 if ( !d->m_doc ) return QString::null;
2007 return d->m_doc->baseTarget();
2011 KURL KHTMLPart::completeURL( const QString &url )
2013 if ( !d->m_doc ) return url;
2017 return KURL(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
2020 return KURL( d->m_doc->completeURL( url ) );
2023 void KHTMLPart::scheduleRedirection( double delay, const QString &url, bool doLockHistory)
2025 kdDebug(6050) << "KHTMLPart::scheduleRedirection delay=" << delay << " url=" << url << endl;
2026 if (delay < 0 || delay > INT_MAX / 1000)
2028 if ( d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect )
2030 d->m_scheduledRedirection = redirectionScheduled;
2031 d->m_delayRedirect = delay;
2032 d->m_redirectURL = url;
2033 d->m_redirectReferrer = QString::null;
2034 d->m_redirectLockHistory = doLockHistory;
2035 d->m_redirectUserGesture = false;
2037 d->m_redirectionTimer.stop();
2038 if ( d->m_bComplete )
2039 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
2043 void KHTMLPart::scheduleLocationChange(const QString &url, const QString &referrer, bool lockHistory, bool userGesture)
2045 // Handle a location change of a page with no document as a special case.
2046 // This may happen when a frame changes the location of another frame.
2047 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
2048 d->m_delayRedirect = 0;
2049 d->m_redirectURL = url;
2050 d->m_redirectReferrer = referrer;
2051 d->m_redirectLockHistory = lockHistory;
2052 d->m_redirectUserGesture = userGesture;
2053 d->m_redirectionTimer.stop();
2055 d->m_redirectionTimer.start(0, true);
2058 bool KHTMLPart::isScheduledLocationChangePending() const
2060 switch (d->m_scheduledRedirection) {
2061 case noRedirectionScheduled:
2062 case redirectionScheduled:
2064 case historyNavigationScheduled:
2065 case locationChangeScheduled:
2066 case locationChangeScheduledDuringLoad:
2072 void KHTMLPart::scheduleHistoryNavigation( int steps )
2075 // navigation will always be allowed in the 0 steps case, which is OK because
2076 // that's supposed to force a reload.
2077 if (!KWQ(this)->canGoBackOrForward(steps)) {
2078 cancelRedirection();
2083 d->m_scheduledRedirection = historyNavigationScheduled;
2084 d->m_delayRedirect = 0;
2085 d->m_redirectURL = QString::null;
2086 d->m_redirectReferrer = QString::null;
2087 d->m_scheduledHistoryNavigationSteps = steps;
2088 d->m_redirectionTimer.stop();
2090 d->m_redirectionTimer.start(0, true);
2093 void KHTMLPart::cancelRedirection(bool cancelWithLoadInProgress)
2096 d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
2097 d->m_scheduledRedirection = noRedirectionScheduled;
2098 d->m_redirectionTimer.stop();
2102 void KHTMLPart::slotRedirect()
2104 if (d->m_scheduledRedirection == historyNavigationScheduled) {
2105 d->m_scheduledRedirection = noRedirectionScheduled;
2107 // Special case for go(0) from a frame -> reload only the frame
2108 // go(i!=0) from a frame navigates into the history of the frame only,
2109 // in both IE and NS (but not in Mozilla).... we can't easily do that
2111 if (d->m_scheduledHistoryNavigationSteps == 0) // add && parentPart() to get only frames, but doesn't matter
2112 openURL( url() ); /// ## need args.reload=true?
2114 if (d->m_extension) {
2115 BrowserInterface *interface = d->m_extension->browserInterface();
2117 interface->callMethod( "goHistory(int)", d->m_scheduledHistoryNavigationSteps );
2123 QString u = d->m_redirectURL;
2125 d->m_scheduledRedirection = noRedirectionScheduled;
2126 d->m_delayRedirect = 0;
2127 d->m_redirectURL = QString::null;
2128 if ( u.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
2130 QString script = KURL::decode_string( u.right( u.length() - 11 ) );
2131 //kdDebug( 6050 ) << "KHTMLPart::slotRedirect script=" << script << endl;
2132 QVariant res = executeScript( script, d->m_redirectUserGesture );
2133 if ( res.type() == QVariant::String ) {
2135 write( res.asString() );
2140 KParts::URLArgs args;
2141 if ( urlcmp( u, m_url.url(), true, false ) )
2144 args.setLockHistory( d->m_redirectLockHistory );
2145 if (!d->m_redirectReferrer.isEmpty())
2146 args.metaData()["referrer"] = d->m_redirectReferrer;
2147 d->m_redirectReferrer = QString::null;
2149 urlSelected( u, 0, 0, "_self", args );
2152 void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url)
2154 // the slave told us that we got redirected
2155 // kdDebug( 6050 ) << "redirection by KIO to " << url.url() << endl;
2156 emit d->m_extension->setLocationBarURL( url.prettyURL() );
2157 d->m_workingURL = url;
2162 bool KHTMLPart::setEncoding( const QString &name, bool override )
2164 d->m_encoding = name;
2165 d->m_haveEncoding = override;
2167 if( !m_url.isEmpty() ) {
2172 d->m_restored = true;
2174 d->m_restored = false;
2182 QString KHTMLPart::encoding() const
2184 if(d->m_haveEncoding && !d->m_encoding.isEmpty())
2185 return d->m_encoding;
2187 if(d->m_decoder && d->m_decoder->encoding())
2188 return QString(d->m_decoder->encoding());
2190 return(settings()->encoding());
2193 void KHTMLPart::setUserStyleSheet(const KURL &url)
2195 if ( d->m_doc && d->m_doc->docLoader() )
2196 (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
2199 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
2202 d->m_doc->setUserStyleSheet( styleSheet );
2205 bool KHTMLPart::gotoAnchor( const QString &name )
2210 NodeImpl *n = d->m_doc->getElementById(name);
2212 HTMLCollectionImpl *anchors =
2213 new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
2215 n = anchors->namedItem(name, !d->m_doc->inCompatMode());
2219 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
2221 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2222 if (!n && !(name.isEmpty() || name.lower() == "top")) {
2223 kdDebug(6050) << "KHTMLPart::gotoAnchor node '" << name << "' not found" << endl;
2227 // We need to update the layout before scrolling, otherwise we could
2228 // really mess things up if an anchor scroll comes at a bad moment.
2230 d->m_doc->updateRendering();
2231 // Only do a layout if changes have occurred that make it necessary.
2232 if ( d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() ) {
2233 d->m_view->layout();
2239 static_cast<HTMLElementImpl *>(n)->getUpperLeftCorner(x, y);
2241 // Scroll to actual top left of element with no slop, since some pages expect anchors to be exactly scrolled to.
2243 // Call recursive version so this will expose correctly from within nested frames.
2244 d->m_view->setContentsPosRecursive(x, y);
2246 d->m_view->setContentsPos(x, y);
2252 void KHTMLPart::setStandardFont( const QString &name )
2254 d->m_settings->setStdFontName(name);
2257 void KHTMLPart::setFixedFont( const QString &name )
2259 d->m_settings->setFixedFontName(name);
2264 void KHTMLPart::setURLCursor( const QCursor &c )
2266 d->m_linkCursor = c;
2271 QCursor KHTMLPart::urlCursor() const
2274 // Don't load the link cursor until it's actually used.
2275 // Also, we don't need setURLCursor.
2276 // This speeds up startup time.
2277 return KCursor::handCursor();
2279 return d->m_linkCursor;
2283 bool KHTMLPart::onlyLocalReferences() const
2285 return d->m_onlyLocalReferences;
2288 void KHTMLPart::setOnlyLocalReferences(bool enable)
2290 d->m_onlyLocalReferences = enable;
2295 void KHTMLPart::findTextBegin(NodeImpl *startNode, int startPos)
2297 d->m_findPos = startPos;
2298 d->m_findNode = startNode;
2301 bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensitive, bool isRegExp )
2306 if(!d->m_findNode) {
2307 if (d->m_doc->isHTMLDocument())
2308 d->m_findNode = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
2310 d->m_findNode = d->m_doc;
2313 if ( !d->m_findNode )
2315 kdDebug() << "KHTMLPart::findTextNext no findNode -> return false" << endl;
2318 if ( d->m_findNode->id() == ID_FRAMESET )
2320 kdDebug() << "KHTMLPart::findTextNext FRAMESET -> return false" << endl;
2326 if( (d->m_findNode->nodeType() == Node::TEXT_NODE || d->m_findNode->nodeType() == Node::CDATA_SECTION_NODE) && d->m_findNode->renderer() )
2328 DOMString nodeText = d->m_findNode->nodeValue();
2329 DOMStringImpl *t = nodeText.implementation();
2330 QConstString s(t->s, t->l);
2334 QRegExp matcher( str );
2335 matcher.setCaseSensitive( caseSensitive );
2336 d->m_findPos = matcher.search(s.string(), d->m_findPos+1);
2337 if ( d->m_findPos != -1 )
2338 matchLen = matcher.matchedLength();
2341 d->m_findPos = s.string().find(str, d->m_findPos+1, caseSensitive);
2342 matchLen = str.length();
2345 if(d->m_findPos != -1)
2348 static_cast<khtml::RenderText *>(d->m_findNode->renderer())
2349 ->posOfChar(d->m_findPos, x, y);
2350 d->m_view->setContentsPos(x-50, y-50);
2351 Position p1(d->m_findNode, d->m_findPos);
2352 Position p2(d->m_findNode, d->m_findPos + matchLen);
2353 setSelection(Selection(p1, khtml::DOWNSTREAM, p2, khtml::SEL_PREFER_UPSTREAM_AFFINITY));
2363 next = d->m_findNode->firstChild();
2365 if(!next) next = d->m_findNode->nextSibling();
2366 while(d->m_findNode && !next) {
2367 d->m_findNode = d->m_findNode->parentNode();
2368 if( d->m_findNode ) {
2369 next = d->m_findNode->nextSibling();
2375 next = d->m_findNode->lastChild();
2377 if (!next ) next = d->m_findNode->previousSibling();
2378 while ( d->m_findNode && !next )
2380 d->m_findNode = d->m_findNode->parentNode();
2383 next = d->m_findNode->previousSibling();
2388 d->m_findNode = next;
2389 if(!d->m_findNode) return false;
2393 #endif // APPLE_CHANGES
2395 #if !KHTML_NO_CPLUSPLUS_DOM
2397 QString KHTMLPart::text(const DOM::Range &r) const
2399 return plainText(r.handle());
2404 QString KHTMLPart::selectedText() const
2406 return plainText(selection().toRange().get());
2409 bool KHTMLPart::hasSelection() const
2411 return d->m_selection.isCaretOrRange();
2414 const Selection &KHTMLPart::selection() const
2416 return d->m_selection;
2419 ETextGranularity KHTMLPart::selectionGranularity() const
2421 return d->m_selectionGranularity;
2424 void KHTMLPart::setSelectionGranularity(ETextGranularity granularity) const
2426 d->m_selectionGranularity = granularity;
2429 const Selection &KHTMLPart::dragCaret() const
2431 return d->m_dragCaret;
2434 const Selection &KHTMLPart::mark() const
2439 void KHTMLPart::setMark(const Selection &s)
2444 void KHTMLPart::setSelection(const Selection &s, bool closeTyping, bool keepTypingStyle)
2446 if (d->m_selection == s) {
2450 clearCaretRectIfNeeded();
2453 Selection oldSelection = d->m_selection;
2458 setFocusNodeIfNeeded();
2460 selectionLayoutChanged();
2462 // Always clear the x position used for vertical arrow navigation.
2463 // It will be restored by the vertical arrow navigation code if necessary.
2464 d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
2467 TypingCommand::closeTyping(lastEditCommand());
2469 if (!keepTypingStyle)
2473 KWQ(this)->respondToChangedSelection(oldSelection, closeTyping);
2476 emitSelectionChanged();
2479 void KHTMLPart::setDragCaret(const Selection &dragCaret)
2481 if (d->m_dragCaret != dragCaret) {
2482 d->m_dragCaret.needsCaretRepaint();
2483 d->m_dragCaret = dragCaret;
2484 d->m_dragCaret.needsCaretRepaint();
2488 void KHTMLPart::clearSelection()
2490 setSelection(Selection());
2493 void KHTMLPart::invalidateSelection()
2495 clearCaretRectIfNeeded();
2496 d->m_selection.setNeedsLayout();
2497 selectionLayoutChanged();
2500 void KHTMLPart::setCaretVisible(bool flag)
2502 if (d->m_caretVisible == flag)
2504 clearCaretRectIfNeeded();
2506 setFocusNodeIfNeeded();
2507 d->m_caretVisible = flag;
2508 selectionLayoutChanged();
2512 void KHTMLPart::slotClearSelection()
2518 void KHTMLPart::clearCaretRectIfNeeded()
2520 if (d->m_caretPaint) {
2521 d->m_caretPaint = false;
2522 d->m_selection.needsCaretRepaint();
2526 // Helper function that tells whether a particular node is an element that has an entire
2527 // KHTMLPart and KHTMLView, a <frame>, <iframe>, or <object>.
2528 static bool isFrame(const NodeImpl *n)
2532 RenderObject *renderer = n->renderer();
2533 if (!renderer || !renderer->isWidget())
2535 QWidget *widget = static_cast<RenderWidget *>(renderer)->widget();
2536 return widget && widget->inherits("KHTMLView");
2539 void KHTMLPart::setFocusNodeIfNeeded()
2541 if (!xmlDocImpl() || d->m_selection.isNone() || !d->m_isFocused)
2544 NodeImpl *n = d->m_selection.start().node();
2545 NodeImpl *target = (n && n->isContentEditable()) ? n : 0;
2547 while (n && n != d->m_selection.end().node()) {
2548 if (n->isContentEditable()) {
2552 n = n->traverseNextNode();
2555 assert(target == 0 || target->isContentEditable());
2558 for ( ; target; target = target->parentNode()) {
2559 // We don't want to set focus on a subframe when selecting in a parent frame,
2560 // so add the !isFrame check here. There's probably a better way to make this
2561 // work in the long term, but this is the safest fix at this time.
2562 if (target->isMouseFocusable() && !isFrame(target)) {
2563 xmlDocImpl()->setFocusNode(target);
2567 xmlDocImpl()->setFocusNode(0);
2571 void KHTMLPart::selectionLayoutChanged()
2573 // kill any caret blink timer now running
2574 if (d->m_caretBlinkTimer >= 0) {
2575 killTimer(d->m_caretBlinkTimer);
2576 d->m_caretBlinkTimer = -1;
2579 // see if a new caret blink timer needs to be started
2580 if (d->m_caretVisible && d->m_caretBlinks &&
2581 d->m_selection.isCaret() && d->m_selection.start().node()->isContentEditable()) {
2582 d->m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
2583 d->m_caretPaint = true;
2584 d->m_selection.needsCaretRepaint();
2588 d->m_doc->updateSelection();
2591 void KHTMLPart::setXPosForVerticalArrowNavigation(int x)
2593 d->m_xPosForVerticalArrowNavigation = x;
2596 int KHTMLPart::xPosForVerticalArrowNavigation() const
2598 return d->m_xPosForVerticalArrowNavigation;
2601 void KHTMLPart::timerEvent(QTimerEvent *e)
2603 if (e->timerId() == d->m_caretBlinkTimer &&
2604 d->m_caretVisible &&
2606 d->m_selection.isCaret()) {
2607 if (d->m_bMousePressed) {
2608 if (!d->m_caretPaint) {
2609 d->m_caretPaint = true;
2610 d->m_selection.needsCaretRepaint();
2614 d->m_caretPaint = !d->m_caretPaint;
2615 d->m_selection.needsCaretRepaint();
2620 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
2622 if (d->m_caretPaint)
2623 d->m_selection.paintCaret(p, rect);
2626 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
2628 d->m_dragCaret.paintCaret(p, rect);
2633 void KHTMLPart::overURL( const QString &url, const QString &target, bool shiftPressed )
2635 if ( !d->m_kjsStatusBarText.isEmpty() && !shiftPressed ) {
2637 emit setStatusBarText( d->m_kjsStatusBarText );
2638 d->m_kjsStatusBarText = QString::null;
2644 if ( url.isEmpty() )
2646 emit setStatusBarText(completeURL(url).htmlURL());
2650 if (url.find( QString::fromLatin1( "javascript:" ),0, false ) != -1 )
2652 emit setStatusBarText( KURL::decode_string( url.mid( url.find( "javascript:", 0, false ) ) ) );
2656 KURL u = completeURL(url);
2658 // special case for <a href="">
2659 if ( url.isEmpty() )
2660 u.setFileName( url );
2664 KMimeType::Ptr typ = KMimeType::findByURL( u );
2667 com = typ->comment( u, false );
2669 if ( u.isMalformed() )
2671 emit setStatusBarText(u.htmlURL());
2675 if ( u.isLocalFile() )
2677 // TODO : use KIO::stat() and create a KFileItem out of its result,
2678 // to use KFileItem::statusBarText()
2679 QCString path = QFile::encodeName( u.path() );
2682 bool ok = !stat( path.data(), &buff );
2685 if (ok) ok = !lstat( path.data(), &lbuff );
2687 QString text = u.htmlURL();
2688 QString text2 = text;
2690 if (ok && S_ISLNK( lbuff.st_mode ) )
2694 tmp = i18n( "Symbolic Link");
2696 tmp = i18n("%1 (Link)").arg(com);
2697 char buff_two[1024];
2699 int n = readlink ( path.data(), buff_two, 1022);
2704 emit setStatusBarText(text2);
2713 else if ( ok && S_ISREG( buff.st_mode ) )
2715 if (buff.st_size < 1024)
2716 text = i18n("%2 (%1 bytes)").arg((long) buff.st_size).arg(text2); // always put the URL last, in case it contains '%'
2719 float d = (float) buff.st_size/1024.0;
2720 text = i18n("%1 (%2 K)").arg(text2).arg(KGlobal::locale()->formatNumber(d, 2)); // was %.2f
2725 else if ( ok && S_ISDIR( buff.st_mode ) )
2735 emit setStatusBarText(text);
2740 if (target == QString::fromLatin1("_blank"))
2742 extra = i18n(" (In new window)");
2744 else if (!target.isEmpty() &&
2745 (target != QString::fromLatin1("_top")) &&
2746 (target != QString::fromLatin1("_self")) &&
2747 (target != QString::fromLatin1("_parent")))
2749 extra = i18n(" (In other frame)");
2752 if (u.protocol() == QString::fromLatin1("mailto")) {
2753 QString mailtoMsg/* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
2754 mailtoMsg += i18n("Email to: ") + KURL::decode_string(u.path());
2755 QStringList queries = QStringList::split('&', u.query().mid(1));
2756 for (QStringList::Iterator it = queries.begin(); it != queries.end(); ++it)
2757 if ((*it).startsWith(QString::fromLatin1("subject=")))
2758 mailtoMsg += i18n(" - Subject: ") + KURL::decode_string((*it).mid(8));
2759 else if ((*it).startsWith(QString::fromLatin1("cc=")))
2760 mailtoMsg += i18n(" - CC: ") + KURL::decode_string((*it).mid(3));
2761 else if ((*it).startsWith(QString::fromLatin1("bcc=")))
2762 mailtoMsg += i18n(" - BCC: ") + KURL::decode_string((*it).mid(4));
2763 mailtoMsg.replace(QRegExp("&"), QString("&"));
2764 mailtoMsg.replace(QRegExp("<"), QString("<"));
2765 mailtoMsg.replace(QRegExp(">"), QString(">"));
2766 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), "");
2767 emit setStatusBarText(mailtoMsg);
2770 // Is this check neccessary at all? (Frerich)
2772 else if (u.protocol() == QString::fromLatin1("http")) {
2773 DOM::Node hrefNode = nodeUnderMouse().parentNode();
2774 while (hrefNode.nodeName().string() != QString::fromLatin1("A") && !hrefNode.isNull())
2775 hrefNode = hrefNode.parentNode();
2777 if (!hrefNode.isNull()) {
2778 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
2779 if (!hreflangNode.isNull()) {
2780 QString countryCode = hreflangNode.nodeValue().string().lower();
2781 // Map the language code to an appropriate country code.
2782 if (countryCode == QString::fromLatin1("en"))
2783 countryCode = QString::fromLatin1("gb");
2784 QString flagImg = QString::fromLatin1("<img src=%1>").arg(
2785 locate("locale", QString::fromLatin1("l10n/")
2787 + QString::fromLatin1("/flag.png")));
2788 emit setStatusBarText(flagImg + u.prettyURL() + extra);
2793 emit setStatusBarText(u.htmlURL() + extra);
2797 #endif // APPLE_CHANGES
2799 void KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target,
2800 KParts::URLArgs args )
2802 bool hasTarget = false;
2804 QString target = _target;
2805 if ( target.isEmpty() && d->m_doc )
2806 target = d->m_doc->baseTarget();
2807 if ( !target.isEmpty() )
2810 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
2812 executeScript( KURL::decode_string( url.right( url.length() - 11) ), true );
2816 KURL cURL = completeURL(url);
2818 // special case for <a href="">
2819 if ( url.isEmpty() )
2820 cURL.setFileName( url );
2823 if ( !cURL.isValid() )
2824 // ### ERROR HANDLING
2827 //kdDebug( 6000 ) << "urlSelected: complete URL:" << cURL.url() << " target = " << target << endl;
2830 if ( button == LeftButton && ( state & ShiftButton ) )
2832 KIO::MetaData metaData;
2833 metaData["referrer"] = d->m_referrer;
2834 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As..." ), cURL, metaData );
2838 if (!checkLinkSecurity(cURL,
2839 i18n( "<qt>The link <B>%1</B><BR>leads from this untrusted page to your local filesystem.<BR>Do you want to follow the link?" ),
2844 args.frameName = target;
2846 if ( d->m_bHTTPRefresh )
2848 d->m_bHTTPRefresh = false;
2849 args.metaData()["cache"] = "refresh";
2853 args.metaData().insert("main_frame_request",
2854 parentPart() == 0 ? "TRUE":"FALSE");
2855 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
2856 args.metaData().insert("ssl_activate_warnings", "TRUE");
2860 args.metaData()["referrer"] = d->m_referrer;
2861 KWQ(this)->urlSelected(cURL, button, state, args);
2865 // unknown frame names should open in a new window.
2866 khtml::ChildFrame *frame = recursiveFrameRequest( cURL, args, false );
2869 args.metaData()["referrer"] = d->m_referrer;
2870 requestObject( frame, cURL, args );
2875 if ( !d->m_bComplete && !hasTarget )
2878 if (!d->m_referrer.isEmpty())
2879 args.metaData()["referrer"] = d->m_referrer;
2881 if ( button == MidButton && (state & ShiftButton) )
2883 KParts::WindowArgs winArgs;
2884 winArgs.lowerWindow = true;
2885 KParts::ReadOnlyPart *newPart = 0;
2886 emit d->m_extension->createNewWindow( cURL, args, winArgs, newPart );
2889 emit d->m_extension->openURLRequest( cURL, args );
2890 #endif // APPLE_CHANGES
2895 void KHTMLPart::slotViewDocumentSource()
2898 if (!(url.isLocalFile()) && KHTMLPageCache::self()->isValid(d->m_cacheId))
2900 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2901 if (sourceFile.status() == 0)
2903 KHTMLPageCache::self()->saveData(d->m_cacheId, sourceFile.dataStream());
2905 url.setPath(sourceFile.name());
2909 // emit d->m_extension->openURLRequest( m_url, KParts::URLArgs( false, 0, 0, QString::fromLatin1( "text/plain" ) ) );
2910 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2913 void KHTMLPart::slotViewFrameSource()
2915 KParts::ReadOnlyPart *frame = currentFrame();
2919 KURL url = frame->url();
2920 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
2922 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
2924 if (KHTMLPageCache::self()->isValid(cacheId))
2926 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2927 if (sourceFile.status() == 0)
2929 KHTMLPageCache::self()->saveData(cacheId, sourceFile.dataStream());
2931 url.setPath(sourceFile.name());
2936 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2939 KURL KHTMLPart::backgroundURL() const
2941 // ### what about XML documents? get from CSS?
2942 if (!d->m_doc || !d->m_doc->isHTMLDocument())
2945 QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
2947 return KURL( m_url, relURL );
2950 void KHTMLPart::slotSaveBackground()
2952 KIO::MetaData metaData;
2953 metaData["referrer"] = d->m_referrer;
2954 KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save background image as"), backgroundURL(), metaData );
2957 void KHTMLPart::slotSaveDocument()
2959 KURL srcURL( m_url );
2961 if ( srcURL.fileName(false).isEmpty() )
2962 srcURL.setFileName( "index.html" );
2964 KIO::MetaData metaData;
2966 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files"), d->m_cacheId );
2969 void KHTMLPart::slotSecurity()
2971 // kdDebug( 6050 ) << "Meta Data:" << endl
2972 // << d->m_ssl_peer_cert_subject
2974 // << d->m_ssl_peer_cert_issuer
2976 // << d->m_ssl_cipher
2978 // << d->m_ssl_cipher_desc
2980 // << d->m_ssl_cipher_version
2982 // << d->m_ssl_good_from
2984 // << d->m_ssl_good_until
2986 // << d->m_ssl_cert_state
2989 KSSLInfoDlg *kid = new KSSLInfoDlg(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
2991 if (d->m_bSecurityInQuestion)
2992 kid->setSecurityInQuestion(true);
2994 if (d->m_ssl_in_use) {
2995 KSSLCertificate *x = KSSLCertificate::fromString(d->m_ssl_peer_certificate.local8Bit());
2997 // Set the chain back onto the certificate
2998 QStringList cl = QStringList::split(QString("\n"), d->m_ssl_peer_chain);
2999 QPtrList<KSSLCertificate> ncl;
3001 ncl.setAutoDelete(true);
3002 for (QStringList::Iterator it = cl.begin(); it != cl.end(); ++it) {
3003 KSSLCertificate *y = KSSLCertificate::fromString((*it).local8Bit());
3004 if (y) ncl.append(y);
3007 if (ncl.count() > 0)
3008 x->chain().setChain(ncl);
3014 d->m_ssl_cipher_desc,
3015 d->m_ssl_cipher_version,
3016 d->m_ssl_cipher_used_bits.toInt(),
3017 d->m_ssl_cipher_bits.toInt(),
3018 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt()
3026 void KHTMLPart::slotSaveFrame()
3028 if ( !d->m_activeFrame )
3029 return; // should never be the case, but one never knows :-)
3031 KURL srcURL( static_cast<KParts::ReadOnlyPart *>( d->m_activeFrame )->url() );
3033 if ( srcURL.fileName(false).isEmpty() )
3034 srcURL.setFileName( "index.html" );
3036 KIO::MetaData metaData;
3037 // Referrer unknown?
3038 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files") );
3041 void KHTMLPart::slotSetEncoding()
3043 // first Item is always auto
3044 if(d->m_paSetEncoding->currentItem() == 0)
3045 setEncoding(QString::null, false);
3047 // strip of the language to get the raw encoding again.
3048 QString enc = KGlobal::charsets()->encodingForName(d->m_paSetEncoding->currentText());
3049 setEncoding(enc, true);
3053 void KHTMLPart::slotUseStylesheet()
3055 if (d->m_doc && d->m_paUseStylesheet->currentText() != d->m_sheetUsed) {
3056 d->m_sheetUsed = d->m_paUseStylesheet->currentText();
3057 d->m_doc->updateStyleSelector();
3061 void KHTMLPart::updateActions()
3063 bool frames = false;
3065 QValueList<khtml::ChildFrame>::ConstIterator it = d->m_frames.begin();
3066 QValueList<khtml::ChildFrame>::ConstIterator end = d->m_frames.end();
3067 for (; it != end; ++it )
3068 if ( (*it).m_type == khtml::ChildFrame::Frame )
3074 d->m_paViewFrame->setEnabled( frames );
3075 d->m_paSaveFrame->setEnabled( frames );
3078 d->m_paFind->setText( i18n( "&Find in Frame..." ) );
3080 d->m_paFind->setText( i18n( "&Find..." ) );
3082 KParts::Part *frame = 0;
3085 frame = currentFrame();
3087 bool enableFindAndSelectAll = true;
3090 enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
3092 d->m_paFind->setEnabled( enableFindAndSelectAll );
3093 d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
3095 bool enablePrintFrame = false;
3099 QObject *ext = KParts::BrowserExtension::childObject( frame );
3101 enablePrintFrame = ext->metaObject()->slotNames().contains( "print()" );
3104 d->m_paPrintFrame->setEnabled( enablePrintFrame );
3109 if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
3110 bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
3112 d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
3117 bool KHTMLPart::requestFrame( khtml::RenderPart *frame, const QString &url, const QString &frameName,
3118 const QStringList ¶mNames, const QStringList ¶mValues, bool isIFrame )
3120 // kdDebug( 6050 ) << "childRequest( ..., " << url << ", " << frameName << " )" << endl;
3121 FrameIt it = d->m_frames.find( frameName );
3122 if ( it == d->m_frames.end() )
3124 khtml::ChildFrame child;
3125 // kdDebug( 6050 ) << "inserting new frame into frame map " << frameName << endl;
3126 child.m_name = frameName;
3127 it = d->m_frames.append( child );
3130 (*it).m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
3131 (*it).m_frame = frame;
3132 (*it).m_paramValues = paramNames;
3133 (*it).m_paramNames = paramValues;
3135 // Support for <frame src="javascript:string">
3136 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
3138 if (!processObjectRequest(&(*it), "about:blank", "text/html" ))
3141 KHTMLPart *newPart = static_cast<KHTMLPart *>(&*(*it).m_part);
3142 newPart->replaceContentsWithScriptResult( url );
3147 return requestObject( &(*it), completeURL( url ));
3150 QString KHTMLPart::requestFrameName()
3153 return KWQ(this)->generateFrameName();
3155 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
3159 bool KHTMLPart::requestObject( khtml::RenderPart *frame, const QString &url, const QString &serviceType,
3160 const QStringList ¶mNames, const QStringList ¶mValues )
3162 khtml::ChildFrame child;
3163 QValueList<khtml::ChildFrame>::Iterator it = d->m_objects.append( child );
3164 (*it).m_frame = frame;
3165 (*it).m_type = khtml::ChildFrame::Object;
3166 (*it).m_paramNames = paramNames;
3167 (*it).m_paramValues = paramValues;
3168 (*it).m_hasFallbackContent = frame->hasFallbackContent();
3172 completedURL = completeURL(url);
3174 KParts::URLArgs args;
3175 args.serviceType = serviceType;
3176 return requestObject( &(*it), completedURL, args );
3179 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KURL &url, const KParts::URLArgs &_args )
3182 if (!checkLinkSecurity(url))
3185 if ( child->m_bPreloaded )
3187 // kdDebug(6005) << "KHTMLPart::requestObject preload" << endl;
3188 if ( child->m_frame && child->m_part && child->m_part->widget() )
3189 child->m_frame->setWidget( child->m_part->widget() );
3191 child->m_bPreloaded = false;
3195 KParts::URLArgs args( _args );
3199 child->m_run->abort();
3202 if ( child->m_part && !args.reload && urlcmp( child->m_part->url().url(), url.url(), true, true ) )
3203 args.serviceType = child->m_serviceType;
3205 child->m_args = args;
3206 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3207 child->m_serviceName = QString::null;
3208 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
3209 child->m_args.metaData()["referrer"] = d->m_referrer;
3212 child->m_args.metaData().insert("main_frame_request",
3213 parentPart() == 0 ? "TRUE":"FALSE");
3214 child->m_args.metaData().insert("ssl_was_in_use",
3215 d->m_ssl_in_use ? "TRUE":"FALSE");
3216 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
3219 // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
3220 if ((url.isEmpty() || url.url() == "about:blank") && args.serviceType.isEmpty())
3221 args.serviceType = QString::fromLatin1( "text/html" );
3224 return processObjectRequest( child, url, args.serviceType );
3226 if ( args.serviceType.isEmpty() ) {
3227 child->m_run = new KHTMLRun( this, child, url, child->m_args,
3228 child->m_type != khtml::ChildFrame::Frame );
3231 return processObjectRequest( child, url, args.serviceType );
3236 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KURL &_url, const QString &mimetype )
3238 //kdDebug( 6050 ) << "KHTMLPart::processObjectRequest trying to create part for " << mimetype << endl;
3240 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
3241 // by an emitting frame part (emit openURLRequest( blahurl, ... ) . A few lines below we delete the part
3242 // though -> the reference becomes invalid -> crash is likely
3245 // khtmlrun called us this way to indicate a loading error
3246 if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
3248 checkEmitLoadEvent();
3249 child->m_bCompleted = true;
3253 if (child->m_bNotify)
3255 child->m_bNotify = false;
3256 if ( !child->m_args.lockHistory() )
3257 emit d->m_extension->openURLNotify();
3261 if ( child->m_part )
3263 KHTMLPart *part = static_cast<KHTMLPart *>(&*child->m_part);
3264 if (part && part->inherits("KHTMLPart")) {
3265 KParts::URLArgs args;
3266 if (!d->m_referrer.isEmpty())
3267 args.metaData()["referrer"] = d->m_referrer;
3268 KWQ(part)->openURLRequest(url, args);
3273 KParts::ReadOnlyPart *part = KWQ(this)->createPart(*child, url, mimetype);
3274 KHTMLPart *khtml_part = static_cast<KHTMLPart *>(part);
3275 if (khtml_part && khtml_part->inherits("KHTMLPart"))
3276 khtml_part->childBegin();
3278 if ( !child->m_services.contains( mimetype ) )
3280 KParts::ReadOnlyPart *part = createPart( d->m_view->viewport(), child->m_name.ascii(), this, child->m_name.ascii(), mimetype, child->m_serviceName, child->m_services, child->m_params );
3284 checkEmitLoadEvent();
3289 if ( child->m_part )
3291 disconnectChild(child);
3293 partManager()->removePart( (KParts::ReadOnlyPart *)child->m_part );
3295 child->m_part->deref();
3298 child->m_serviceType = mimetype;
3299 if ( child->m_frame && part->widget() )
3300 child->m_frame->setWidget( part->widget() );
3303 if ( child->m_type != khtml::ChildFrame::Object )
3304 partManager()->addPart( part, false );
3306 // kdDebug(6005) << "AH! NO FRAME!!!!!" << endl;
3309 child->m_part = part;
3310 assert( ((void*) child->m_part) != 0);
3312 connectChild(child);
3317 child->m_extension = KParts::BrowserExtension::childObject( part );
3319 if ( child->m_extension )
3321 connect( child->m_extension, SIGNAL( openURLNotify() ),
3322 d->m_extension, SIGNAL( openURLNotify() ) );
3324 connect( child->m_extension, SIGNAL( openURLRequestDelayed( const KURL &, const KParts::URLArgs & ) ),
3325 this, SLOT( slotChildURLRequest( const KURL &, const KParts::URLArgs & ) ) );
3327 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ),
3328 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ) );
3329 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs &, const KParts::WindowArgs &, KParts::ReadOnlyPart *& ) ),
3330 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & , const KParts::WindowArgs &, KParts::ReadOnlyPart *&) ) );
3332 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ),
3333 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ) );
3334 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ),
3335 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ) );
3336 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ),
3337 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ) );
3338 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ),
3339 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ) );
3341 connect( child->m_extension, SIGNAL( infoMessage( const QString & ) ),
3342 d->m_extension, SIGNAL( infoMessage( const QString & ) ) );
3344 child->m_extension->setBrowserInterface( d->m_extension->browserInterface() );
3349 checkEmitLoadEvent();
3350 // Some JS code in the load event may have destroyed the part
3351 // In that case, abort
3352 if ( !child->m_part )
3355 if ( child->m_bPreloaded )
3357 if ( child->m_frame && child->m_part )
3358 child->m_frame->setWidget( child->m_part->widget() );
3360 child->m_bPreloaded = false;
3364 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3366 // make sure the part has a way to find out about the mimetype.
3367 // we actually set it in child->m_args in requestObject already,
3368 // but it's useless if we had to use a KHTMLRun instance, as the
3369 // point the run object is to find out exactly the mimetype.
3370 child->m_args.serviceType = mimetype;
3372 child->m_bCompleted = false;
3373 if ( child->m_extension )
3374 child->m_extension->setURLArgs( child->m_args );
3377 // In these cases, the synchronous load would have finished
3378 // before we could connect the signals, so make sure to send the
3379 // completed() signal for the child by hand
3380 // FIXME: In this case the KHTMLPart will have finished loading before
3381 // it's being added to the child list. It would be a good idea to
3382 // create the child first, then invoke the loader separately
3383 if (url.isEmpty() || url.url() == "about:blank") {
3384 ReadOnlyPart *readOnlyPart = child->m_part;
3385 KHTMLPart *part = static_cast<KHTMLPart *>(readOnlyPart);
3386 if (part && part->inherits("KHTMLPart")) {
3388 part->checkCompleted();
3392 if(url.protocol() == "javascript" || url.url() == "about:blank") {
3393 if (!child->m_part->inherits("KHTMLPart"))
3396 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(child->m_part));
3399 if (d->m_doc && p->d->m_doc)
3400 p->d->m_doc->setBaseURL(d->m_doc->baseURL());
3401 if (!url.url().startsWith("about:")) {
3402 p->write(url.path());
3409 else if ( !url.isEmpty() )
3411 //kdDebug( 6050 ) << "opening " << url.url() << " in frame " << child->m_part << endl;
3412 return child->m_part->openURL( url );
3421 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget, const char *widgetName,
3422 QObject *parent, const char *name, const QString &mimetype,
3423 QString &serviceName, QStringList &serviceTypes,
3424 const QStringList ¶ms )
3427 if ( !serviceName.isEmpty() )
3428 constr.append( QString::fromLatin1( "Name == '%1'" ).arg( serviceName ) );
3430 KTrader::OfferList offers = KTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr, QString::null );
3432 if ( offers.isEmpty() )
3435 KService::Ptr service = *offers.begin();
3437 KLibFactory *factory = KLibLoader::self()->factory( QFile::encodeName(service->library()) );
3442 KParts::ReadOnlyPart *res = 0L;
3444 const char *className = "KParts::ReadOnlyPart";
3445 if ( service->serviceTypes().contains( "Browser/View" ) )
3446 className = "Browser/View";
3448 if ( factory->inherits( "KParts::Factory" ) )
3449 res = static_cast<KParts::ReadOnlyPart *>(static_cast<KParts::Factory *>( factory )->createPart( parentWidget, widgetName, parent, name, className, params ));
3451 res = static_cast<KParts::ReadOnlyPart *>(factory->create( parentWidget, widgetName, className ));
3456 serviceTypes = service->serviceTypes();
3457 serviceName = service->name();
3462 KParts::PartManager *KHTMLPart::partManager()
3464 if ( !d->m_manager )
3466 d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this, "khtml part manager" );
3467 d->m_manager->setAllowNestedParts( true );
3468 connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
3469 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
3470 connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ),
3471 this, SLOT( slotPartRemoved( KParts::Part * ) ) );
3474 return d->m_manager;
3479 void KHTMLPart::submitFormAgain()
3481 if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
3482 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 );
3484 delete d->m_submitForm;
3485 d->m_submitForm = 0;
3486 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
3489 void KHTMLPart::submitForm( const char *action, const QString &url, const FormData &formData, const QString &_target, const QString& contentType, const QString& boundary )
3491 kdDebug(6000) << this << ": KHTMLPart::submitForm target=" << _target << " url=" << url << endl;
3492 KURL u = completeURL( url );
3496 // ### ERROR HANDLING!
3501 // Form security checks
3504 /* This is separate for a reason. It has to be _before_ all script, etc,
3505 * AND I don't want to break anything that uses checkLinkSecurity() in
3509 // This causes crashes... needs to be fixed.
3510 if (!d->m_submitForm && u.protocol() != "https" && u.protocol() != "mailto") {
3511 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
3512 int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
3513 "\nA third party may be able to intercept and view this information."
3514 "\nAre you sure you wish to continue?"),
3516 if (rc == KMessageBox::Cancel)
3518 } else { // Going from nonSSL -> nonSSL
3519 KSSLSettings kss(true);
3520 if (kss.warnOnUnencrypted()) {
3521 int rc = KMessageBox::warningContinueCancel(NULL,
3522 i18n("Warning: Your data is about to be transmitted across the network unencrypted."
3523 "\nAre you sure you wish to continue?"),
3526 "WarnOnUnencryptedForm");
3527 // Move this setting into KSSL instead
3528 KConfig *config = kapp->config();
3529 QString grpNotifMsgs = QString::fromLatin1("Notification Messages");
3530 KConfigGroupSaver saver( config, grpNotifMsgs );
3532 if (!config->readBoolEntry("WarnOnUnencryptedForm", true)) {
3533 config->deleteEntry("WarnOnUnencryptedForm");
3535 kss.setWarnOnUnencrypted(false);
3538 if (rc == KMessageBox::Cancel)
3544 if (!d->m_submitForm && u.protocol() == "mailto") {
3545 int rc = KMessageBox::warningContinueCancel(NULL,
3546 i18n("This site is attempting to submit form data via email."),
3549 "WarnTriedEmailSubmit");
3551 if (rc == KMessageBox::Cancel) {
3556 // End form security checks
3558 #endif // APPLE_CHANGES
3560 QString urlstring = u.url();
3562 if ( urlstring.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
3563 urlstring = KURL::decode_string(urlstring);
3564 d->m_executingJavaScriptFormAction = true;
3565 executeScript( urlstring.right( urlstring.length() - 11) );
3566 d->m_executingJavaScriptFormAction = false;
3571 if (!checkLinkSecurity(u,
3572 i18n( "<qt>The form will be submitted to <BR><B>%1</B><BR>on your local filesystem.<BR>Do you want to submit the form?" ),
3577 KParts::URLArgs args;
3579 if (!d->m_referrer.isEmpty())
3580 args.metaData()["referrer"] = d->m_referrer;
3583 args.metaData().insert("main_frame_request",
3584 parentPart() == 0 ? "TRUE":"FALSE");
3585 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
3586 args.metaData().insert("ssl_activate_warnings", "TRUE");
3588 args.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
3590 // Handle mailto: forms
3591 if (u.protocol() == "mailto") {
3592 // 1) Check for attach= and strip it
3593 QString q = u.query().mid(1);
3594 QStringList nvps = QStringList::split("&", q);
3595 bool triedToAttach = false;
3597 for (QStringList::Iterator nvp = nvps.begin(); nvp != nvps.end(); ++nvp) {
3598 QStringList pair = QStringList::split("=", *nvp);
3599 if (pair.count() >= 2) {
3600 if (pair.first().lower() == "attach") {
3601 nvp = nvps.remove(nvp);
3602 triedToAttach = true;
3609 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");
3614 if (contentType.lower() == "multipart/form-data") {
3615 // FIXME: is this correct? I suspect not
3616 bodyEnc = KURL::encode_string(formData.flattenToString());
3617 } else if (contentType.lower() == "text/plain") {
3618 // Convention seems to be to decode, and s/&/\n/
3619 QString tmpbody = formData.flattenToString();
3620 tmpbody.replace('&', '\n');
3621 tmpbody.replace('+', ' ');
3622 tmpbody = KURL::decode_string(tmpbody); // Decode the rest of it
3623 bodyEnc = KURL::encode_string(tmpbody); // Recode for the URL
3625 bodyEnc = KURL::encode_string(formData.flattenToString());
3628 nvps.append(QString("body=%1").arg(bodyEnc));
3633 if ( strcmp( action, "get" ) == 0 ) {
3634 if (u.protocol() != "mailto")
3635 u.setQuery( formData.flattenToString() );
3636 args.setDoPost( false );
3640 args.postData = formData;
3642 args.postData = formData.flatten();
3644 args.setDoPost( true );
3646 // construct some user headers if necessary
3647 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
3648 args.setContentType( "Content-Type: application/x-www-form-urlencoded" );
3649 else // contentType must be "multipart/form-data"
3650 args.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
3653 if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
3654 if( d->m_submitForm ) {
3655 kdDebug(6000) << "KHTMLPart::submitForm ABORTING!" << endl;
3658 d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
3659 d->m_submitForm->submitAction = action;
3660 d->m_submitForm->submitUrl = url;
3661 d->m_submitForm->submitFormData = formData;
3662 d->m_submitForm->target = _target;
3663 d->m_submitForm->submitContentType = contentType;
3664 d->m_submitForm->submitBoundary = boundary;
3665 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
3670 KWQ(this)->submitForm( u, args);
3672 emit d->m_extension->openURLRequest( u, args );
3679 void KHTMLPart::popupMenu( const QString &linkUrl )
3683 if ( linkUrl.isEmpty() ) // click on background
3684 popupURL = this->url();
3685 else { // click on link
3686 popupURL = completeURL( linkUrl );
3687 linkKURL = popupURL;
3690 KXMLGUIClient *client = new KHTMLPopupGUIClient( this, d->m_popupMenuXML, linkKURL );
3692 emit d->m_extension->popupMenu( client, QCursor::pos(), popupURL,
3693 QString::fromLatin1( "text/html" ), S_IFREG /*always a file*/ );
3697 emit popupMenu(linkUrl, QCursor::pos());
3702 void KHTMLPart::slotParentCompleted()
3704 if ( d->m_scheduledRedirection != noRedirectionScheduled && !d->m_redirectionTimer.isActive() )
3706 // kdDebug(6050) << this << ": Child redirection -> " << d->m_redirectURL << endl;