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.
29 #include "khtml_part.h"
32 #define DIRECT_LINKAGE_TO_ECMA
33 #define QT_NO_CLIPBOARD
34 #define QT_NO_DRAGANDDROP
37 #include "khtml_pagecache.h"
39 #include "css/csshelper.h"
40 #include "css/cssproperties.h"
41 #include "css/cssstyleselector.h"
42 #include "css/css_computedstyle.h"
43 #include "css/css_valueimpl.h"
44 #include "dom/dom_string.h"
45 #include "dom/dom_element.h"
46 #include "dom/html_document.h"
47 #include "editing/selection.h"
48 #include "editing/visible_position.h"
49 #include "editing/visible_text.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 "rendering/render_block.h"
55 #include "rendering/render_text.h"
56 #include "rendering/render_frames.h"
57 #include "misc/htmlhashes.h"
58 #include "misc/loader.h"
59 #include "xml/dom2_eventsimpl.h"
60 #include "xml/xml_tokenizer.h"
64 #include "khtmlview.h"
65 #include <kparts/partmanager.h>
66 #include "ecma/kjs_proxy.h"
67 #include "khtml_settings.h"
69 #include <sys/types.h>
73 #include <kstandarddirs.h>
75 #include <kio/global.h>
77 #include <kiconloader.h>
79 #include <kcharsets.h>
80 #include <kmessagebox.h>
81 #include <kstdaction.h>
82 #include <kfiledialog.h>
84 #include <kdatastream.h>
85 #include <ktempfile.h>
86 #include <kglobalsettings.h>
88 #include <kapplication.h>
89 #if !defined(QT_NO_DRAGANDDROP)
90 #include <kmultipledrag.h>
93 #include <ksslcertchain.h>
94 #include <ksslinfodlg.h>
96 #include <qclipboard.h>
98 #include <qmetaobject.h>
100 #include <private/qucomextra_p.h>
102 #include "khtmlpart_p.h"
105 #include <CoreServices/CoreServices.h>
108 using khtml::ApplyStyleCommand;
109 using khtml::CHARACTER;
110 using khtml::ChildFrame;
111 using khtml::Decoder;
112 using khtml::EAffinity;
113 using khtml::EditCommandPtr;
114 using khtml::ETextGranularity;
115 using khtml::FormData;
116 using khtml::InlineTextBox;
117 using khtml::PARAGRAPH;
118 using khtml::plainText;
119 using khtml::RenderObject;
120 using khtml::RenderText;
121 using khtml::Selection;
122 using khtml::Tokenizer;
123 using khtml::TypingCommand;
124 using khtml::VisiblePosition;
127 using KParts::BrowserInterface;
129 const int CARET_BLINK_FREQUENCY = 500;
132 class PartStyleSheetLoader : public CachedObjectClient
135 PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
138 m_cachedSheet = Cache::requestStyleSheet(dl, url );
140 m_cachedSheet->ref( this );
142 virtual ~PartStyleSheetLoader()
144 if ( m_cachedSheet ) m_cachedSheet->deref(this);
146 virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet)
149 m_part->setUserStyleSheet( sheet.string() );
153 QGuardedPtr<KHTMLPart> m_part;
154 khtml::CachedCSSStyleSheet *m_cachedSheet;
158 FrameList::Iterator FrameList::find( const QString &name )
160 Iterator it = begin();
164 if ( (*it).m_name==name )
170 KHTMLPart::KHTMLPart( QWidget *parentWidget, const char *widgetname, QObject *parent, const char *name,
172 : KParts::ReadOnlyPart( parent, name )
175 KHTMLFactory::registerPart( this );
176 setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
178 init( new KHTMLView( this, parentWidget, widgetname ), prof );
184 KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, const char *name, GUIProfile prof )
185 : KParts::ReadOnlyPart( parent, name )
188 KHTMLFactory::registerPart( this );
189 setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
194 #endif // APPLE_CHANGES
196 void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
198 AtomicString::init();
199 if ( prof == DefaultGUI )
200 setXMLFile( "khtml.rc" );
201 else if ( prof == BrowserViewGUI )
202 setXMLFile( "khtml_browser.rc" );
206 d = new KHTMLPartPrivate(parent());
209 setWidget( d->m_view );
212 d->m_guiProfile = prof;
214 d->m_extension = new KHTMLPartBrowserExtension( this );
215 d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
217 d->m_bSecurityInQuestion = false;
218 d->m_bMousePressed = false;
220 d->m_paLoadImages = 0;
221 d->m_paViewDocument = new KAction( i18n( "View Document Source" ), 0, this, SLOT( slotViewDocumentSource() ), actionCollection(), "viewDocumentSource" );
222 d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), 0, this, SLOT( slotViewFrameSource() ), actionCollection(), "viewFrameSource" );
223 d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), 0, this, SLOT( slotSaveBackground() ), actionCollection(), "saveBackground" );
224 d->m_paSaveDocument = new KAction( i18n( "&Save As..." ), CTRL+Key_S, this, SLOT( slotSaveDocument() ), actionCollection(), "saveDocument" );
226 d->m_paSaveDocument->setShortcut( KShortcut() ); // avoid clashes
227 d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), 0, this, SLOT( slotSaveFrame() ), actionCollection(), "saveFrame" );
228 d->m_paSecurity = new KAction( i18n( "Security..." ), "decrypted", 0, this, SLOT( slotSecurity() ), actionCollection(), "security" );
229 d->m_paDebugRenderTree = new KAction( "print rendering tree to stdout", 0, this, SLOT( slotDebugRenderTree() ), actionCollection(), "debugRenderTree" );
230 d->m_paDebugDOMTree = new KAction( "print DOM tree to stdout", 0, this, SLOT( slotDebugDOMTree() ), actionCollection(), "debugDOMTree" );
232 QString foo1 = i18n("Show Images");
233 QString foo2 = i18n("Show Animated Images");
234 QString foo3 = i18n("Stop Animated Images");
236 d->m_paSetEncoding = new KSelectAction( i18n( "Set &Encoding" ), 0, this, SLOT( slotSetEncoding() ), actionCollection(), "setEncoding" );
237 QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames();
238 encodings.prepend( i18n( "Auto" ) );
239 d->m_paSetEncoding->setItems( encodings );
240 d->m_paSetEncoding->setCurrentItem(0);
242 d->m_paUseStylesheet = new KSelectAction( i18n( "&Use Stylesheet"), 0, this, SLOT( slotUseStylesheet() ), actionCollection(), "useStylesheet" );
244 d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, i18n( "Increase Font Sizes" ), "viewmag+", this, SLOT( slotIncZoom() ), actionCollection(), "incFontSizes" );
245 d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, i18n( "Decrease Font Sizes" ), "viewmag-", this, SLOT( slotDecZoom() ), actionCollection(), "decFontSizes" );
247 d->m_paFind = KStdAction::find( this, SLOT( slotFind() ), actionCollection(), "find" );
249 d->m_paFind->setShortcut( KShortcut() ); // avoid clashes
251 d->m_paPrintFrame = new KAction( i18n( "Print Frame" ), "frameprint", 0, this, SLOT( slotPrintFrame() ), actionCollection(), "printFrame" );
253 d->m_paSelectAll = KStdAction::selectAll( this, SLOT( slotSelectAll() ), actionCollection(), "selectAll" );
255 d->m_paSelectAll->setShortcut( KShortcut() ); // avoid clashes
259 // set the default java(script) flags according to the current host.
260 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled();
261 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
262 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled();
263 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled();
265 // The java, javascript, and plugin settings will be set after the settings
266 // have been initialized.
267 d->m_bJScriptEnabled = true;
268 d->m_bJScriptDebugEnabled = true;
269 d->m_bJavaEnabled = true;
270 d->m_bPluginsEnabled = true;
274 connect( this, SIGNAL( completed() ),
275 this, SLOT( updateActions() ) );
276 connect( this, SIGNAL( completed( bool ) ),
277 this, SLOT( updateActions() ) );
278 connect( this, SIGNAL( started( KIO::Job * ) ),
279 this, SLOT( updateActions() ) );
281 d->m_popupMenuXML = KXMLGUIFactory::readConfigFile( locate( "data", "khtml/khtml_popupmenu.rc", KHTMLFactory::instance() ) );
284 connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
285 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
286 connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
287 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
288 connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
289 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
292 findTextBegin(); //reset find variables
295 connect( &d->m_redirectionTimer, SIGNAL( timeout() ),
296 this, SLOT( slotRedirect() ) );
298 connect(&d->m_lifeSupportTimer, SIGNAL(timeout()), this, SLOT(slotEndLifeSupport()));
301 d->m_dcopobject = new KHTMLPartIface(this);
305 KHTMLPart::~KHTMLPart()
307 //kdDebug(6050) << "KHTMLPart::~KHTMLPart " << this << endl;
309 if ( d->m_findDialog )
310 disconnect( d->m_findDialog, SIGNAL( destroyed() ),
311 this, SLOT( slotFindDialogDestroyed() ) );
315 d->m_manager->setActivePart( 0 );
316 // Shouldn't we delete d->m_manager here ? (David)
317 // No need to, I would say. We specify "this" as parent qobject
318 // in ::partManager() (Simon)
328 disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
329 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
330 disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
331 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
332 disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
333 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
340 d->m_view->viewport()->hide();
341 d->m_view->m_part = 0;
345 delete d->m_hostExtension;
349 KHTMLFactory::deregisterPart( this );
352 bool KHTMLPart::restoreURL( const KURL &url )
354 kdDebug( 6050 ) << "KHTMLPart::restoreURL " << url.url() << endl;
359 * That's not a good idea as it will call closeURL() on all
360 * child frames, preventing them from further loading. This
361 * method gets called from restoreState() in case of a full frameset
362 * restoral, and restoreState() calls closeURL() before restoring
364 kdDebug( 6050 ) << "closing old URL" << endl;
368 d->m_bComplete = false;
369 d->m_bLoadEventEmitted = false;
370 d->m_workingURL = url;
372 // set the java(script) flags according to the current host.
374 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
375 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
376 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
377 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
379 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
380 d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled();
381 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
382 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
387 KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &)));
396 bool KHTMLPart::didOpenURL(const KURL &url)
398 bool KHTMLPart::openURL( const KURL &url )
401 kdDebug( 6050 ) << "KHTMLPart(" << this << ")::openURL " << url.url() << endl;
403 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
404 // We're about to get a redirect that happened before the document was
405 // created. This can happen when one frame may change the location of a
412 // clear last edit command
413 d->m_lastEditCommand = EditCommandPtr();
415 KWQ(this)->clearUndoRedoOperations();
419 // check to see if this is an "error://" URL. This is caused when an error
420 // occurs before this part was loaded (e.g. KonqRun), and is passed to
421 // khtmlpart so that it can display the error.
422 if ( url.protocol() == "error" && url.hasSubURL() ) {
425 * The format of the error url is that two variables are passed in the query:
426 * error = int kio error code, errText = QString error text from kio
427 * and the URL where the error happened is passed as a sub URL.
429 KURL::List urls = KURL::split( url );
430 //kdDebug() << "Handling error URL. URL count:" << urls.count() << endl;
432 if ( urls.count() > 1 ) {
433 KURL mainURL = urls.first();
434 int error = mainURL.queryItem( "error" ).toInt();
435 // error=0 isn't a valid error code, so 0 means it's missing from the URL
436 if ( error == 0 ) error = KIO::ERR_UNKNOWN;
437 QString errorText = mainURL.queryItem( "errText" );
439 d->m_workingURL = KURL::join( urls );
440 //kdDebug() << "Emitting fixed URL " << d->m_workingURL.prettyURL() << endl;
441 emit d->m_extension->setLocationBarURL( d->m_workingURL.prettyURL() );
442 htmlError( error, errorText, d->m_workingURL );
446 #endif // APPLE_CHANGES
448 KParts::URLArgs args( d->m_extension->urlArgs() );
451 // in case we have a) no frameset (don't test m_frames.count(), iframes get in there)
452 // b) the url is identical with the currently
453 // displayed one (except for the htmlref!) , c) the url request is not a POST
454 // operation and d) the caller did not request to reload the page we try to
455 // be smart and instead of reloading the whole document we just jump to the
456 // request html anchor
458 bool isFrameSet = false;
459 if ( d->m_doc->isHTMLDocument() ) {
460 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
461 isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET);
464 urlcmp( url.url(), m_url.url(), true, true ) &&
465 url.hasRef() && !args.doPost() && !args.reload )
467 kdDebug( 6050 ) << "KHTMLPart::openURL, jumping to anchor. m_url = " << url.url() << endl;
473 d->m_bComplete = true;
474 d->m_doc->setParsing(false);
476 kdDebug( 6050 ) << "completed..." << endl;
481 #endif // APPLE_CHANGES
485 kdDebug( 6050 ) << "closing old URL" << endl;
490 args.metaData().insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" );
491 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" );
492 args.metaData().insert("ssl_activate_warnings", "TRUE" );
496 d->m_cachePolicy = KIO::CC_Cache;
497 else if (args.reload)
498 d->m_cachePolicy = KIO::CC_Refresh;
500 d->m_cachePolicy = KIO::CC_Verify;
502 if ( args.doPost() && (url.protocol().startsWith("http")) )
504 d->m_job = KIO::http_post( url, args.postData, false );
505 d->m_job->addMetaData("content-type", args.contentType() );
509 d->m_job = KIO::get( url, false, false );
510 d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
513 d->m_job->addMetaData(args.metaData());
515 connect( d->m_job, SIGNAL( result( KIO::Job * ) ),
516 SLOT( slotFinished( KIO::Job * ) ) );
518 connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray &)),
519 SLOT( slotData( KIO::Job*, const QByteArray &)));
522 connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KURL&) ),
523 SLOT( slotRedirection(KIO::Job*,const KURL&) ) );
525 d->m_bComplete = false;
526 d->m_bLoadEventEmitted = false;
528 // delete old status bar msg's from kjs (if it _was_ activated on last URL)
529 if( d->m_bJScriptEnabled )
531 d->m_kjsStatusBarText = QString::null;
532 d->m_kjsDefaultStatusBarText = QString::null;
535 // set the javascript flags according to the current url
537 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
538 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
539 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
541 d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled();
542 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
543 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
546 // 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
547 // data arrives) (Simon)
549 if(m_url.protocol().startsWith( "http" ) && !m_url.host().isEmpty() &&
550 m_url.path().isEmpty()) {
552 emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
554 // copy to m_workingURL after fixing m_url above
555 d->m_workingURL = m_url;
557 kdDebug( 6050 ) << "KHTMLPart::openURL now (before started) m_url = " << m_url.url() << endl;
559 connect( d->m_job, SIGNAL( speed( KIO::Job*, unsigned long ) ),
560 this, SLOT( slotJobSpeed( KIO::Job*, unsigned long ) ) );
562 connect( d->m_job, SIGNAL( percent( KIO::Job*, unsigned long ) ),
563 this, SLOT( slotJobPercent( KIO::Job*, unsigned long ) ) );
570 bool KHTMLPart::closeURL()
574 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
579 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
580 HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
582 if ( hdoc->body() && d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted ) {
583 hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false );
585 d->m_doc->updateRendering();
586 d->m_bUnloadEventEmitted = true;
590 d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
591 d->m_bLoadEventEmitted = true; // don't want that one either
592 d->m_cachePolicy = KIO::CC_Verify; // Why here?
594 KHTMLPageCache::self()->cancelFetch(this);
595 if ( d->m_doc && d->m_doc->parsing() )
597 kdDebug( 6050 ) << " was still parsing... calling end " << endl;
598 slotFinishedParsing();
599 d->m_doc->setParsing(false);
602 if ( !d->m_workingURL.isEmpty() )
604 // Aborted before starting to render
605 kdDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << m_url.prettyURL() << endl;
606 emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
609 d->m_workingURL = KURL();
611 if ( d->m_doc && d->m_doc->docLoader() )
612 khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() );
614 // tell all subframes to stop as well
615 ConstFrameIt it = d->m_frames.begin();
616 ConstFrameIt end = d->m_frames.end();
617 for (; it != end; ++it )
618 if ( !( *it ).m_part.isNull() )
619 ( *it ).m_part->closeURL();
621 d->m_bPendingChildRedirection = false;
623 // Stop any started redirections as well!! (DA)
626 // null node activated.
627 emit nodeActivated(Node());
632 DOM::HTMLDocument KHTMLPart::htmlDocument() const
634 if (d->m_doc && d->m_doc->isHTMLDocument())
635 return static_cast<HTMLDocumentImpl*>(d->m_doc);
637 return static_cast<HTMLDocumentImpl*>(0);
640 DOM::Document KHTMLPart::document() const
646 KParts::BrowserExtension *KHTMLPart::browserExtension() const
648 return d->m_extension;
651 KHTMLView *KHTMLPart::view() const
656 void KHTMLPart::setJScriptEnabled( bool enable )
658 if ( !enable && jScriptEnabled() && d->m_jscript ) {
659 d->m_jscript->clear();
661 d->m_bJScriptForce = enable;
662 d->m_bJScriptOverride = true;
665 bool KHTMLPart::jScriptEnabled() const
667 if ( d->m_bJScriptOverride )
668 return d->m_bJScriptForce;
669 return d->m_bJScriptEnabled;
672 void KHTMLPart::setMetaRefreshEnabled( bool enable )
674 d->m_metaRefreshEnabled = enable;
677 bool KHTMLPart::metaRefreshEnabled() const
679 return d->m_metaRefreshEnabled;
682 // Define this to disable dlopening kjs_html, when directly linking to it.
683 // You need to edit khtml/Makefile.am to add ./ecma/libkjs_html.la to LIBADD
684 // and to edit khtml/ecma/Makefile.am to s/kjs_html/libkjs_html/, remove libkhtml from LIBADD,
685 // remove LDFLAGS line, and replace kde_module with either lib (shared) or noinst (static)
686 //#define DIRECT_LINKAGE_TO_ECMA
688 #ifdef DIRECT_LINKAGE_TO_ECMA
689 extern "C" { KJSProxy *kjs_html_init(KHTMLPart *khtmlpart); }
692 KJSProxy *KHTMLPart::jScript()
694 if (!jScriptEnabled()){
700 #ifndef DIRECT_LINKAGE_TO_ECMA
701 KLibrary *lib = KLibLoader::self()->library("kjs_html");
703 setJScriptEnabled( false );
706 // look for plain C init function
707 void *sym = lib->symbol("kjs_html_init");
710 setJScriptEnabled( false );
713 typedef KJSProxy* (*initFunction)(KHTMLPart *);
714 initFunction initSym = (initFunction) sym;
715 d->m_jscript = (*initSym)(this);
718 d->m_jscript = kjs_html_init(this);
719 // d->m_kjs_lib remains 0L.
721 if (d->m_bJScriptDebugEnabled)
722 d->m_jscript->setDebugEnabled(true);
728 void KHTMLPart::replaceContentsWithScriptResult( const KURL &url )
730 QString script = KURL::decode_string(url.url().mid(strlen("javascript:")));
731 QVariant ret = executeScript(script);
733 if (ret.type() == QVariant::String) {
735 write(ret.asString());
740 QVariant KHTMLPart::executeScript( const QString &script, bool forceUserGesture )
742 return executeScript( DOM::Node(), script, forceUserGesture );
745 //Enable this to see all JS scripts being executed
746 //#define KJS_VERBOSE
748 QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script, bool forceUserGesture )
751 kdDebug(6070) << "KHTMLPart::executeScript n=" << n.nodeName().string().latin1() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " << script << endl;
753 KJSProxy *proxy = jScript();
755 if (!proxy || proxy->paused())
757 d->m_runningScripts++;
758 // If forceUserGesture is true, then make the script interpreter
759 // treat it as if triggered by a user gesture even if there is no
760 // current DOM event being processed.
761 QVariant ret = proxy->evaluate( forceUserGesture ? QString::null : m_url.url(), 0, script, n );
762 d->m_runningScripts--;
763 if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
765 DocumentImpl::updateDocumentsRendering();
768 kdDebug(6070) << "KHTMLPart::executeScript - done" << endl;
773 bool KHTMLPart::scheduleScript(const DOM::Node &n, const QString& script)
775 //kdDebug(6050) << "KHTMLPart::scheduleScript "<< script << endl;
777 d->scheduledScript = script;
778 d->scheduledScriptNode = n;
783 QVariant KHTMLPart::executeScheduledScript()
785 if( d->scheduledScript.isEmpty() )
788 //kdDebug(6050) << "executing delayed " << d->scheduledScript << endl;
790 QVariant ret = executeScript( d->scheduledScriptNode, d->scheduledScript );
791 d->scheduledScript = QString();
792 d->scheduledScriptNode = DOM::Node();
797 void KHTMLPart::setJavaEnabled( bool enable )
799 d->m_bJavaForce = enable;
800 d->m_bJavaOverride = true;
803 bool KHTMLPart::javaEnabled() const
806 if( d->m_bJavaOverride )
807 return d->m_bJavaForce;
808 return d->m_bJavaEnabled;
814 KJavaAppletContext *KHTMLPart::javaContext()
817 return d->m_javaContext;
823 KJavaAppletContext *KHTMLPart::createJavaContext()
826 if ( !d->m_javaContext ) {
828 d->m_javaContext = new KJavaAppletContext(d->m_dcopobject, this);
830 d->m_javaContext = new KJavaAppletContext(d->m_dcopobject);
831 connect( d->m_javaContext, SIGNAL(showStatus(const QString&)),
832 this, SIGNAL(setStatusBarText(const QString&)) );
833 connect( d->m_javaContext, SIGNAL(showDocument(const QString&, const QString&)),
834 this, SLOT(slotShowDocument(const QString&, const QString&)) );
838 return d->m_javaContext;
844 void KHTMLPart::setPluginsEnabled( bool enable )
846 d->m_bPluginsForce = enable;
847 d->m_bPluginsOverride = true;
850 bool KHTMLPart::pluginsEnabled() const
852 if ( d->m_bPluginsOverride )
853 return d->m_bPluginsForce;
854 return d->m_bPluginsEnabled;
859 void KHTMLPart::slotShowDocument( const QString &url, const QString &target )
861 // this is mostly copied from KHTMLPart::slotChildURLRequest. The better approach
862 // would be to put those functions into a single one.
863 khtml::ChildFrame *child = 0;
864 KParts::URLArgs args;
865 args.frameName = target;
867 QString frameName = args.frameName.lower();
868 if ( !frameName.isEmpty() )
870 if ( frameName == QString::fromLatin1( "_top" ) )
872 emit d->m_extension->openURLRequest( url, args );
875 else if ( frameName == QString::fromLatin1( "_blank" ) )
877 emit d->m_extension->createNewWindow( url, args );
880 else if ( frameName == QString::fromLatin1( "_parent" ) )
882 KParts::URLArgs newArgs( args );
883 newArgs.frameName = QString::null;
885 emit d->m_extension->openURLRequest( url, newArgs );
888 else if ( frameName != QString::fromLatin1( "_self" ) )
890 khtml::ChildFrame *_frame = recursiveFrameRequest( url, args );
894 emit d->m_extension->openURLRequest( url, args );
902 // TODO: handle child target correctly! currently the script are always executed fur the parent
903 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
904 executeScript( KURL::decode_string( url.right( url.length() - 11) ) );
909 requestObject( child, KURL(url), args );
910 } else if ( frameName==QString::fromLatin1("_self") ) // this is for embedded objects (via <object>) which want to replace the current document
912 KParts::URLArgs newArgs( args );
913 newArgs.frameName = QString::null;
914 emit d->m_extension->openURLRequest( KURL(url), newArgs );
918 #endif // APPLE_CHANGES
920 void KHTMLPart::slotDebugDOMTree()
922 if ( d->m_doc && d->m_doc->firstChild() )
923 qDebug("%s", d->m_doc->firstChild()->toHTML().latin1());
926 void KHTMLPart::slotDebugRenderTree()
930 d->m_doc->renderer()->printTree();
934 void KHTMLPart::setAutoloadImages( bool enable )
936 if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
940 d->m_doc->docLoader()->setAutoloadImages( enable );
943 unplugActionList( "loadImages" );
946 delete d->m_paLoadImages;
947 d->m_paLoadImages = 0;
949 else if ( !d->m_paLoadImages )
950 d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), "images_display", 0, this, SLOT( slotLoadImages() ), actionCollection(), "loadImages" );
952 if ( d->m_paLoadImages ) {
953 QPtrList<KAction> lst;
954 lst.append( d->m_paLoadImages );
955 plugActionList( "loadImages", lst );
960 bool KHTMLPart::autoloadImages() const
963 return d->m_doc->docLoader()->autoloadImages();
968 void KHTMLPart::clear()
972 d->m_bCleared = true;
974 d->m_bClearing = true;
978 ConstFrameIt it = d->m_frames.begin();
979 ConstFrameIt end = d->m_frames.end();
980 for(; it != end; ++it )
982 // Stop HTMLRun jobs for frames
984 (*it).m_run->abort();
989 QValueList<khtml::ChildFrame>::ConstIterator it = d->m_objects.begin();
990 QValueList<khtml::ChildFrame>::ConstIterator end = d->m_objects.end();
991 for(; it != end; ++it )
993 // Stop HTMLRun jobs for objects
995 (*it).m_run->abort();
1000 findTextBegin(); // resets d->m_findNode and d->m_findPos
1003 d->m_mousePressNode = DOM::Node();
1009 // Moving past doc so that onUnload works.
1011 d->m_jscript->clear();
1016 // do not dereference the document before the jscript and view are cleared, as some destructors
1017 // might still try to access the document.
1023 d->m_decoder->deref();
1027 ConstFrameIt it = d->m_frames.begin();
1028 ConstFrameIt end = d->m_frames.end();
1029 for(; it != end; ++it )
1033 disconnectChild(&*it);
1035 partManager()->removePart( (*it).m_part );
1037 (*it).m_part->deref();
1041 d->m_frames.clear();
1044 ConstFrameIt it = d->m_objects.begin();
1045 ConstFrameIt end = d->m_objects.end();
1046 for(; it != end; ++it )
1051 partManager()->removePart( (*it).m_part );
1053 (*it).m_part->deref();
1057 d->m_objects.clear();
1060 delete d->m_javaContext;
1061 d->m_javaContext = 0;
1064 d->m_scheduledRedirection = noRedirectionScheduled;
1065 d->m_delayRedirect = 0;
1066 d->m_redirectURL = QString::null;
1067 d->m_redirectLockHistory = true;
1068 d->m_redirectUserGesture = false;
1069 d->m_bHTTPRefresh = false;
1070 d->m_bClearing = false;
1071 d->m_frameNameId = 1;
1072 d->m_bFirstData = true;
1074 d->m_bMousePressed = false;
1076 #ifndef QT_NO_CLIPBOARD
1077 connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
1081 d->m_totalObjectCount = 0;
1082 d->m_loadedObjects = 0;
1083 d->m_jobPercent = 0;
1086 if ( !d->m_haveEncoding )
1087 d->m_encoding = QString::null;
1089 d->m_parsetime.restart();
1093 bool KHTMLPart::openFile()
1098 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
1105 void KHTMLPart::replaceDocImpl(DocumentImpl* newDoc)
1118 /*bool KHTMLPart::isSSLInUse() const
1120 return d->m_ssl_in_use;
1123 void KHTMLPart::receivedFirstData()
1125 // Leave indented one extra for easier merging.
1127 //kdDebug( 6050 ) << "begin!" << endl;
1129 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1132 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
1133 d->m_workingURL = KURL();
1135 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
1137 // When the first data arrives, the metadata has just been made available
1141 d->m_bSecurityInQuestion = false;
1142 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
1143 kdDebug(6050) << "SSL in use? " << d->m_job->queryMetaData("ssl_in_use") << endl;
1146 KHTMLPart *p = parentPart();
1147 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
1148 while (p->parentPart()) p = p->parentPart();
1150 p->d->m_paSecurity->setIcon( "halfencrypted" );
1151 p->d->m_bSecurityInQuestion = true;
1152 kdDebug(6050) << "parent setIcon half done." << endl;
1156 d->m_paSecurity->setIcon( d->m_ssl_in_use ? "encrypted" : "decrypted" );
1157 kdDebug(6050) << "setIcon " << ( d->m_ssl_in_use ? "encrypted" : "decrypted" ) << " done." << endl;
1159 // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
1161 d->m_ssl_peer_certificate = d->m_job->queryMetaData("ssl_peer_certificate");
1162 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
1163 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
1164 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
1165 d->m_ssl_cipher_desc = d->m_job->queryMetaData("ssl_cipher_desc");
1166 d->m_ssl_cipher_version = d->m_job->queryMetaData("ssl_cipher_version");
1167 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
1168 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
1169 d->m_ssl_cert_state = d->m_job->queryMetaData("ssl_cert_state");
1171 // Check for charset meta-data
1172 QString qData = d->m_job->queryMetaData("charset");
1173 if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
1174 d->m_encoding = qData;
1175 #endif // APPLE_CHANGES
1177 // Support for http-refresh
1178 qData = d->m_job->queryMetaData("http-refresh");
1179 if( !qData.isEmpty() && d->m_metaRefreshEnabled )
1181 kdDebug(6050) << "HTTP Refresh Request: " << qData << endl;
1183 int pos = qData.find( ';' );
1185 pos = qData.find( ',' );
1189 delay = qData.stripWhiteSpace().toDouble();
1191 // We want a new history item if the refresh timeout > 1 second
1192 scheduleRedirection( delay, m_url.url(), delay <= 1);
1194 scheduleRedirection( delay, m_url.url());
1199 int end_pos = qData.length();
1200 delay = qData.left(pos).stripWhiteSpace().toDouble();
1201 while ( qData[++pos] == ' ' );
1202 if ( qData.find( "url", pos, false ) == pos )
1205 while (qData[pos] == ' ' || qData[pos] == '=' )
1207 if ( qData[pos] == '"' )
1210 int index = end_pos-1;
1211 while( index > pos )
1213 if ( qData[index] == '"' )
1222 // We want a new history item if the refresh timeout > 1 second
1223 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ), delay <= 1);
1225 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ));
1228 d->m_bHTTPRefresh = true;
1231 // Support for http last-modified
1232 d->m_lastModified = d->m_job->queryMetaData("modified");
1233 //kdDebug() << "KHTMLPart::slotData metadata modified: " << d->m_lastModified << endl;
1238 void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
1240 assert ( d->m_job == kio_job );
1242 //kdDebug( 6050 ) << "slotData: " << data.size() << endl;
1244 if ( !d->m_workingURL.isEmpty() )
1245 receivedFirstData( );
1247 KHTMLPageCache::self()->addData(d->m_cacheId, data);
1248 write( data.data(), data.size() );
1251 void KHTMLPart::slotRestoreData(const QByteArray &data )
1254 if ( !d->m_workingURL.isEmpty() )
1256 long saveCacheId = d->m_cacheId;
1257 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1258 d->m_cacheId = saveCacheId;
1259 d->m_workingURL = KURL();
1262 //kdDebug( 6050 ) << "slotRestoreData: " << data.size() << endl;
1263 write( data.data(), data.size() );
1265 if (data.size() == 0)
1267 //kdDebug( 6050 ) << "slotRestoreData: <<end of data>>" << endl;
1269 if (d->m_doc && d->m_doc->parsing())
1270 end(); //will emit completed()
1274 void KHTMLPart::showError( KIO::Job* job )
1276 kdDebug() << "KHTMLPart::showError d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
1277 << " d->m_bCleared=" << d->m_bCleared << endl;
1279 if (job->error() == KIO::ERR_NO_CONTENT)
1282 if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
1283 job->showErrorDialog( /*d->m_view*/ );
1286 htmlError( job->error(), job->errorText(), d->m_workingURL );
1290 // This is a protected method, placed here because of it's relevance to showError
1291 void KHTMLPart::htmlError( int errorCode, const QString& text, const KURL& reqUrl )
1293 kdDebug(6050) << "KHTMLPart::htmlError errorCode=" << errorCode << " text=" << text << endl;
1294 // make sure we're not executing any embedded JS
1295 bool bJSFO = d->m_bJScriptForce;
1296 bool bJSOO = d->m_bJScriptOverride;
1297 d->m_bJScriptForce = false;
1298 d->m_bJScriptOverride = true;
1300 QString errText = QString::fromLatin1( "<HTML><HEAD><TITLE>" );
1301 errText += i18n( "Error while loading %1" ).arg( reqUrl.htmlURL() );
1302 errText += QString::fromLatin1( "</TITLE></HEAD><BODY><P>" );
1303 errText += i18n( "An error occured while loading <B>%1</B>:" ).arg( reqUrl.htmlURL() );
1304 errText += QString::fromLatin1( "</P><P>" );
1305 QString kioErrString = KIO::buildErrorString( errorCode, text );
1307 kioErrString.replace(QRegExp("&"), QString("&"));
1308 kioErrString.replace(QRegExp("<"), QString("<"));
1309 kioErrString.replace(QRegExp(">"), QString(">"));
1311 // In case the error string has '\n' in it, replace with <BR/>
1312 kioErrString.replace( QRegExp("\n"), "<BR/>" );
1314 errText += kioErrString;
1315 errText += QString::fromLatin1( "</P></BODY></HTML>" );
1319 d->m_bJScriptForce = bJSFO;
1320 d->m_bJScriptOverride = bJSOO;
1322 // make the working url the current url, so that reload works and
1323 // emit the progress signals to advance one step in the history
1324 // (so that 'back' works)
1325 m_url = reqUrl; // same as d->m_workingURL
1326 d->m_workingURL = KURL();
1330 // following disabled until 3.1
1332 QString errorName, techName, description;
1333 QStringList causes, solutions;
1335 QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
1336 QDataStream stream(raw, IO_ReadOnly);
1338 stream >> errorName >> techName >> description >> causes >> solutions;
1340 QString url, protocol, datetime;
1341 url = reqUrl.prettyURL();
1342 protocol = reqUrl.protocol();
1343 datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
1346 QString doc = QString::fromLatin1( "<html><head><title>" );
1347 doc += i18n( "Error: " );
1349 doc += QString::fromLatin1( " - %1</title></head><body><h1>" ).arg( url );
1350 doc += i18n( "The requested operation could not be completed" );
1351 doc += QString::fromLatin1( "</h1><h2>" );
1353 doc += QString::fromLatin1( "</h2>" );
1354 if ( techName != QString::null ) {
1355 doc += QString::fromLatin1( "<h2>" );
1356 doc += i18n( "Technical Reason: " );
1358 doc += QString::fromLatin1( "</h2>" );
1360 doc += QString::fromLatin1( "<h3>" );
1361 doc += i18n( "Details of the Request:" );
1362 doc += QString::fromLatin1( "</h3><ul><li>" );
1363 doc += i18n( "URL: %1" ).arg( url );
1364 doc += QString::fromLatin1( "</li><li>" );
1365 if ( protocol != QString::null ) {
1366 // uncomment for 3.1... i18n change
1367 // doc += i18n( "Protocol: %1" ).arg( protocol ).arg( protocol );
1368 doc += QString::fromLatin1( "</li><li>" );
1370 doc += i18n( "Date and Time: %1" ).arg( datetime );
1371 doc += QString::fromLatin1( "</li><li>" );
1372 doc += i18n( "Additional Information: %1" ).arg( text );
1373 doc += QString::fromLatin1( "</li></ul><h3>" );
1374 doc += i18n( "Description:" );
1375 doc += QString::fromLatin1( "</h3><p>" );
1377 doc += QString::fromLatin1( "</p>" );
1378 if ( causes.count() ) {
1379 doc += QString::fromLatin1( "<h3>" );
1380 doc += i18n( "Possible Causes:" );
1381 doc += QString::fromLatin1( "</h3><ul><li>" );
1382 doc += causes.join( "</li><li>" );
1383 doc += QString::fromLatin1( "</li></ul>" );
1385 if ( solutions.count() ) {
1386 doc += QString::fromLatin1( "<h3>" );
1387 doc += i18n( "Possible Solutions:" );
1388 doc += QString::fromLatin1( "</h3><ul><li>" );
1389 doc += solutions.join( "</li><li>" );
1390 doc += QString::fromLatin1( "</li></ul>" );
1392 doc += QString::fromLatin1( "</body></html>" );
1400 void KHTMLPart::slotFinished( KIO::Job * job )
1404 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
1407 emit canceled( job->errorString() );
1409 // TODO: what else ?
1416 //kdDebug( 6050 ) << "slotFinished" << endl;
1418 KHTMLPageCache::self()->endData(d->m_cacheId);
1420 if ( d->m_doc && d->m_doc->docLoader()->expireDate() && m_url.protocol().lower().startsWith("http"))
1421 KIO::http_update_cache(m_url, false, d->m_doc->docLoader()->expireDate());
1423 d->m_workingURL = KURL();
1426 if (d->m_doc->parsing())
1427 end(); //will emit completed()
1431 void KHTMLPart::childBegin()
1433 // We need to do this when the child is created so as to avoid the bogus state of the parent's
1434 // child->m_bCompleted being false but the child's m_bComplete being true. If the child gets
1435 // an error early on, we had trouble where checkingComplete on the child was a NOP because
1436 // it thought it was already complete, and thus the parent was never signaled, and never set
1437 // its child->m_bComplete.
1438 d->m_bComplete = false;
1442 void KHTMLPart::begin( const KURL &url, int xOffset, int yOffset )
1445 // If we aren't loading an actual URL, then we need to make sure
1446 // that we have at least an empty document. createEmptyDocument will
1447 // do that if we don't have a document already.
1448 if (d->m_workingURL.isEmpty()) {
1449 KWQ(this)->createEmptyDocument();
1456 KWQ(this)->partClearedInBegin();
1459 // Only do this after clearing the part, so that JavaScript can
1460 // clean up properly if it was on for the last load.
1462 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
1464 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
1467 d->m_bCleared = false;
1469 d->m_bComplete = false;
1470 d->m_bLoadEventEmitted = false;
1474 KHTMLFactory::vLinks()->insert( KWQ(this)->requestedURLString() );
1476 QString urlString = url.url();
1477 KHTMLFactory::vLinks()->insert( urlString );
1478 QString urlString2 = url.prettyURL();
1479 if ( urlString != urlString2 ) {
1480 KHTMLFactory::vLinks()->insert( urlString2 );
1488 KParts::URLArgs args( d->m_extension->urlArgs() );
1489 args.xOffset = xOffset;
1490 args.yOffset = yOffset;
1491 d->m_extension->setURLArgs( args );
1494 ref.setUser(QSTRING_NULL);
1495 ref.setPass(QSTRING_NULL);
1496 ref.setRef(QSTRING_NULL);
1497 d->m_referrer = ref.protocol().startsWith("http") ? ref.url() : "";
1502 // We don't need KDE chained URI handling or window caption setting
1503 if ( !m_url.isEmpty() )
1508 if ( !m_url.isEmpty() )
1510 KURL::List lst = KURL::split( m_url );
1511 if ( !lst.isEmpty() )
1512 baseurl = *lst.begin();
1514 KURL title( baseurl );
1515 title.setRef( QString::null );
1516 title.setQuery( QString::null );
1517 emit setWindowCaption( title.url() );
1520 emit setWindowCaption( i18n( "no title", "* Unknown *" ) );
1523 if (args.serviceType == "text/xml" || args.serviceType == "application/xml" || args.serviceType == "application/xhtml+xml" ||
1524 args.serviceType == "text/xsl" || args.serviceType == "application/rss+xml" || args.serviceType == "application/atom+xml")
1525 d->m_doc = DOMImplementationImpl::instance()->createDocument( d->m_view );
1527 d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
1530 if (!d->m_doc->attached())
1531 d->m_doc->attach( );
1532 d->m_doc->setURL( m_url.url() );
1533 // We prefer m_baseURL over m_url because m_url changes when we are
1534 // about to load a new page.
1535 d->m_doc->setBaseURL( baseurl.url() );
1538 d->m_doc->setDecoder(d->m_decoder);
1541 d->m_doc->docLoader()->setShowAnimations( KHTMLFactory::defaultHTMLSettings()->showAnimations() );
1543 d->m_doc->docLoader()->setShowAnimations( d->m_settings->showAnimations() );
1547 KWQ(this)->updatePolicyBaseURL();
1551 d->m_paUseStylesheet->setItems(QStringList());
1552 d->m_paUseStylesheet->setEnabled( false );
1556 setAutoloadImages( KHTMLFactory::defaultHTMLSettings()->autoLoadImages() );
1557 QString userStyleSheet = KHTMLFactory::defaultHTMLSettings()->userStyleSheet();
1559 setAutoloadImages( d->m_settings->autoLoadImages() );
1560 QString userStyleSheet = d->m_settings->userStyleSheet();
1563 if ( !userStyleSheet.isEmpty() )
1564 setUserStyleSheet( KURL( userStyleSheet ) );
1567 KWQ(this)->restoreDocumentState();
1569 d->m_doc->setRestoreState(args.docState);
1573 d->m_doc->setParsing(true);
1576 d->m_view->resizeContents( 0, 0 );
1577 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
1580 emit d->m_extension->enableAction( "print", true );
1583 d->m_doc->setParsing(true);
1586 void KHTMLPart::write( const char *str, int len )
1588 if ( !d->m_decoder ) {
1589 d->m_decoder = new Decoder;
1590 if (!d->m_encoding.isNull())
1591 d->m_decoder->setEncoding(d->m_encoding.latin1(),
1592 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
1594 // Inherit the default encoding from the parent frame if there is one.
1595 const char *defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
1596 ? parentPart()->d->m_decoder->encoding() : settings()->encoding().latin1();
1597 d->m_decoder->setEncoding(defaultEncoding, Decoder::DefaultEncoding);
1601 d->m_doc->setDecoder(d->m_decoder);
1608 len = strlen( str );
1610 QString decoded = d->m_decoder->decode( str, len );
1612 if(decoded.isEmpty()) return;
1614 if(d->m_bFirstData) {
1615 // determine the parse mode
1616 d->m_doc->determineParseMode( decoded );
1617 d->m_bFirstData = false;
1619 //kdDebug(6050) << "KHTMLPart::write haveEnc = " << d->m_haveEncoding << endl;
1620 // ### this is still quite hacky, but should work a lot better than the old solution
1621 if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
1622 d->m_doc->recalcStyle( NodeImpl::Force );
1626 jScript()->appendSourceFile(m_url.url(),decoded);
1627 Tokenizer* t = d->m_doc->tokenizer();
1630 t->write( decoded, true );
1633 void KHTMLPart::write( const QString &str )
1638 if(d->m_bFirstData) {
1639 // determine the parse mode
1640 d->m_doc->setParseMode( DocumentImpl::Strict );
1641 d->m_bFirstData = false;
1644 jScript()->appendSourceFile(m_url.url(),str);
1645 Tokenizer* t = d->m_doc->tokenizer();
1647 t->write( str, true );
1650 void KHTMLPart::end()
1652 // make sure nothing's left in there...
1654 write(d->m_decoder->flush());
1656 d->m_doc->finishParsing();
1658 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
1659 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1660 // become true. An example is when a subframe is a pure text doc, and that subframe is the
1661 // last one to complete.
1665 void KHTMLPart::stop()
1667 // make sure nothing's left in there...
1668 Tokenizer* t = d->m_doc ? d->m_doc->tokenizer() : 0;
1672 d->m_doc->finishParsing();
1674 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
1675 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1676 // become true. An example is when a subframe is a pure text doc, and that subframe is the
1677 // last one to complete.
1683 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
1685 if (!d->m_view) return;
1686 d->m_view->paint(p, rc, yOff, more);
1691 void KHTMLPart::stopAnimations()
1694 d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
1696 ConstFrameIt it = d->m_frames.begin();
1697 ConstFrameIt end = d->m_frames.end();
1698 for (; it != end; ++it )
1699 if ( !( *it ).m_part.isNull() && ( *it ).m_part->inherits( "KHTMLPart" ) ) {
1700 KParts::ReadOnlyPart* p = ( *it ).m_part;
1701 static_cast<KHTMLPart*>( p )->stopAnimations();
1705 void KHTMLPart::gotoAnchor()
1707 if (m_url.hasRef()) {
1708 QString ref = m_url.encodedHtmlRef();
1709 if (!gotoAnchor(ref)) {
1710 // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
1711 // Decoding here has to match encoding in completeURL, which means it has to use the
1712 // page's encoding rather than UTF-8.
1715 gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()->mibEnum()));
1717 gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()));
1723 void KHTMLPart::slotFinishedParsing()
1725 d->m_doc->setParsing(false);
1726 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
1729 return; // We are probably being destructed.
1734 return; // We are being destroyed by something checkCompleted called.
1736 // check if the scrollbars are really needed for the content
1737 // if not, remove them, relayout, and repaint
1739 d->m_view->restoreScrollBar();
1743 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
1746 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1747 KHTMLPart* p = this;
1750 p->d->m_totalObjectCount++;
1751 p = p->parentPart();
1752 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount )
1753 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1759 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
1762 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1763 KHTMLPart* p = this;
1766 p->d->m_loadedObjects++;
1767 p = p->parentPart();
1768 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount && d->m_jobPercent >= 100 )
1769 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1779 void KHTMLPart::slotProgressUpdate()
1782 if ( d->m_loadedObjects < d->m_totalObjectCount )
1783 percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
1785 percent = d->m_jobPercent;
1787 if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
1788 emit d->m_extension->infoMessage( i18n( "%1 of 1 Image loaded", "%1 of %n Images loaded", d->m_totalObjectCount ).arg( d->m_loadedObjects ) );
1790 emit d->m_extension->loadingProgress( percent );
1793 void KHTMLPart::slotJobSpeed( KIO::Job* /*job*/, unsigned long speed )
1795 emit d->m_extension->speedProgress( speed );
1798 void KHTMLPart::slotJobPercent( KIO::Job* /*job*/, unsigned long percent )
1800 d->m_jobPercent = percent;
1802 if ( !parentPart() )
1803 QTimer::singleShot( 0, this, SLOT( slotProgressUpdate() ) );
1808 void KHTMLPart::checkCompleted()
1810 // kdDebug( 6050 ) << "KHTMLPart::checkCompleted() parsing: " << d->m_doc->parsing() << endl;
1811 // kdDebug( 6050 ) << " complete: " << d->m_bComplete << endl;
1814 // restore the cursor position
1815 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
1817 if (d->m_focusNodeNumber >= 0)
1818 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
1820 d->m_doc->setFocusNode(0);
1821 d->m_focusNodeRestored = true;
1825 // Any frame that hasn't completed yet ?
1826 ConstFrameIt it = d->m_frames.begin();
1827 ConstFrameIt end = d->m_frames.end();
1828 for (; it != end; ++it )
1829 if ( !(*it).m_bCompleted )
1832 // Are we still parsing - or have we done the completed stuff already ?
1833 if ( d->m_bComplete || (d->m_doc && d->m_doc->parsing()) )
1836 // Still waiting for images/scripts from the loader ?
1838 if ( d->m_doc && d->m_doc->docLoader() )
1839 requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
1845 // Now do what should be done when we are really completed.
1846 d->m_bComplete = true;
1848 checkEmitLoadEvent(); // if we didn't do it before
1851 // check that the view has not been moved by the user
1852 if ( !m_url.hasRef() && d->m_view->contentsY() == 0 )
1853 d->m_view->setContentsPos( d->m_extension->urlArgs().xOffset,
1854 d->m_extension->urlArgs().yOffset );
1857 if ( d->m_scheduledRedirection != noRedirectionScheduled )
1859 // Do not start redirection for frames here! That action is
1860 // deferred until the parent emits a completed signal.
1861 if ( parentPart() == 0 )
1862 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1864 emit completed( true );
1868 if ( d->m_bPendingChildRedirection )
1869 emit completed ( true );
1875 // find the alternate stylesheets
1878 sheets = d->m_doc->availableStyleSheets();
1879 d->m_paUseStylesheet->setItems( sheets );
1880 d->m_paUseStylesheet->setEnabled( !sheets.isEmpty() );
1881 if (!sheets.isEmpty())
1883 d->m_paUseStylesheet->setCurrentItem(kMax(sheets.findIndex(d->m_sheetUsed), 0));
1884 slotUseStylesheet();
1888 emit setStatusBarText(i18n("Done."));
1892 kdDebug(6050) << "DONE: " <<d->m_parsetime.elapsed() << endl;
1896 void KHTMLPart::checkEmitLoadEvent()
1898 if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
1900 ConstFrameIt it = d->m_frames.begin();
1901 ConstFrameIt end = d->m_frames.end();
1902 for (; it != end; ++it )
1903 if ( !(*it).m_bCompleted ) // still got a frame running -> too early
1907 // All frames completed -> set their domain to the frameset's domain
1908 // This must only be done when loading the frameset initially (#22039),
1909 // not when following a link in a frame (#44162).
1912 DOMString domain = d->m_doc->domain();
1913 ConstFrameIt it = d->m_frames.begin();
1914 ConstFrameIt end = d->m_frames.end();
1915 for (; it != end; ++it )
1917 KParts::ReadOnlyPart *p = (*it).m_part;
1918 if ( p && p->inherits( "KHTMLPart" ))
1920 KHTMLPart* htmlFrame = static_cast<KHTMLPart *>(p);
1921 if (htmlFrame->d->m_doc)
1923 kdDebug() << "KHTMLPart::checkCompleted setting frame domain to " << domain.string() << endl;
1924 htmlFrame->d->m_doc->setDomain( domain );
1930 d->m_bLoadEventEmitted = true;
1931 d->m_bUnloadEventEmitted = false;
1936 const KHTMLSettings *KHTMLPart::settings() const
1938 return d->m_settings;
1941 #ifndef KDE_NO_COMPAT
1942 KURL KHTMLPart::baseURL() const
1944 if ( !d->m_doc ) return KURL();
1946 return d->m_doc->baseURL();
1949 QString KHTMLPart::baseTarget() const
1951 if ( !d->m_doc ) return QString::null;
1953 return d->m_doc->baseTarget();
1957 KURL KHTMLPart::completeURL( const QString &url )
1959 if ( !d->m_doc ) return url;
1963 return KURL(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
1966 return KURL( d->m_doc->completeURL( url ) );
1969 void KHTMLPart::scheduleRedirection( double delay, const QString &url, bool doLockHistory)
1971 kdDebug(6050) << "KHTMLPart::scheduleRedirection delay=" << delay << " url=" << url << endl;
1972 if (delay < 0 || delay > INT_MAX / 1000)
1974 if ( d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect )
1976 d->m_scheduledRedirection = redirectionScheduled;
1977 d->m_delayRedirect = delay;
1978 d->m_redirectURL = url;
1979 d->m_redirectLockHistory = doLockHistory;
1980 d->m_redirectUserGesture = false;
1982 d->m_redirectionTimer.stop();
1983 if ( d->m_bComplete )
1984 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1988 void KHTMLPart::scheduleLocationChange(const QString &url, bool lockHistory, bool userGesture)
1990 // Handle a location change of a page with no document as a special case.
1991 // This may happen when a frame changes the location of another frame.
1992 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
1993 d->m_delayRedirect = 0;
1994 d->m_redirectURL = url;
1995 d->m_redirectLockHistory = lockHistory;
1996 d->m_redirectUserGesture = userGesture;
1997 d->m_redirectionTimer.stop();
1999 d->m_redirectionTimer.start(0, true);
2002 bool KHTMLPart::isScheduledLocationChangePending() const
2004 switch (d->m_scheduledRedirection) {
2005 case noRedirectionScheduled:
2006 case redirectionScheduled:
2008 case historyNavigationScheduled:
2009 case locationChangeScheduled:
2010 case locationChangeScheduledDuringLoad:
2016 void KHTMLPart::scheduleHistoryNavigation( int steps )
2019 // navigation will always be allowed in the 0 steps case, which is OK because
2020 // that's supposed to force a reload.
2021 if (!KWQ(this)->canGoBackOrForward(steps)) {
2022 cancelRedirection();
2027 d->m_scheduledRedirection = historyNavigationScheduled;
2028 d->m_delayRedirect = 0;
2029 d->m_redirectURL = QString::null;
2030 d->m_scheduledHistoryNavigationSteps = steps;
2031 d->m_redirectionTimer.stop();
2033 d->m_redirectionTimer.start(0, true);
2036 void KHTMLPart::cancelRedirection(bool cancelWithLoadInProgress)
2039 d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
2040 d->m_scheduledRedirection = noRedirectionScheduled;
2041 d->m_redirectionTimer.stop();
2045 void KHTMLPart::slotRedirect()
2047 if (d->m_scheduledRedirection == historyNavigationScheduled) {
2048 d->m_scheduledRedirection = noRedirectionScheduled;
2050 // Special case for go(0) from a frame -> reload only the frame
2051 // go(i!=0) from a frame navigates into the history of the frame only,
2052 // in both IE and NS (but not in Mozilla).... we can't easily do that
2054 if (d->m_scheduledHistoryNavigationSteps == 0) // add && parentPart() to get only frames, but doesn't matter
2055 openURL( url() ); /// ## need args.reload=true?
2057 if (d->m_extension) {
2058 BrowserInterface *interface = d->m_extension->browserInterface();
2060 interface->callMethod( "goHistory(int)", d->m_scheduledHistoryNavigationSteps );
2066 QString u = d->m_redirectURL;
2067 d->m_scheduledRedirection = noRedirectionScheduled;
2068 d->m_delayRedirect = 0;
2069 d->m_redirectURL = QString::null;
2070 if ( u.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
2072 QString script = KURL::decode_string( u.right( u.length() - 11 ) );
2073 //kdDebug( 6050 ) << "KHTMLPart::slotRedirect script=" << script << endl;
2074 QVariant res = executeScript( script, d->m_redirectUserGesture );
2075 if ( res.type() == QVariant::String ) {
2077 write( res.asString() );
2082 KParts::URLArgs args;
2083 if ( urlcmp( u, m_url.url(), true, false ) )
2086 args.setLockHistory( d->m_redirectLockHistory );
2087 urlSelected( u, 0, 0, "_self", args );
2090 void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url)
2092 // the slave told us that we got redirected
2093 // kdDebug( 6050 ) << "redirection by KIO to " << url.url() << endl;
2094 emit d->m_extension->setLocationBarURL( url.prettyURL() );
2095 d->m_workingURL = url;
2100 bool KHTMLPart::setEncoding( const QString &name, bool override )
2102 d->m_encoding = name;
2103 d->m_haveEncoding = override;
2105 if( !m_url.isEmpty() ) {
2110 d->m_restored = true;
2112 d->m_restored = false;
2120 QString KHTMLPart::encoding() const
2122 if(d->m_haveEncoding && !d->m_encoding.isEmpty())
2123 return d->m_encoding;
2125 if(d->m_decoder && d->m_decoder->encoding())
2126 return QString(d->m_decoder->encoding());
2128 return(settings()->encoding());
2131 void KHTMLPart::setUserStyleSheet(const KURL &url)
2133 if ( d->m_doc && d->m_doc->docLoader() )
2134 (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
2137 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
2140 d->m_doc->setUserStyleSheet( styleSheet );
2143 bool KHTMLPart::gotoAnchor( const QString &name )
2148 NodeImpl *n = d->m_doc->getElementById(name);
2150 HTMLCollectionImpl *anchors =
2151 new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
2153 n = anchors->namedItem(name, !d->m_doc->inCompatMode());
2157 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
2159 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2160 if (!n && !(name.isEmpty() || name.lower() == "top")) {
2161 kdDebug(6050) << "KHTMLPart::gotoAnchor node '" << name << "' not found" << endl;
2165 // We need to update the layout before scrolling, otherwise we could
2166 // really mess things up if an anchor scroll comes at a bad moment.
2168 d->m_doc->updateRendering();
2169 // Only do a layout if changes have occurred that make it necessary.
2170 if ( d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() ) {
2171 d->m_view->layout();
2177 static_cast<HTMLElementImpl *>(n)->getUpperLeftCorner(x, y);
2179 // Scroll to actual top left of element with no slop, since some pages expect anchors to be exactly scrolled to.
2181 // Call recursive version so this will expose correctly from within nested frames.
2182 d->m_view->setContentsPosRecursive(x, y);
2184 d->m_view->setContentsPos(x, y);
2190 void KHTMLPart::setStandardFont( const QString &name )
2192 d->m_settings->setStdFontName(name);
2195 void KHTMLPart::setFixedFont( const QString &name )
2197 d->m_settings->setFixedFontName(name);
2202 void KHTMLPart::setURLCursor( const QCursor &c )
2204 d->m_linkCursor = c;
2209 QCursor KHTMLPart::urlCursor() const
2212 // Don't load the link cursor until it's actually used.
2213 // Also, we don't need setURLCursor.
2214 // This speeds up startup time.
2215 return KCursor::handCursor();
2217 return d->m_linkCursor;
2221 bool KHTMLPart::onlyLocalReferences() const
2223 return d->m_onlyLocalReferences;
2226 void KHTMLPart::setOnlyLocalReferences(bool enable)
2228 d->m_onlyLocalReferences = enable;
2233 void KHTMLPart::findTextBegin(NodeImpl *startNode, int startPos)
2235 d->m_findPos = startPos;
2236 d->m_findNode = startNode;
2239 bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensitive, bool isRegExp )
2244 if(!d->m_findNode) {
2245 if (d->m_doc->isHTMLDocument())
2246 d->m_findNode = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
2248 d->m_findNode = d->m_doc;
2251 if ( !d->m_findNode )
2253 kdDebug() << "KHTMLPart::findTextNext no findNode -> return false" << endl;
2256 if ( d->m_findNode->id() == ID_FRAMESET )
2258 kdDebug() << "KHTMLPart::findTextNext FRAMESET -> return false" << endl;
2264 if( (d->m_findNode->nodeType() == Node::TEXT_NODE || d->m_findNode->nodeType() == Node::CDATA_SECTION_NODE) && d->m_findNode->renderer() )
2266 DOMString nodeText = d->m_findNode->nodeValue();
2267 DOMStringImpl *t = nodeText.implementation();
2268 QConstString s(t->s, t->l);
2272 QRegExp matcher( str );
2273 matcher.setCaseSensitive( caseSensitive );
2274 d->m_findPos = matcher.search(s.string(), d->m_findPos+1);
2275 if ( d->m_findPos != -1 )
2276 matchLen = matcher.matchedLength();
2279 d->m_findPos = s.string().find(str, d->m_findPos+1, caseSensitive);
2280 matchLen = str.length();
2283 if(d->m_findPos != -1)
2286 static_cast<khtml::RenderText *>(d->m_findNode->renderer())
2287 ->posOfChar(d->m_findPos, x, y);
2288 d->m_view->setContentsPos(x-50, y-50);
2289 Position p1(d->m_findNode, d->m_findPos);
2290 Position p2(d->m_findNode, d->m_findPos + matchLen);
2291 setSelection(Selection(p1, p2));
2301 next = d->m_findNode->firstChild();
2303 if(!next) next = d->m_findNode->nextSibling();
2304 while(d->m_findNode && !next) {
2305 d->m_findNode = d->m_findNode->parentNode();
2306 if( d->m_findNode ) {
2307 next = d->m_findNode->nextSibling();
2313 next = d->m_findNode->lastChild();
2315 if (!next ) next = d->m_findNode->previousSibling();
2316 while ( d->m_findNode && !next )
2318 d->m_findNode = d->m_findNode->parentNode();
2321 next = d->m_findNode->previousSibling();
2326 d->m_findNode = next;
2327 if(!d->m_findNode) return false;
2331 #endif // APPLE_CHANGES
2333 QString KHTMLPart::text(const DOM::Range &r) const
2335 return plainText(r);
2338 QString KHTMLPart::selectedText() const
2340 return text(selection().toRange());
2343 bool KHTMLPart::hasSelection() const
2345 return d->m_selection.isCaretOrRange();
2348 const Selection &KHTMLPart::selection() const
2350 return d->m_selection;
2353 ETextGranularity KHTMLPart::selectionGranularity() const
2355 return d->m_selectionGranularity;
2358 const Selection &KHTMLPart::dragCaret() const
2360 return d->m_dragCaret;
2363 const Selection &KHTMLPart::mark() const
2368 void KHTMLPart::setMark(const Selection &s)
2373 void KHTMLPart::setSelection(const Selection &s, bool closeTyping, bool keepTypingStyle)
2375 if (d->m_selection == s) {
2379 clearCaretRectIfNeeded();
2382 Selection oldSelection = d->m_selection;
2387 setFocusNodeIfNeeded();
2389 selectionLayoutChanged();
2391 // Always clear the x position used for vertical arrow navigation.
2392 // It will be restored by the vertical arrow navigation code if necessary.
2393 d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
2396 TypingCommand::closeTyping(lastEditCommand());
2398 if (!keepTypingStyle)
2402 KWQ(this)->respondToChangedSelection(oldSelection, closeTyping);
2405 emitSelectionChanged();
2408 void KHTMLPart::setDragCaret(const Selection &dragCaret)
2410 if (d->m_dragCaret != dragCaret) {
2411 d->m_dragCaret.needsCaretRepaint();
2412 d->m_dragCaret = dragCaret;
2413 d->m_dragCaret.needsCaretRepaint();
2417 void KHTMLPart::clearSelection()
2419 setSelection(Selection());
2422 void KHTMLPart::invalidateSelection()
2424 clearCaretRectIfNeeded();
2425 d->m_selection.setNeedsLayout();
2426 selectionLayoutChanged();
2429 void KHTMLPart::setCaretVisible(bool flag)
2431 if (d->m_caretVisible == flag)
2433 clearCaretRectIfNeeded();
2435 setFocusNodeIfNeeded();
2436 d->m_caretVisible = flag;
2437 selectionLayoutChanged();
2441 void KHTMLPart::slotClearSelection()
2447 void KHTMLPart::clearCaretRectIfNeeded()
2449 if (d->m_caretPaint) {
2450 d->m_caretPaint = false;
2451 d->m_selection.needsCaretRepaint();
2455 void KHTMLPart::setFocusNodeIfNeeded()
2457 if (!xmlDocImpl() || d->m_selection.isNone() || !d->m_isFocused)
2460 NodeImpl *n = d->m_selection.start().node();
2461 NodeImpl *target = (n && n->isContentEditable()) ? n : 0;
2463 while (n && n != d->m_selection.end().node()) {
2464 if (n->isContentEditable()) {
2468 n = n->traverseNextNode();
2471 assert(target == 0 || target->isContentEditable());
2474 for ( ; target; target = target->parentNode()) {
2475 if (target->isMouseFocusable()) {
2476 xmlDocImpl()->setFocusNode(target);
2480 xmlDocImpl()->setFocusNode(0);
2484 void KHTMLPart::selectionLayoutChanged()
2486 // kill any caret blink timer now running
2487 if (d->m_caretBlinkTimer >= 0) {
2488 killTimer(d->m_caretBlinkTimer);
2489 d->m_caretBlinkTimer = -1;
2492 // see if a new caret blink timer needs to be started
2493 if (d->m_caretVisible && d->m_caretBlinks &&
2494 d->m_selection.isCaret() && d->m_selection.start().node()->isContentEditable()) {
2495 d->m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
2496 d->m_caretPaint = true;
2497 d->m_selection.needsCaretRepaint();
2501 d->m_doc->updateSelection();
2504 void KHTMLPart::setXPosForVerticalArrowNavigation(int x)
2506 d->m_xPosForVerticalArrowNavigation = x;
2509 int KHTMLPart::xPosForVerticalArrowNavigation() const
2511 return d->m_xPosForVerticalArrowNavigation;
2514 void KHTMLPart::timerEvent(QTimerEvent *e)
2516 if (e->timerId() == d->m_caretBlinkTimer &&
2517 d->m_caretVisible &&
2519 d->m_selection.isCaret()) {
2520 if (d->m_bMousePressed) {
2521 if (!d->m_caretPaint) {
2522 d->m_caretPaint = true;
2523 d->m_selection.needsCaretRepaint();
2527 d->m_caretPaint = !d->m_caretPaint;
2528 d->m_selection.needsCaretRepaint();
2533 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
2535 if (d->m_caretPaint)
2536 d->m_selection.paintCaret(p, rect);
2539 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
2541 d->m_dragCaret.paintCaret(p, rect);
2546 void KHTMLPart::overURL( const QString &url, const QString &target, bool shiftPressed )
2548 if ( !d->m_kjsStatusBarText.isEmpty() && !shiftPressed ) {
2550 emit setStatusBarText( d->m_kjsStatusBarText );
2551 d->m_kjsStatusBarText = QString::null;
2557 if ( url.isEmpty() )
2559 emit setStatusBarText(completeURL(url).htmlURL());
2563 if (url.find( QString::fromLatin1( "javascript:" ),0, false ) != -1 )
2565 emit setStatusBarText( KURL::decode_string( url.mid( url.find( "javascript:", 0, false ) ) ) );
2569 KURL u = completeURL(url);
2571 // special case for <a href="">
2572 if ( url.isEmpty() )
2573 u.setFileName( url );
2577 KMimeType::Ptr typ = KMimeType::findByURL( u );
2580 com = typ->comment( u, false );
2582 if ( u.isMalformed() )
2584 emit setStatusBarText(u.htmlURL());
2588 if ( u.isLocalFile() )
2590 // TODO : use KIO::stat() and create a KFileItem out of its result,
2591 // to use KFileItem::statusBarText()
2592 QCString path = QFile::encodeName( u.path() );
2595 bool ok = !stat( path.data(), &buff );
2598 if (ok) ok = !lstat( path.data(), &lbuff );
2600 QString text = u.htmlURL();
2601 QString text2 = text;
2603 if (ok && S_ISLNK( lbuff.st_mode ) )
2607 tmp = i18n( "Symbolic Link");
2609 tmp = i18n("%1 (Link)").arg(com);
2610 char buff_two[1024];
2612 int n = readlink ( path.data(), buff_two, 1022);
2617 emit setStatusBarText(text2);
2626 else if ( ok && S_ISREG( buff.st_mode ) )
2628 if (buff.st_size < 1024)
2629 text = i18n("%2 (%1 bytes)").arg((long) buff.st_size).arg(text2); // always put the URL last, in case it contains '%'
2632 float d = (float) buff.st_size/1024.0;
2633 text = i18n("%1 (%2 K)").arg(text2).arg(KGlobal::locale()->formatNumber(d, 2)); // was %.2f
2638 else if ( ok && S_ISDIR( buff.st_mode ) )
2648 emit setStatusBarText(text);
2653 if (target == QString::fromLatin1("_blank"))
2655 extra = i18n(" (In new window)");
2657 else if (!target.isEmpty() &&
2658 (target != QString::fromLatin1("_top")) &&
2659 (target != QString::fromLatin1("_self")) &&
2660 (target != QString::fromLatin1("_parent")))
2662 extra = i18n(" (In other frame)");
2665 if (u.protocol() == QString::fromLatin1("mailto")) {
2666 QString mailtoMsg/* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
2667 mailtoMsg += i18n("Email to: ") + KURL::decode_string(u.path());
2668 QStringList queries = QStringList::split('&', u.query().mid(1));
2669 for (QStringList::Iterator it = queries.begin(); it != queries.end(); ++it)
2670 if ((*it).startsWith(QString::fromLatin1("subject=")))
2671 mailtoMsg += i18n(" - Subject: ") + KURL::decode_string((*it).mid(8));
2672 else if ((*it).startsWith(QString::fromLatin1("cc=")))
2673 mailtoMsg += i18n(" - CC: ") + KURL::decode_string((*it).mid(3));
2674 else if ((*it).startsWith(QString::fromLatin1("bcc=")))
2675 mailtoMsg += i18n(" - BCC: ") + KURL::decode_string((*it).mid(4));
2676 mailtoMsg.replace(QRegExp("&"), QString("&"));
2677 mailtoMsg.replace(QRegExp("<"), QString("<"));
2678 mailtoMsg.replace(QRegExp(">"), QString(">"));
2679 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), "");
2680 emit setStatusBarText(mailtoMsg);
2683 // Is this check neccessary at all? (Frerich)
2685 else if (u.protocol() == QString::fromLatin1("http")) {
2686 DOM::Node hrefNode = nodeUnderMouse().parentNode();
2687 while (hrefNode.nodeName().string() != QString::fromLatin1("A") && !hrefNode.isNull())
2688 hrefNode = hrefNode.parentNode();
2690 if (!hrefNode.isNull()) {
2691 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
2692 if (!hreflangNode.isNull()) {
2693 QString countryCode = hreflangNode.nodeValue().string().lower();
2694 // Map the language code to an appropriate country code.
2695 if (countryCode == QString::fromLatin1("en"))
2696 countryCode = QString::fromLatin1("gb");
2697 QString flagImg = QString::fromLatin1("<img src=%1>").arg(
2698 locate("locale", QString::fromLatin1("l10n/")
2700 + QString::fromLatin1("/flag.png")));
2701 emit setStatusBarText(flagImg + u.prettyURL() + extra);
2706 emit setStatusBarText(u.htmlURL() + extra);
2710 #endif // APPLE_CHANGES
2712 void KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target,
2713 KParts::URLArgs args )
2715 bool hasTarget = false;
2717 QString target = _target;
2718 if ( target.isEmpty() && d->m_doc )
2719 target = d->m_doc->baseTarget();
2720 if ( !target.isEmpty() )
2723 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
2725 executeScript( KURL::decode_string( url.right( url.length() - 11) ), true );
2729 KURL cURL = completeURL(url);
2731 // special case for <a href="">
2732 if ( url.isEmpty() )
2733 cURL.setFileName( url );
2736 if ( !cURL.isValid() )
2737 // ### ERROR HANDLING
2740 //kdDebug( 6000 ) << "urlSelected: complete URL:" << cURL.url() << " target = " << target << endl;
2743 if ( button == LeftButton && ( state & ShiftButton ) )
2745 KIO::MetaData metaData;
2746 metaData["referrer"] = d->m_referrer;
2747 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As..." ), cURL, metaData );
2751 if (!checkLinkSecurity(cURL,
2752 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?" ),
2757 args.frameName = target;
2759 if ( d->m_bHTTPRefresh )
2761 d->m_bHTTPRefresh = false;
2762 args.metaData()["cache"] = "refresh";
2766 args.metaData().insert("main_frame_request",
2767 parentPart() == 0 ? "TRUE":"FALSE");
2768 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
2769 args.metaData().insert("ssl_activate_warnings", "TRUE");
2773 args.metaData()["referrer"] = d->m_referrer;
2774 KWQ(this)->urlSelected(cURL, button, state, args);
2778 // unknown frame names should open in a new window.
2779 khtml::ChildFrame *frame = recursiveFrameRequest( cURL, args, false );
2782 args.metaData()["referrer"] = d->m_referrer;
2783 requestObject( frame, cURL, args );
2788 if ( !d->m_bComplete && !hasTarget )
2791 if (!d->m_referrer.isEmpty())
2792 args.metaData()["referrer"] = d->m_referrer;
2794 if ( button == MidButton && (state & ShiftButton) )
2796 KParts::WindowArgs winArgs;
2797 winArgs.lowerWindow = true;
2798 KParts::ReadOnlyPart *newPart = 0;
2799 emit d->m_extension->createNewWindow( cURL, args, winArgs, newPart );
2802 emit d->m_extension->openURLRequest( cURL, args );
2803 #endif // APPLE_CHANGES
2808 void KHTMLPart::slotViewDocumentSource()
2811 if (!(url.isLocalFile()) && KHTMLPageCache::self()->isValid(d->m_cacheId))
2813 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2814 if (sourceFile.status() == 0)
2816 KHTMLPageCache::self()->saveData(d->m_cacheId, sourceFile.dataStream());
2818 url.setPath(sourceFile.name());
2822 // emit d->m_extension->openURLRequest( m_url, KParts::URLArgs( false, 0, 0, QString::fromLatin1( "text/plain" ) ) );
2823 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2826 void KHTMLPart::slotViewFrameSource()
2828 KParts::ReadOnlyPart *frame = currentFrame();
2832 KURL url = frame->url();
2833 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
2835 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
2837 if (KHTMLPageCache::self()->isValid(cacheId))
2839 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2840 if (sourceFile.status() == 0)
2842 KHTMLPageCache::self()->saveData(cacheId, sourceFile.dataStream());
2844 url.setPath(sourceFile.name());
2849 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2852 KURL KHTMLPart::backgroundURL() const
2854 // ### what about XML documents? get from CSS?
2855 if (!d->m_doc || !d->m_doc->isHTMLDocument())
2858 QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
2860 return KURL( m_url, relURL );
2863 void KHTMLPart::slotSaveBackground()
2865 KIO::MetaData metaData;
2866 metaData["referrer"] = d->m_referrer;
2867 KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save background image as"), backgroundURL(), metaData );
2870 void KHTMLPart::slotSaveDocument()
2872 KURL srcURL( m_url );
2874 if ( srcURL.fileName(false).isEmpty() )
2875 srcURL.setFileName( "index.html" );
2877 KIO::MetaData metaData;
2879 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files"), d->m_cacheId );
2882 void KHTMLPart::slotSecurity()
2884 // kdDebug( 6050 ) << "Meta Data:" << endl
2885 // << d->m_ssl_peer_cert_subject
2887 // << d->m_ssl_peer_cert_issuer
2889 // << d->m_ssl_cipher
2891 // << d->m_ssl_cipher_desc
2893 // << d->m_ssl_cipher_version
2895 // << d->m_ssl_good_from
2897 // << d->m_ssl_good_until
2899 // << d->m_ssl_cert_state
2902 KSSLInfoDlg *kid = new KSSLInfoDlg(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
2904 if (d->m_bSecurityInQuestion)
2905 kid->setSecurityInQuestion(true);
2907 if (d->m_ssl_in_use) {
2908 KSSLCertificate *x = KSSLCertificate::fromString(d->m_ssl_peer_certificate.local8Bit());
2910 // Set the chain back onto the certificate
2911 QStringList cl = QStringList::split(QString("\n"), d->m_ssl_peer_chain);
2912 QPtrList<KSSLCertificate> ncl;
2914 ncl.setAutoDelete(true);
2915 for (QStringList::Iterator it = cl.begin(); it != cl.end(); ++it) {
2916 KSSLCertificate *y = KSSLCertificate::fromString((*it).local8Bit());
2917 if (y) ncl.append(y);
2920 if (ncl.count() > 0)
2921 x->chain().setChain(ncl);
2927 d->m_ssl_cipher_desc,
2928 d->m_ssl_cipher_version,
2929 d->m_ssl_cipher_used_bits.toInt(),
2930 d->m_ssl_cipher_bits.toInt(),
2931 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt()
2939 void KHTMLPart::slotSaveFrame()
2941 if ( !d->m_activeFrame )
2942 return; // should never be the case, but one never knows :-)
2944 KURL srcURL( static_cast<KParts::ReadOnlyPart *>( d->m_activeFrame )->url() );
2946 if ( srcURL.fileName(false).isEmpty() )
2947 srcURL.setFileName( "index.html" );
2949 KIO::MetaData metaData;
2950 // Referrer unknown?
2951 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files") );
2954 void KHTMLPart::slotSetEncoding()
2956 // first Item is always auto
2957 if(d->m_paSetEncoding->currentItem() == 0)
2958 setEncoding(QString::null, false);
2960 // strip of the language to get the raw encoding again.
2961 QString enc = KGlobal::charsets()->encodingForName(d->m_paSetEncoding->currentText());
2962 setEncoding(enc, true);
2966 void KHTMLPart::slotUseStylesheet()
2968 if (d->m_doc && d->m_paUseStylesheet->currentText() != d->m_sheetUsed) {
2969 d->m_sheetUsed = d->m_paUseStylesheet->currentText();
2970 d->m_doc->updateStyleSelector();
2974 void KHTMLPart::updateActions()
2976 bool frames = false;
2978 QValueList<khtml::ChildFrame>::ConstIterator it = d->m_frames.begin();
2979 QValueList<khtml::ChildFrame>::ConstIterator end = d->m_frames.end();
2980 for (; it != end; ++it )
2981 if ( (*it).m_type == khtml::ChildFrame::Frame )
2987 d->m_paViewFrame->setEnabled( frames );
2988 d->m_paSaveFrame->setEnabled( frames );
2991 d->m_paFind->setText( i18n( "&Find in Frame..." ) );
2993 d->m_paFind->setText( i18n( "&Find..." ) );
2995 KParts::Part *frame = 0;
2998 frame = currentFrame();
3000 bool enableFindAndSelectAll = true;
3003 enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
3005 d->m_paFind->setEnabled( enableFindAndSelectAll );
3006 d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
3008 bool enablePrintFrame = false;
3012 QObject *ext = KParts::BrowserExtension::childObject( frame );
3014 enablePrintFrame = ext->metaObject()->slotNames().contains( "print()" );
3017 d->m_paPrintFrame->setEnabled( enablePrintFrame );
3022 if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
3023 bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
3025 d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
3030 bool KHTMLPart::requestFrame( khtml::RenderPart *frame, const QString &url, const QString &frameName,
3031 const QStringList ¶mNames, const QStringList ¶mValues, bool isIFrame )
3033 // kdDebug( 6050 ) << "childRequest( ..., " << url << ", " << frameName << " )" << endl;
3034 FrameIt it = d->m_frames.find( frameName );
3035 if ( it == d->m_frames.end() )
3037 khtml::ChildFrame child;
3038 // kdDebug( 6050 ) << "inserting new frame into frame map " << frameName << endl;
3039 child.m_name = frameName;
3040 it = d->m_frames.append( child );
3043 (*it).m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
3044 (*it).m_frame = frame;
3045 (*it).m_paramValues = paramNames;
3046 (*it).m_paramNames = paramValues;
3048 // Support for <frame src="javascript:string">
3049 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
3051 if (!processObjectRequest(&(*it), "about:blank", "text/html" ))
3054 KHTMLPart *newPart = static_cast<KHTMLPart *>(&*(*it).m_part);
3055 newPart->replaceContentsWithScriptResult( url );
3060 return requestObject( &(*it), completeURL( url ));
3063 QString KHTMLPart::requestFrameName()
3066 return KWQ(this)->generateFrameName();
3068 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
3072 bool KHTMLPart::requestObject( khtml::RenderPart *frame, const QString &url, const QString &serviceType,
3073 const QStringList ¶mNames, const QStringList ¶mValues )
3075 khtml::ChildFrame child;
3076 QValueList<khtml::ChildFrame>::Iterator it = d->m_objects.append( child );
3077 (*it).m_frame = frame;
3078 (*it).m_type = khtml::ChildFrame::Object;
3079 (*it).m_paramNames = paramNames;
3080 (*it).m_paramValues = paramValues;
3084 completedURL = completeURL(url);
3086 KParts::URLArgs args;
3087 args.serviceType = serviceType;
3088 return requestObject( &(*it), completedURL, args );
3091 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KURL &url, const KParts::URLArgs &_args )
3094 if (!checkLinkSecurity(url))
3097 if ( child->m_bPreloaded )
3099 // kdDebug(6005) << "KHTMLPart::requestObject preload" << endl;
3100 if ( child->m_frame && child->m_part && child->m_part->widget() )
3101 child->m_frame->setWidget( child->m_part->widget() );
3103 child->m_bPreloaded = false;
3107 KParts::URLArgs args( _args );
3111 child->m_run->abort();
3114 if ( child->m_part && !args.reload && urlcmp( child->m_part->url().url(), url.url(), true, true ) )
3115 args.serviceType = child->m_serviceType;
3117 child->m_args = args;
3118 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3119 child->m_serviceName = QString::null;
3120 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
3121 child->m_args.metaData()["referrer"] = d->m_referrer;
3124 child->m_args.metaData().insert("main_frame_request",
3125 parentPart() == 0 ? "TRUE":"FALSE");
3126 child->m_args.metaData().insert("ssl_was_in_use",
3127 d->m_ssl_in_use ? "TRUE":"FALSE");
3128 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
3131 // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
3132 if ((url.isEmpty() || url.url() == "about:blank") && args.serviceType.isEmpty())
3133 args.serviceType = QString::fromLatin1( "text/html" );
3136 return processObjectRequest( child, url, args.serviceType );
3138 if ( args.serviceType.isEmpty() ) {
3139 child->m_run = new KHTMLRun( this, child, url, child->m_args,
3140 child->m_type != khtml::ChildFrame::Frame );
3143 return processObjectRequest( child, url, args.serviceType );
3148 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KURL &_url, const QString &mimetype )
3150 //kdDebug( 6050 ) << "KHTMLPart::processObjectRequest trying to create part for " << mimetype << endl;
3152 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
3153 // by an emitting frame part (emit openURLRequest( blahurl, ... ) . A few lines below we delete the part
3154 // though -> the reference becomes invalid -> crash is likely
3157 // khtmlrun called us this way to indicate a loading error
3158 if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
3160 checkEmitLoadEvent();
3161 child->m_bCompleted = true;
3165 if (child->m_bNotify)
3167 child->m_bNotify = false;
3168 if ( !child->m_args.lockHistory() )
3169 emit d->m_extension->openURLNotify();
3173 if ( child->m_part )
3175 KHTMLPart *part = dynamic_cast<KHTMLPart *>(&*child->m_part);
3181 KParts::ReadOnlyPart *part = KWQ(this)->createPart(*child, url, mimetype);
3182 KHTMLPart *khtml_part = dynamic_cast<KHTMLPart *>(part);
3184 khtml_part->childBegin();
3186 if ( !child->m_services.contains( mimetype ) )
3188 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 );
3193 if ( child->m_frame )
3194 if (child->m_frame->partLoadingErrorNotify( child, url, mimetype ))
3195 return true; // we succeeded after all (a fallback was used)
3197 checkEmitLoadEvent();
3202 if ( child->m_part )
3204 disconnectChild(child);
3206 partManager()->removePart( (KParts::ReadOnlyPart *)child->m_part );
3208 child->m_part->deref();
3211 child->m_serviceType = mimetype;
3212 if ( child->m_frame && part->widget() )
3213 child->m_frame->setWidget( part->widget() );
3216 if ( child->m_type != khtml::ChildFrame::Object )
3217 partManager()->addPart( part, false );
3219 // kdDebug(6005) << "AH! NO FRAME!!!!!" << endl;
3222 child->m_part = part;
3223 assert( ((void*) child->m_part) != 0);
3225 connectChild(child);
3230 child->m_extension = KParts::BrowserExtension::childObject( part );
3232 if ( child->m_extension )
3234 connect( child->m_extension, SIGNAL( openURLNotify() ),
3235 d->m_extension, SIGNAL( openURLNotify() ) );
3237 connect( child->m_extension, SIGNAL( openURLRequestDelayed( const KURL &, const KParts::URLArgs & ) ),
3238 this, SLOT( slotChildURLRequest( const KURL &, const KParts::URLArgs & ) ) );
3240 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ),
3241 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ) );
3242 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs &, const KParts::WindowArgs &, KParts::ReadOnlyPart *& ) ),
3243 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & , const KParts::WindowArgs &, KParts::ReadOnlyPart *&) ) );
3245 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ),
3246 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ) );
3247 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ),
3248 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ) );
3249 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ),
3250 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ) );
3251 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ),
3252 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ) );
3254 connect( child->m_extension, SIGNAL( infoMessage( const QString & ) ),
3255 d->m_extension, SIGNAL( infoMessage( const QString & ) ) );
3257 child->m_extension->setBrowserInterface( d->m_extension->browserInterface() );
3262 checkEmitLoadEvent();
3263 // Some JS code in the load event may have destroyed the part
3264 // In that case, abort
3265 if ( !child->m_part )
3268 if ( child->m_bPreloaded )
3270 if ( child->m_frame && child->m_part )
3271 child->m_frame->setWidget( child->m_part->widget() );
3273 child->m_bPreloaded = false;
3277 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3279 // make sure the part has a way to find out about the mimetype.
3280 // we actually set it in child->m_args in requestObject already,
3281 // but it's useless if we had to use a KHTMLRun instance, as the
3282 // point the run object is to find out exactly the mimetype.
3283 child->m_args.serviceType = mimetype;
3285 child->m_bCompleted = false;
3286 if ( child->m_extension )
3287 child->m_extension->setURLArgs( child->m_args );
3290 // In these cases, the synchronous load would have finished
3291 // before we could connect the signals, so make sure to send the
3292 // completed() signal for the child by hand:
3293 if (url.isEmpty() || url.url() == "about:blank") {
3294 ReadOnlyPart *readOnlyPart = child->m_part;
3295 KHTMLPart *part = dynamic_cast<KHTMLPart *>(readOnlyPart);
3301 if(url.protocol() == "javascript" || url.url() == "about:blank") {
3302 if (!child->m_part->inherits("KHTMLPart"))
3305 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(child->m_part));
3308 if (d->m_doc && p->d->m_doc)
3309 p->d->m_doc->setBaseURL(d->m_doc->baseURL());
3310 if (!url.url().startsWith("about:")) {
3311 p->write(url.path());
3318 else if ( !url.isEmpty() )
3320 //kdDebug( 6050 ) << "opening " << url.url() << " in frame " << child->m_part << endl;
3321 return child->m_part->openURL( url );
3330 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget, const char *widgetName,
3331 QObject *parent, const char *name, const QString &mimetype,
3332 QString &serviceName, QStringList &serviceTypes,
3333 const QStringList ¶ms )
3336 if ( !serviceName.isEmpty() )
3337 constr.append( QString::fromLatin1( "Name == '%1'" ).arg( serviceName ) );
3339 KTrader::OfferList offers = KTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr, QString::null );
3341 if ( offers.isEmpty() )
3344 KService::Ptr service = *offers.begin();
3346 KLibFactory *factory = KLibLoader::self()->factory( QFile::encodeName(service->library()) );
3351 KParts::ReadOnlyPart *res = 0L;
3353 const char *className = "KParts::ReadOnlyPart";
3354 if ( service->serviceTypes().contains( "Browser/View" ) )
3355 className = "Browser/View";
3357 if ( factory->inherits( "KParts::Factory" ) )
3358 res = static_cast<KParts::ReadOnlyPart *>(static_cast<KParts::Factory *>( factory )->createPart( parentWidget, widgetName, parent, name, className, params ));
3360 res = static_cast<KParts::ReadOnlyPart *>(factory->create( parentWidget, widgetName, className ));
3365 serviceTypes = service->serviceTypes();
3366 serviceName = service->name();
3371 KParts::PartManager *KHTMLPart::partManager()
3373 if ( !d->m_manager )
3375 d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this, "khtml part manager" );
3376 d->m_manager->setAllowNestedParts( true );
3377 connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
3378 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
3379 connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ),
3380 this, SLOT( slotPartRemoved( KParts::Part * ) ) );
3383 return d->m_manager;
3388 void KHTMLPart::submitFormAgain()
3390 if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
3391 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 );
3393 delete d->m_submitForm;
3394 d->m_submitForm = 0;
3395 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
3398 void KHTMLPart::submitForm( const char *action, const QString &url, const FormData &formData, const QString &_target, const QString& contentType, const QString& boundary )
3400 kdDebug(6000) << this << ": KHTMLPart::submitForm target=" << _target << " url=" << url << endl;
3401 KURL u = completeURL( url );
3405 // ### ERROR HANDLING!
3410 // Form security checks
3413 /* This is separate for a reason. It has to be _before_ all script, etc,
3414 * AND I don't want to break anything that uses checkLinkSecurity() in
3418 // This causes crashes... needs to be fixed.
3419 if (!d->m_submitForm && u.protocol() != "https" && u.protocol() != "mailto") {
3420 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
3421 int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
3422 "\nA third party may be able to intercept and view this information."
3423 "\nAre you sure you wish to continue?"),
3425 if (rc == KMessageBox::Cancel)
3427 } else { // Going from nonSSL -> nonSSL
3428 KSSLSettings kss(true);
3429 if (kss.warnOnUnencrypted()) {
3430 int rc = KMessageBox::warningContinueCancel(NULL,
3431 i18n("Warning: Your data is about to be transmitted across the network unencrypted."
3432 "\nAre you sure you wish to continue?"),
3435 "WarnOnUnencryptedForm");
3436 // Move this setting into KSSL instead
3437 KConfig *config = kapp->config();
3438 QString grpNotifMsgs = QString::fromLatin1("Notification Messages");
3439 KConfigGroupSaver saver( config, grpNotifMsgs );
3441 if (!config->readBoolEntry("WarnOnUnencryptedForm", true)) {
3442 config->deleteEntry("WarnOnUnencryptedForm");
3444 kss.setWarnOnUnencrypted(false);
3447 if (rc == KMessageBox::Cancel)
3453 if (!d->m_submitForm && u.protocol() == "mailto") {
3454 int rc = KMessageBox::warningContinueCancel(NULL,
3455 i18n("This site is attempting to submit form data via email."),
3458 "WarnTriedEmailSubmit");
3460 if (rc == KMessageBox::Cancel) {
3465 // End form security checks
3467 #endif // APPLE_CHANGES
3469 QString urlstring = u.url();
3471 if ( urlstring.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
3472 urlstring = KURL::decode_string(urlstring);
3473 d->m_executingJavaScriptFormAction = true;
3474 executeScript( urlstring.right( urlstring.length() - 11) );
3475 d->m_executingJavaScriptFormAction = false;
3480 if (!checkLinkSecurity(u,
3481 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?" ),
3486 KParts::URLArgs args;
3488 if (!d->m_referrer.isEmpty())
3489 args.metaData()["referrer"] = d->m_referrer;
3492 args.metaData().insert("main_frame_request",
3493 parentPart() == 0 ? "TRUE":"FALSE");
3494 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
3495 args.metaData().insert("ssl_activate_warnings", "TRUE");
3497 args.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
3499 // Handle mailto: forms
3500 if (u.protocol() == "mailto") {
3501 // 1) Check for attach= and strip it
3502 QString q = u.query().mid(1);
3503 QStringList nvps = QStringList::split("&", q);
3504 bool triedToAttach = false;
3506 for (QStringList::Iterator nvp = nvps.begin(); nvp != nvps.end(); ++nvp) {
3507 QStringList pair = QStringList::split("=", *nvp);
3508 if (pair.count() >= 2) {
3509 if (pair.first().lower() == "attach") {
3510 nvp = nvps.remove(nvp);
3511 triedToAttach = true;
3518 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");
3523 if (contentType.lower() == "multipart/form-data") {
3524 // FIXME: is this correct? I suspect not
3525 bodyEnc = KURL::encode_string(formData.flattenToString());
3526 } else if (contentType.lower() == "text/plain") {
3527 // Convention seems to be to decode, and s/&/\n/
3528 QString tmpbody = formData.flattenToString();
3529 tmpbody.replace('&', '\n');
3530 tmpbody.replace('+', ' ');
3531 tmpbody = KURL::decode_string(tmpbody); // Decode the rest of it
3532 bodyEnc = KURL::encode_string(tmpbody); // Recode for the URL
3534 bodyEnc = KURL::encode_string(formData.flattenToString());
3537 nvps.append(QString("body=%1").arg(bodyEnc));
3542 if ( strcmp( action, "get" ) == 0 ) {
3543 if (u.protocol() != "mailto")
3544 u.setQuery( formData.flattenToString() );
3545 args.setDoPost( false );
3549 args.postData = formData;
3551 args.postData = formData.flatten();
3553 args.setDoPost( true );
3555 // construct some user headers if necessary
3556 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
3557 args.setContentType( "Content-Type: application/x-www-form-urlencoded" );
3558 else // contentType must be "multipart/form-data"
3559 args.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
3562 if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
3563 if( d->m_submitForm ) {
3564 kdDebug(6000) << "KHTMLPart::submitForm ABORTING!" << endl;
3567 d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
3568 d->m_submitForm->submitAction = action;
3569 d->m_submitForm->submitUrl = url;
3570 d->m_submitForm->submitFormData = formData;
3571 d->m_submitForm->target = _target;
3572 d->m_submitForm->submitContentType = contentType;
3573 d->m_submitForm->submitBoundary = boundary;
3574 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
3579 KWQ(this)->submitForm( u, args);
3581 emit d->m_extension->openURLRequest( u, args );
3588 void KHTMLPart::popupMenu( const QString &linkUrl )
3592 if ( linkUrl.isEmpty() ) // click on background
3593 popupURL = this->url();
3594 else { // click on link
3595 popupURL = completeURL( linkUrl );
3596 linkKURL = popupURL;
3599 KXMLGUIClient *client = new KHTMLPopupGUIClient( this, d->m_popupMenuXML, linkKURL );
3601 emit d->m_extension->popupMenu( client, QCursor::pos(), popupURL,
3602 QString::fromLatin1( "text/html" ), S_IFREG /*always a file*/ );
3606 emit popupMenu(linkUrl, QCursor::pos());
3611 void KHTMLPart::slotParentCompleted()
3613 if ( d->m_scheduledRedirection != noRedirectionScheduled && !d->m_redirectionTimer.isActive() )
3615 // kdDebug(6050) << this << ": Child redirection -> " << d->m_redirectURL << endl;
3616 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
3620 void KHTMLPart::slotChildStarted( KIO::Job *job )
3622 khtml::ChildFrame *child = childFrame( sender() );
3626 child->m_bCompleted = false;
3628 if ( d->m_bComplete )
3631 // WABA: Looks like this belongs somewhere else
3632 if ( !parentPart() ) // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes
3634 emit d->m_extension->openURLNotify();
3637 d->m_bComplete = false;
3638 emit started( job );
3642 void KHTMLPart::slotChildCompleted()
3644 slotChildCompleted( false );
3647 void KHTMLPart::slotChildCompleted( bool complete )
3649 khtml::ChildFrame *child = childFrame( sender() );
3653 child->m_bCompleted = true;
3654 child->m_args = KParts::URLArgs();
3656 if ( complete && parentPart() == 0 )
3657 d->m_bPendingChildRedirection = true;
3664 void KHTMLPart::slotChildURLRequest( const KURL &url, const KParts::URLArgs &args )
3666 khtml::ChildFrame *child = childFrame( sender()->parent() );
3668 QString frameName = args.frameName.lower();
3669 if ( !frameName.isEmpty() )
3671 if ( frameName == QString::fromLatin1( "_top" ) )
3673 emit d->m_extension->openURLRequest( url, args );
3676 else if ( frameName == QString::fromLatin1( "_blank" ) )
3678 emit d->m_extension->createNewWindow( url, args );
3681 else if ( frameName == QString::fromLatin1( "_parent" ) )
3683 KParts::URLArgs newArgs( args );
3684 newArgs.frameName = QString::null;
3686 emit d->m_extension->openURLRequest( url, newArgs );
3689 else if ( frameName != QString::fromLatin1( "_self" ) )
3691 khtml::ChildFrame *_frame = recursiveFrameRequest( url, args );
3695 emit d->m_extension->openURLRequest( url, args );
3703 // TODO: handle child target correctly! currently the script are always executed fur the parent
3704 QString urlStr = url.url();
3705 if ( urlStr.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
3706 executeScript( KURL::decode_string( urlStr.right( urlStr.length() - 11) ) );