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::HTMLDocumentImpl *KHTMLPart::docImpl() const
1100 if ( d && d->m_doc && d->m_doc->isHTMLDocument() )
1101 return static_cast<HTMLDocumentImpl*>(d->m_doc);
1105 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
1112 void KHTMLPart::replaceDocImpl(DocumentImpl* newDoc)
1125 /*bool KHTMLPart::isSSLInUse() const
1127 return d->m_ssl_in_use;
1130 void KHTMLPart::receivedFirstData()
1132 // Leave indented one extra for easier merging.
1134 //kdDebug( 6050 ) << "begin!" << endl;
1136 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1139 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
1140 d->m_workingURL = KURL();
1142 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
1144 // When the first data arrives, the metadata has just been made available
1148 d->m_bSecurityInQuestion = false;
1149 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
1150 kdDebug(6050) << "SSL in use? " << d->m_job->queryMetaData("ssl_in_use") << endl;
1153 KHTMLPart *p = parentPart();
1154 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
1155 while (p->parentPart()) p = p->parentPart();
1157 p->d->m_paSecurity->setIcon( "halfencrypted" );
1158 p->d->m_bSecurityInQuestion = true;
1159 kdDebug(6050) << "parent setIcon half done." << endl;
1163 d->m_paSecurity->setIcon( d->m_ssl_in_use ? "encrypted" : "decrypted" );
1164 kdDebug(6050) << "setIcon " << ( d->m_ssl_in_use ? "encrypted" : "decrypted" ) << " done." << endl;
1166 // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
1168 d->m_ssl_peer_certificate = d->m_job->queryMetaData("ssl_peer_certificate");
1169 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
1170 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
1171 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
1172 d->m_ssl_cipher_desc = d->m_job->queryMetaData("ssl_cipher_desc");
1173 d->m_ssl_cipher_version = d->m_job->queryMetaData("ssl_cipher_version");
1174 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
1175 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
1176 d->m_ssl_cert_state = d->m_job->queryMetaData("ssl_cert_state");
1178 // Check for charset meta-data
1179 QString qData = d->m_job->queryMetaData("charset");
1180 if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
1181 d->m_encoding = qData;
1182 #endif // APPLE_CHANGES
1184 // Support for http-refresh
1185 qData = d->m_job->queryMetaData("http-refresh");
1186 if( !qData.isEmpty() && d->m_metaRefreshEnabled )
1188 kdDebug(6050) << "HTTP Refresh Request: " << qData << endl;
1190 int pos = qData.find( ';' );
1192 pos = qData.find( ',' );
1196 delay = qData.stripWhiteSpace().toDouble();
1198 // We want a new history item if the refresh timeout > 1 second
1199 scheduleRedirection( delay, m_url.url(), delay <= 1);
1201 scheduleRedirection( delay, m_url.url());
1206 int end_pos = qData.length();
1207 delay = qData.left(pos).stripWhiteSpace().toDouble();
1208 while ( qData[++pos] == ' ' );
1209 if ( qData.find( "url", pos, false ) == pos )
1212 while (qData[pos] == ' ' || qData[pos] == '=' )
1214 if ( qData[pos] == '"' )
1217 int index = end_pos-1;
1218 while( index > pos )
1220 if ( qData[index] == '"' )
1229 // We want a new history item if the refresh timeout > 1 second
1230 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ), delay <= 1);
1232 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ));
1235 d->m_bHTTPRefresh = true;
1238 // Support for http last-modified
1239 d->m_lastModified = d->m_job->queryMetaData("modified");
1240 //kdDebug() << "KHTMLPart::slotData metadata modified: " << d->m_lastModified << endl;
1245 void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
1247 assert ( d->m_job == kio_job );
1249 //kdDebug( 6050 ) << "slotData: " << data.size() << endl;
1251 if ( !d->m_workingURL.isEmpty() )
1252 receivedFirstData( );
1254 KHTMLPageCache::self()->addData(d->m_cacheId, data);
1255 write( data.data(), data.size() );
1258 void KHTMLPart::slotRestoreData(const QByteArray &data )
1261 if ( !d->m_workingURL.isEmpty() )
1263 long saveCacheId = d->m_cacheId;
1264 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1265 d->m_cacheId = saveCacheId;
1266 d->m_workingURL = KURL();
1269 //kdDebug( 6050 ) << "slotRestoreData: " << data.size() << endl;
1270 write( data.data(), data.size() );
1272 if (data.size() == 0)
1274 //kdDebug( 6050 ) << "slotRestoreData: <<end of data>>" << endl;
1276 if (d->m_doc && d->m_doc->parsing())
1277 end(); //will emit completed()
1281 void KHTMLPart::showError( KIO::Job* job )
1283 kdDebug() << "KHTMLPart::showError d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
1284 << " d->m_bCleared=" << d->m_bCleared << endl;
1286 if (job->error() == KIO::ERR_NO_CONTENT)
1289 if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
1290 job->showErrorDialog( /*d->m_view*/ );
1293 htmlError( job->error(), job->errorText(), d->m_workingURL );
1297 // This is a protected method, placed here because of it's relevance to showError
1298 void KHTMLPart::htmlError( int errorCode, const QString& text, const KURL& reqUrl )
1300 kdDebug(6050) << "KHTMLPart::htmlError errorCode=" << errorCode << " text=" << text << endl;
1301 // make sure we're not executing any embedded JS
1302 bool bJSFO = d->m_bJScriptForce;
1303 bool bJSOO = d->m_bJScriptOverride;
1304 d->m_bJScriptForce = false;
1305 d->m_bJScriptOverride = true;
1307 QString errText = QString::fromLatin1( "<HTML><HEAD><TITLE>" );
1308 errText += i18n( "Error while loading %1" ).arg( reqUrl.htmlURL() );
1309 errText += QString::fromLatin1( "</TITLE></HEAD><BODY><P>" );
1310 errText += i18n( "An error occured while loading <B>%1</B>:" ).arg( reqUrl.htmlURL() );
1311 errText += QString::fromLatin1( "</P><P>" );
1312 QString kioErrString = KIO::buildErrorString( errorCode, text );
1314 kioErrString.replace(QRegExp("&"), QString("&"));
1315 kioErrString.replace(QRegExp("<"), QString("<"));
1316 kioErrString.replace(QRegExp(">"), QString(">"));
1318 // In case the error string has '\n' in it, replace with <BR/>
1319 kioErrString.replace( QRegExp("\n"), "<BR/>" );
1321 errText += kioErrString;
1322 errText += QString::fromLatin1( "</P></BODY></HTML>" );
1326 d->m_bJScriptForce = bJSFO;
1327 d->m_bJScriptOverride = bJSOO;
1329 // make the working url the current url, so that reload works and
1330 // emit the progress signals to advance one step in the history
1331 // (so that 'back' works)
1332 m_url = reqUrl; // same as d->m_workingURL
1333 d->m_workingURL = KURL();
1337 // following disabled until 3.1
1339 QString errorName, techName, description;
1340 QStringList causes, solutions;
1342 QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
1343 QDataStream stream(raw, IO_ReadOnly);
1345 stream >> errorName >> techName >> description >> causes >> solutions;
1347 QString url, protocol, datetime;
1348 url = reqUrl.prettyURL();
1349 protocol = reqUrl.protocol();
1350 datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
1353 QString doc = QString::fromLatin1( "<html><head><title>" );
1354 doc += i18n( "Error: " );
1356 doc += QString::fromLatin1( " - %1</title></head><body><h1>" ).arg( url );
1357 doc += i18n( "The requested operation could not be completed" );
1358 doc += QString::fromLatin1( "</h1><h2>" );
1360 doc += QString::fromLatin1( "</h2>" );
1361 if ( techName != QString::null ) {
1362 doc += QString::fromLatin1( "<h2>" );
1363 doc += i18n( "Technical Reason: " );
1365 doc += QString::fromLatin1( "</h2>" );
1367 doc += QString::fromLatin1( "<h3>" );
1368 doc += i18n( "Details of the Request:" );
1369 doc += QString::fromLatin1( "</h3><ul><li>" );
1370 doc += i18n( "URL: %1" ).arg( url );
1371 doc += QString::fromLatin1( "</li><li>" );
1372 if ( protocol != QString::null ) {
1373 // uncomment for 3.1... i18n change
1374 // doc += i18n( "Protocol: %1" ).arg( protocol ).arg( protocol );
1375 doc += QString::fromLatin1( "</li><li>" );
1377 doc += i18n( "Date and Time: %1" ).arg( datetime );
1378 doc += QString::fromLatin1( "</li><li>" );
1379 doc += i18n( "Additional Information: %1" ).arg( text );
1380 doc += QString::fromLatin1( "</li></ul><h3>" );
1381 doc += i18n( "Description:" );
1382 doc += QString::fromLatin1( "</h3><p>" );
1384 doc += QString::fromLatin1( "</p>" );
1385 if ( causes.count() ) {
1386 doc += QString::fromLatin1( "<h3>" );
1387 doc += i18n( "Possible Causes:" );
1388 doc += QString::fromLatin1( "</h3><ul><li>" );
1389 doc += causes.join( "</li><li>" );
1390 doc += QString::fromLatin1( "</li></ul>" );
1392 if ( solutions.count() ) {
1393 doc += QString::fromLatin1( "<h3>" );
1394 doc += i18n( "Possible Solutions:" );
1395 doc += QString::fromLatin1( "</h3><ul><li>" );
1396 doc += solutions.join( "</li><li>" );
1397 doc += QString::fromLatin1( "</li></ul>" );
1399 doc += QString::fromLatin1( "</body></html>" );
1407 void KHTMLPart::slotFinished( KIO::Job * job )
1411 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
1414 emit canceled( job->errorString() );
1416 // TODO: what else ?
1423 //kdDebug( 6050 ) << "slotFinished" << endl;
1425 KHTMLPageCache::self()->endData(d->m_cacheId);
1427 if ( d->m_doc && d->m_doc->docLoader()->expireDate() && m_url.protocol().lower().startsWith("http"))
1428 KIO::http_update_cache(m_url, false, d->m_doc->docLoader()->expireDate());
1430 d->m_workingURL = KURL();
1433 if (d->m_doc->parsing())
1434 end(); //will emit completed()
1438 void KHTMLPart::childBegin()
1440 // We need to do this when the child is created so as to avoid the bogus state of the parent's
1441 // child->m_bCompleted being false but the child's m_bComplete being true. If the child gets
1442 // an error early on, we had trouble where checkingComplete on the child was a NOP because
1443 // it thought it was already complete, and thus the parent was never signaled, and never set
1444 // its child->m_bComplete.
1445 d->m_bComplete = false;
1449 void KHTMLPart::begin( const KURL &url, int xOffset, int yOffset )
1452 // If we aren't loading an actual URL, then we need to make sure
1453 // that we have at least an empty document. createEmptyDocument will
1454 // do that if we don't have a document already.
1455 if (d->m_workingURL.isEmpty()) {
1456 KWQ(this)->createEmptyDocument();
1463 KWQ(this)->partClearedInBegin();
1466 // Only do this after clearing the part, so that JavaScript can
1467 // clean up properly if it was on for the last load.
1469 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
1471 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
1474 d->m_bCleared = false;
1476 d->m_bComplete = false;
1477 d->m_bLoadEventEmitted = false;
1481 KHTMLFactory::vLinks()->insert( KWQ(this)->requestedURLString() );
1483 QString urlString = url.url();
1484 KHTMLFactory::vLinks()->insert( urlString );
1485 QString urlString2 = url.prettyURL();
1486 if ( urlString != urlString2 ) {
1487 KHTMLFactory::vLinks()->insert( urlString2 );
1495 KParts::URLArgs args( d->m_extension->urlArgs() );
1496 args.xOffset = xOffset;
1497 args.yOffset = yOffset;
1498 d->m_extension->setURLArgs( args );
1501 ref.setUser(QSTRING_NULL);
1502 ref.setPass(QSTRING_NULL);
1503 ref.setRef(QSTRING_NULL);
1504 d->m_referrer = ref.protocol().startsWith("http") ? ref.url() : "";
1509 // We don't need KDE chained URI handling or window caption setting
1510 if ( !m_url.isEmpty() )
1515 if ( !m_url.isEmpty() )
1517 KURL::List lst = KURL::split( m_url );
1518 if ( !lst.isEmpty() )
1519 baseurl = *lst.begin();
1521 KURL title( baseurl );
1522 title.setRef( QString::null );
1523 title.setQuery( QString::null );
1524 emit setWindowCaption( title.url() );
1527 emit setWindowCaption( i18n( "no title", "* Unknown *" ) );
1530 if (args.serviceType == "text/xml" || args.serviceType == "application/xml" || args.serviceType == "application/xhtml+xml" ||
1531 args.serviceType == "text/xsl" || args.serviceType == "application/rss+xml" || args.serviceType == "application/atom+xml")
1532 d->m_doc = DOMImplementationImpl::instance()->createDocument( d->m_view );
1534 d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
1537 if (!d->m_doc->attached())
1538 d->m_doc->attach( );
1539 d->m_doc->setURL( m_url.url() );
1540 // We prefer m_baseURL over m_url because m_url changes when we are
1541 // about to load a new page.
1542 d->m_doc->setBaseURL( baseurl.url() );
1545 d->m_doc->setDecoder(d->m_decoder);
1548 d->m_doc->docLoader()->setShowAnimations( KHTMLFactory::defaultHTMLSettings()->showAnimations() );
1550 d->m_doc->docLoader()->setShowAnimations( d->m_settings->showAnimations() );
1554 KWQ(this)->updatePolicyBaseURL();
1558 d->m_paUseStylesheet->setItems(QStringList());
1559 d->m_paUseStylesheet->setEnabled( false );
1563 setAutoloadImages( KHTMLFactory::defaultHTMLSettings()->autoLoadImages() );
1564 QString userStyleSheet = KHTMLFactory::defaultHTMLSettings()->userStyleSheet();
1566 setAutoloadImages( d->m_settings->autoLoadImages() );
1567 QString userStyleSheet = d->m_settings->userStyleSheet();
1570 if ( !userStyleSheet.isEmpty() )
1571 setUserStyleSheet( KURL( userStyleSheet ) );
1574 KWQ(this)->restoreDocumentState();
1576 d->m_doc->setRestoreState(args.docState);
1582 d->m_view->resizeContents( 0, 0 );
1583 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
1586 emit d->m_extension->enableAction( "print", true );
1589 d->m_doc->setParsing(true);
1592 void KHTMLPart::write( const char *str, int len )
1594 if ( !d->m_decoder ) {
1595 d->m_decoder = new Decoder;
1596 if (!d->m_encoding.isNull())
1597 d->m_decoder->setEncoding(d->m_encoding.latin1(),
1598 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
1600 // Inherit the default encoding from the parent frame if there is one.
1601 const char *defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
1602 ? parentPart()->d->m_decoder->encoding() : settings()->encoding().latin1();
1603 d->m_decoder->setEncoding(defaultEncoding, Decoder::DefaultEncoding);
1607 d->m_doc->setDecoder(d->m_decoder);
1614 len = strlen( str );
1616 QString decoded = d->m_decoder->decode( str, len );
1618 if(decoded.isEmpty()) return;
1620 if(d->m_bFirstData) {
1621 // determine the parse mode
1622 d->m_doc->determineParseMode( decoded );
1623 d->m_bFirstData = false;
1625 //kdDebug(6050) << "KHTMLPart::write haveEnc = " << d->m_haveEncoding << endl;
1626 // ### this is still quite hacky, but should work a lot better than the old solution
1627 if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
1628 d->m_doc->recalcStyle( NodeImpl::Force );
1632 jScript()->appendSourceFile(m_url.url(),decoded);
1633 Tokenizer* t = d->m_doc->tokenizer();
1636 t->write( decoded, true );
1639 void KHTMLPart::write( const QString &str )
1644 if(d->m_bFirstData) {
1645 // determine the parse mode
1646 d->m_doc->setParseMode( DocumentImpl::Strict );
1647 d->m_bFirstData = false;
1650 jScript()->appendSourceFile(m_url.url(),str);
1651 Tokenizer* t = d->m_doc->tokenizer();
1653 t->write( str, true );
1656 void KHTMLPart::end()
1658 // make sure nothing's left in there...
1660 write(d->m_decoder->flush());
1662 d->m_doc->finishParsing();
1664 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
1665 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1666 // become true. An example is when a subframe is a pure text doc, and that subframe is the
1667 // last one to complete.
1673 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
1675 if (!d->m_view) return;
1676 d->m_view->paint(p, rc, yOff, more);
1681 void KHTMLPart::stopAnimations()
1684 d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
1686 ConstFrameIt it = d->m_frames.begin();
1687 ConstFrameIt end = d->m_frames.end();
1688 for (; it != end; ++it )
1689 if ( !( *it ).m_part.isNull() && ( *it ).m_part->inherits( "KHTMLPart" ) ) {
1690 KParts::ReadOnlyPart* p = ( *it ).m_part;
1691 static_cast<KHTMLPart*>( p )->stopAnimations();
1695 void KHTMLPart::gotoAnchor()
1697 if (m_url.hasRef()) {
1698 QString ref = m_url.encodedHtmlRef();
1699 if (!gotoAnchor(ref)) {
1700 // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
1701 // Decoding here has to match encoding in completeURL, which means it has to use the
1702 // page's encoding rather than UTF-8.
1705 gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()->mibEnum()));
1707 gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()));
1713 void KHTMLPart::slotFinishedParsing()
1715 d->m_doc->setParsing(false);
1716 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
1719 return; // We are probably being destructed.
1724 return; // We are being destroyed by something checkCompleted called.
1726 // check if the scrollbars are really needed for the content
1727 // if not, remove them, relayout, and repaint
1729 d->m_view->restoreScrollBar();
1733 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
1736 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1737 KHTMLPart* p = this;
1740 p->d->m_totalObjectCount++;
1741 p = p->parentPart();
1742 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount )
1743 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1749 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
1752 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1753 KHTMLPart* p = this;
1756 p->d->m_loadedObjects++;
1757 p = p->parentPart();
1758 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount && d->m_jobPercent >= 100 )
1759 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1769 void KHTMLPart::slotProgressUpdate()
1772 if ( d->m_loadedObjects < d->m_totalObjectCount )
1773 percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
1775 percent = d->m_jobPercent;
1777 if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
1778 emit d->m_extension->infoMessage( i18n( "%1 of 1 Image loaded", "%1 of %n Images loaded", d->m_totalObjectCount ).arg( d->m_loadedObjects ) );
1780 emit d->m_extension->loadingProgress( percent );
1783 void KHTMLPart::slotJobSpeed( KIO::Job* /*job*/, unsigned long speed )
1785 emit d->m_extension->speedProgress( speed );
1788 void KHTMLPart::slotJobPercent( KIO::Job* /*job*/, unsigned long percent )
1790 d->m_jobPercent = percent;
1792 if ( !parentPart() )
1793 QTimer::singleShot( 0, this, SLOT( slotProgressUpdate() ) );
1798 void KHTMLPart::checkCompleted()
1800 // kdDebug( 6050 ) << "KHTMLPart::checkCompleted() parsing: " << d->m_doc->parsing() << endl;
1801 // kdDebug( 6050 ) << " complete: " << d->m_bComplete << endl;
1804 // restore the cursor position
1805 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
1807 if (d->m_focusNodeNumber >= 0)
1808 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
1810 d->m_doc->setFocusNode(0);
1811 d->m_focusNodeRestored = true;
1815 // Any frame that hasn't completed yet ?
1816 ConstFrameIt it = d->m_frames.begin();
1817 ConstFrameIt end = d->m_frames.end();
1818 for (; it != end; ++it )
1819 if ( !(*it).m_bCompleted )
1822 // Are we still parsing - or have we done the completed stuff already ?
1823 if ( d->m_bComplete || (d->m_doc && d->m_doc->parsing()) )
1826 // Still waiting for images/scripts from the loader ?
1828 if ( d->m_doc && d->m_doc->docLoader() )
1829 requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
1835 // Now do what should be done when we are really completed.
1836 d->m_bComplete = true;
1838 checkEmitLoadEvent(); // if we didn't do it before
1841 // check that the view has not been moved by the user
1842 if ( !m_url.hasRef() && d->m_view->contentsY() == 0 )
1843 d->m_view->setContentsPos( d->m_extension->urlArgs().xOffset,
1844 d->m_extension->urlArgs().yOffset );
1847 if ( d->m_scheduledRedirection != noRedirectionScheduled )
1849 // Do not start redirection for frames here! That action is
1850 // deferred until the parent emits a completed signal.
1851 if ( parentPart() == 0 )
1852 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1854 emit completed( true );
1858 if ( d->m_bPendingChildRedirection )
1859 emit completed ( true );
1865 // find the alternate stylesheets
1868 sheets = d->m_doc->availableStyleSheets();
1869 d->m_paUseStylesheet->setItems( sheets );
1870 d->m_paUseStylesheet->setEnabled( !sheets.isEmpty() );
1871 if (!sheets.isEmpty())
1873 d->m_paUseStylesheet->setCurrentItem(kMax(sheets.findIndex(d->m_sheetUsed), 0));
1874 slotUseStylesheet();
1878 emit setStatusBarText(i18n("Done."));
1882 kdDebug(6050) << "DONE: " <<d->m_parsetime.elapsed() << endl;
1886 void KHTMLPart::checkEmitLoadEvent()
1888 if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
1890 ConstFrameIt it = d->m_frames.begin();
1891 ConstFrameIt end = d->m_frames.end();
1892 for (; it != end; ++it )
1893 if ( !(*it).m_bCompleted ) // still got a frame running -> too early
1897 // All frames completed -> set their domain to the frameset's domain
1898 // This must only be done when loading the frameset initially (#22039),
1899 // not when following a link in a frame (#44162).
1902 DOMString domain = d->m_doc->domain();
1903 ConstFrameIt it = d->m_frames.begin();
1904 ConstFrameIt end = d->m_frames.end();
1905 for (; it != end; ++it )
1907 KParts::ReadOnlyPart *p = (*it).m_part;
1908 if ( p && p->inherits( "KHTMLPart" ))
1910 KHTMLPart* htmlFrame = static_cast<KHTMLPart *>(p);
1911 if (htmlFrame->d->m_doc)
1913 kdDebug() << "KHTMLPart::checkCompleted setting frame domain to " << domain.string() << endl;
1914 htmlFrame->d->m_doc->setDomain( domain );
1920 d->m_bLoadEventEmitted = true;
1921 d->m_bUnloadEventEmitted = false;
1926 const KHTMLSettings *KHTMLPart::settings() const
1928 return d->m_settings;
1931 #ifndef KDE_NO_COMPAT
1932 KURL KHTMLPart::baseURL() const
1934 if ( !d->m_doc ) return KURL();
1936 return d->m_doc->baseURL();
1939 QString KHTMLPart::baseTarget() const
1941 if ( !d->m_doc ) return QString::null;
1943 return d->m_doc->baseTarget();
1947 KURL KHTMLPart::completeURL( const QString &url )
1949 if ( !d->m_doc ) return url;
1953 return KURL(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
1956 return KURL( d->m_doc->completeURL( url ) );
1959 void KHTMLPart::scheduleRedirection( double delay, const QString &url, bool doLockHistory)
1961 kdDebug(6050) << "KHTMLPart::scheduleRedirection delay=" << delay << " url=" << url << endl;
1962 if (delay < 0 || delay > INT_MAX / 1000)
1964 if ( d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect )
1966 d->m_scheduledRedirection = redirectionScheduled;
1967 d->m_delayRedirect = delay;
1968 d->m_redirectURL = url;
1969 d->m_redirectLockHistory = doLockHistory;
1970 d->m_redirectUserGesture = false;
1972 d->m_redirectionTimer.stop();
1973 if ( d->m_bComplete )
1974 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1978 void KHTMLPart::scheduleLocationChange(const QString &url, bool lockHistory, bool userGesture)
1980 // Handle a location change of a page with no document as a special case.
1981 // This may happen when a frame changes the location of another frame.
1982 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
1983 d->m_delayRedirect = 0;
1984 d->m_redirectURL = url;
1985 d->m_redirectLockHistory = lockHistory;
1986 d->m_redirectUserGesture = userGesture;
1987 d->m_redirectionTimer.stop();
1989 d->m_redirectionTimer.start(0, true);
1992 bool KHTMLPart::isScheduledLocationChangePending() const
1994 switch (d->m_scheduledRedirection) {
1995 case noRedirectionScheduled:
1996 case redirectionScheduled:
1998 case historyNavigationScheduled:
1999 case locationChangeScheduled:
2000 case locationChangeScheduledDuringLoad:
2006 void KHTMLPart::scheduleHistoryNavigation( int steps )
2009 // navigation will always be allowed in the 0 steps case, which is OK because
2010 // that's supposed to force a reload.
2011 if (!KWQ(this)->canGoBackOrForward(steps)) {
2012 cancelRedirection();
2017 d->m_scheduledRedirection = historyNavigationScheduled;
2018 d->m_delayRedirect = 0;
2019 d->m_redirectURL = QString::null;
2020 d->m_scheduledHistoryNavigationSteps = steps;
2021 d->m_redirectionTimer.stop();
2023 d->m_redirectionTimer.start(0, true);
2026 void KHTMLPart::cancelRedirection(bool cancelWithLoadInProgress)
2029 d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
2030 d->m_scheduledRedirection = noRedirectionScheduled;
2031 d->m_redirectionTimer.stop();
2035 void KHTMLPart::slotRedirect()
2037 if (d->m_scheduledRedirection == historyNavigationScheduled) {
2038 d->m_scheduledRedirection = noRedirectionScheduled;
2040 // Special case for go(0) from a frame -> reload only the frame
2041 // go(i!=0) from a frame navigates into the history of the frame only,
2042 // in both IE and NS (but not in Mozilla).... we can't easily do that
2044 if (d->m_scheduledHistoryNavigationSteps == 0) // add && parentPart() to get only frames, but doesn't matter
2045 openURL( url() ); /// ## need args.reload=true?
2047 if (d->m_extension) {
2048 BrowserInterface *interface = d->m_extension->browserInterface();
2050 interface->callMethod( "goHistory(int)", d->m_scheduledHistoryNavigationSteps );
2056 QString u = d->m_redirectURL;
2057 d->m_scheduledRedirection = noRedirectionScheduled;
2058 d->m_delayRedirect = 0;
2059 d->m_redirectURL = QString::null;
2060 if ( u.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
2062 QString script = KURL::decode_string( u.right( u.length() - 11 ) );
2063 //kdDebug( 6050 ) << "KHTMLPart::slotRedirect script=" << script << endl;
2064 QVariant res = executeScript( script, d->m_redirectUserGesture );
2065 if ( res.type() == QVariant::String ) {
2067 write( res.asString() );
2072 KParts::URLArgs args;
2073 if ( urlcmp( u, m_url.url(), true, false ) )
2076 args.setLockHistory( d->m_redirectLockHistory );
2077 urlSelected( u, 0, 0, "_self", args );
2080 void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url)
2082 // the slave told us that we got redirected
2083 // kdDebug( 6050 ) << "redirection by KIO to " << url.url() << endl;
2084 emit d->m_extension->setLocationBarURL( url.prettyURL() );
2085 d->m_workingURL = url;
2090 bool KHTMLPart::setEncoding( const QString &name, bool override )
2092 d->m_encoding = name;
2093 d->m_haveEncoding = override;
2095 if( !m_url.isEmpty() ) {
2100 d->m_restored = true;
2102 d->m_restored = false;
2110 QString KHTMLPart::encoding() const
2112 if(d->m_haveEncoding && !d->m_encoding.isEmpty())
2113 return d->m_encoding;
2115 if(d->m_decoder && d->m_decoder->encoding())
2116 return QString(d->m_decoder->encoding());
2118 return(settings()->encoding());
2121 void KHTMLPart::setUserStyleSheet(const KURL &url)
2123 if ( d->m_doc && d->m_doc->docLoader() )
2124 (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
2127 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
2130 d->m_doc->setUserStyleSheet( styleSheet );
2133 bool KHTMLPart::gotoAnchor( const QString &name )
2138 NodeImpl *n = d->m_doc->getElementById(name);
2140 HTMLCollectionImpl *anchors =
2141 new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
2143 n = anchors->namedItem(name, !d->m_doc->inCompatMode());
2147 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
2149 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2150 if (!n && !(name.isEmpty() || name.lower() == "top")) {
2151 kdDebug(6050) << "KHTMLPart::gotoAnchor node '" << name << "' not found" << endl;
2155 // We need to update the layout before scrolling, otherwise we could
2156 // really mess things up if an anchor scroll comes at a bad moment.
2158 d->m_doc->updateRendering();
2159 // Only do a layout if changes have occurred that make it necessary.
2160 if ( d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() ) {
2161 d->m_view->layout();
2167 static_cast<HTMLElementImpl *>(n)->getUpperLeftCorner(x, y);
2169 // Scroll to actual top left of element with no slop, since some pages expect anchors to be exactly scrolled to.
2171 // Call recursive version so this will expose correctly from within nested frames.
2172 d->m_view->setContentsPosRecursive(x, y);
2174 d->m_view->setContentsPos(x, y);
2180 void KHTMLPart::setStandardFont( const QString &name )
2182 d->m_settings->setStdFontName(name);
2185 void KHTMLPart::setFixedFont( const QString &name )
2187 d->m_settings->setFixedFontName(name);
2192 void KHTMLPart::setURLCursor( const QCursor &c )
2194 d->m_linkCursor = c;
2199 QCursor KHTMLPart::urlCursor() const
2202 // Don't load the link cursor until it's actually used.
2203 // Also, we don't need setURLCursor.
2204 // This speeds up startup time.
2205 return KCursor::handCursor();
2207 return d->m_linkCursor;
2211 bool KHTMLPart::onlyLocalReferences() const
2213 return d->m_onlyLocalReferences;
2216 void KHTMLPart::setOnlyLocalReferences(bool enable)
2218 d->m_onlyLocalReferences = enable;
2223 void KHTMLPart::findTextBegin(NodeImpl *startNode, int startPos)
2225 d->m_findPos = startPos;
2226 d->m_findNode = startNode;
2229 bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensitive, bool isRegExp )
2234 if(!d->m_findNode) {
2235 if (d->m_doc->isHTMLDocument())
2236 d->m_findNode = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
2238 d->m_findNode = d->m_doc;
2241 if ( !d->m_findNode )
2243 kdDebug() << "KHTMLPart::findTextNext no findNode -> return false" << endl;
2246 if ( d->m_findNode->id() == ID_FRAMESET )
2248 kdDebug() << "KHTMLPart::findTextNext FRAMESET -> return false" << endl;
2254 if( (d->m_findNode->nodeType() == Node::TEXT_NODE || d->m_findNode->nodeType() == Node::CDATA_SECTION_NODE) && d->m_findNode->renderer() )
2256 DOMString nodeText = d->m_findNode->nodeValue();
2257 DOMStringImpl *t = nodeText.implementation();
2258 QConstString s(t->s, t->l);
2262 QRegExp matcher( str );
2263 matcher.setCaseSensitive( caseSensitive );
2264 d->m_findPos = matcher.search(s.string(), d->m_findPos+1);
2265 if ( d->m_findPos != -1 )
2266 matchLen = matcher.matchedLength();
2269 d->m_findPos = s.string().find(str, d->m_findPos+1, caseSensitive);
2270 matchLen = str.length();
2273 if(d->m_findPos != -1)
2276 static_cast<khtml::RenderText *>(d->m_findNode->renderer())
2277 ->posOfChar(d->m_findPos, x, y);
2278 d->m_view->setContentsPos(x-50, y-50);
2279 Position p1(d->m_findNode, d->m_findPos);
2280 Position p2(d->m_findNode, d->m_findPos + matchLen);
2281 setSelection(Selection(p1, p2));
2291 next = d->m_findNode->firstChild();
2293 if(!next) next = d->m_findNode->nextSibling();
2294 while(d->m_findNode && !next) {
2295 d->m_findNode = d->m_findNode->parentNode();
2296 if( d->m_findNode ) {
2297 next = d->m_findNode->nextSibling();
2303 next = d->m_findNode->lastChild();
2305 if (!next ) next = d->m_findNode->previousSibling();
2306 while ( d->m_findNode && !next )
2308 d->m_findNode = d->m_findNode->parentNode();
2311 next = d->m_findNode->previousSibling();
2316 d->m_findNode = next;
2317 if(!d->m_findNode) return false;
2321 #endif // APPLE_CHANGES
2323 QString KHTMLPart::text(const DOM::Range &r) const
2325 return plainText(r);
2328 QString KHTMLPart::selectedText() const
2330 return text(selection().toRange());
2333 bool KHTMLPart::hasSelection() const
2335 return d->m_selection.isCaretOrRange();
2338 const Selection &KHTMLPart::selection() const
2340 return d->m_selection;
2343 ETextGranularity KHTMLPart::selectionGranularity() const
2345 return d->m_selectionGranularity;
2348 const Selection &KHTMLPart::dragCaret() const
2350 return d->m_dragCaret;
2353 const Selection &KHTMLPart::mark() const
2358 void KHTMLPart::setMark(const Selection &s)
2363 void KHTMLPart::setSelection(const Selection &s, bool closeTyping, bool keepTypingStyle)
2365 if (d->m_selection == s) {
2369 clearCaretRectIfNeeded();
2372 Selection oldSelection = d->m_selection;
2377 setFocusNodeIfNeeded();
2379 selectionLayoutChanged();
2381 // Always clear the x position used for vertical arrow navigation.
2382 // It will be restored by the vertical arrow navigation code if necessary.
2383 d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
2386 TypingCommand::closeTyping(lastEditCommand());
2388 if (!keepTypingStyle)
2392 KWQ(this)->respondToChangedSelection(oldSelection, closeTyping);
2395 emitSelectionChanged();
2398 void KHTMLPart::setDragCaret(const Selection &dragCaret)
2400 if (d->m_dragCaret != dragCaret) {
2401 d->m_dragCaret.needsCaretRepaint();
2402 d->m_dragCaret = dragCaret;
2403 d->m_dragCaret.needsCaretRepaint();
2407 void KHTMLPart::clearSelection()
2409 setSelection(Selection());
2412 void KHTMLPart::invalidateSelection()
2414 clearCaretRectIfNeeded();
2415 d->m_selection.setNeedsLayout();
2416 selectionLayoutChanged();
2419 void KHTMLPart::setCaretVisible(bool flag)
2421 if (d->m_caretVisible == flag)
2423 clearCaretRectIfNeeded();
2425 setFocusNodeIfNeeded();
2426 d->m_caretVisible = flag;
2427 selectionLayoutChanged();
2431 void KHTMLPart::slotClearSelection()
2437 void KHTMLPart::clearCaretRectIfNeeded()
2439 if (d->m_caretPaint) {
2440 d->m_caretPaint = false;
2441 d->m_selection.needsCaretRepaint();
2445 void KHTMLPart::setFocusNodeIfNeeded()
2447 if (!xmlDocImpl() || d->m_selection.isNone() || !d->m_isFocused)
2450 NodeImpl *n = d->m_selection.start().node();
2451 NodeImpl *target = (n && n->isContentEditable()) ? n : 0;
2453 while (n && n != d->m_selection.end().node()) {
2454 if (n->isContentEditable()) {
2458 n = n->traverseNextNode();
2461 assert(target == 0 || target->isContentEditable());
2464 for ( ; target && !target->isFocusable(); target = target->parentNode()); // loop
2465 if (target && target->isMouseFocusable())
2466 xmlDocImpl()->setFocusNode(target);
2467 else if (!target || !target->focused())
2468 xmlDocImpl()->setFocusNode(0);
2472 void KHTMLPart::selectionLayoutChanged()
2474 // kill any caret blink timer now running
2475 if (d->m_caretBlinkTimer >= 0) {
2476 killTimer(d->m_caretBlinkTimer);
2477 d->m_caretBlinkTimer = -1;
2480 // see if a new caret blink timer needs to be started
2481 if (d->m_caretVisible && d->m_caretBlinks &&
2482 d->m_selection.isCaret() && d->m_selection.start().node()->isContentEditable()) {
2483 d->m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
2484 d->m_caretPaint = true;
2485 d->m_selection.needsCaretRepaint();
2489 d->m_doc->updateSelection();
2492 void KHTMLPart::setXPosForVerticalArrowNavigation(int x)
2494 d->m_xPosForVerticalArrowNavigation = x;
2497 int KHTMLPart::xPosForVerticalArrowNavigation() const
2499 return d->m_xPosForVerticalArrowNavigation;
2502 void KHTMLPart::timerEvent(QTimerEvent *e)
2504 if (e->timerId() == d->m_caretBlinkTimer &&
2505 d->m_caretVisible &&
2507 d->m_selection.isCaret()) {
2508 d->m_caretPaint = !d->m_caretPaint;
2509 d->m_selection.needsCaretRepaint();
2513 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
2515 if (d->m_caretPaint)
2516 d->m_selection.paintCaret(p, rect);
2519 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
2521 d->m_dragCaret.paintCaret(p, rect);
2526 void KHTMLPart::overURL( const QString &url, const QString &target, bool shiftPressed )
2528 if ( !d->m_kjsStatusBarText.isEmpty() && !shiftPressed ) {
2530 emit setStatusBarText( d->m_kjsStatusBarText );
2531 d->m_kjsStatusBarText = QString::null;
2537 if ( url.isEmpty() )
2539 emit setStatusBarText(completeURL(url).htmlURL());
2543 if (url.find( QString::fromLatin1( "javascript:" ),0, false ) != -1 )
2545 emit setStatusBarText( KURL::decode_string( url.mid( url.find( "javascript:", 0, false ) ) ) );
2549 KURL u = completeURL(url);
2551 // special case for <a href="">
2552 if ( url.isEmpty() )
2553 u.setFileName( url );
2557 KMimeType::Ptr typ = KMimeType::findByURL( u );
2560 com = typ->comment( u, false );
2562 if ( u.isMalformed() )
2564 emit setStatusBarText(u.htmlURL());
2568 if ( u.isLocalFile() )
2570 // TODO : use KIO::stat() and create a KFileItem out of its result,
2571 // to use KFileItem::statusBarText()
2572 QCString path = QFile::encodeName( u.path() );
2575 bool ok = !stat( path.data(), &buff );
2578 if (ok) ok = !lstat( path.data(), &lbuff );
2580 QString text = u.htmlURL();
2581 QString text2 = text;
2583 if (ok && S_ISLNK( lbuff.st_mode ) )
2587 tmp = i18n( "Symbolic Link");
2589 tmp = i18n("%1 (Link)").arg(com);
2590 char buff_two[1024];
2592 int n = readlink ( path.data(), buff_two, 1022);
2597 emit setStatusBarText(text2);
2606 else if ( ok && S_ISREG( buff.st_mode ) )
2608 if (buff.st_size < 1024)
2609 text = i18n("%2 (%1 bytes)").arg((long) buff.st_size).arg(text2); // always put the URL last, in case it contains '%'
2612 float d = (float) buff.st_size/1024.0;
2613 text = i18n("%1 (%2 K)").arg(text2).arg(KGlobal::locale()->formatNumber(d, 2)); // was %.2f
2618 else if ( ok && S_ISDIR( buff.st_mode ) )
2628 emit setStatusBarText(text);
2633 if (target == QString::fromLatin1("_blank"))
2635 extra = i18n(" (In new window)");
2637 else if (!target.isEmpty() &&
2638 (target != QString::fromLatin1("_top")) &&
2639 (target != QString::fromLatin1("_self")) &&
2640 (target != QString::fromLatin1("_parent")))
2642 extra = i18n(" (In other frame)");
2645 if (u.protocol() == QString::fromLatin1("mailto")) {
2646 QString mailtoMsg/* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
2647 mailtoMsg += i18n("Email to: ") + KURL::decode_string(u.path());
2648 QStringList queries = QStringList::split('&', u.query().mid(1));
2649 for (QStringList::Iterator it = queries.begin(); it != queries.end(); ++it)
2650 if ((*it).startsWith(QString::fromLatin1("subject=")))
2651 mailtoMsg += i18n(" - Subject: ") + KURL::decode_string((*it).mid(8));
2652 else if ((*it).startsWith(QString::fromLatin1("cc=")))
2653 mailtoMsg += i18n(" - CC: ") + KURL::decode_string((*it).mid(3));
2654 else if ((*it).startsWith(QString::fromLatin1("bcc=")))
2655 mailtoMsg += i18n(" - BCC: ") + KURL::decode_string((*it).mid(4));
2656 mailtoMsg.replace(QRegExp("&"), QString("&"));
2657 mailtoMsg.replace(QRegExp("<"), QString("<"));
2658 mailtoMsg.replace(QRegExp(">"), QString(">"));
2659 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), "");
2660 emit setStatusBarText(mailtoMsg);
2663 // Is this check neccessary at all? (Frerich)
2665 else if (u.protocol() == QString::fromLatin1("http")) {
2666 DOM::Node hrefNode = nodeUnderMouse().parentNode();
2667 while (hrefNode.nodeName().string() != QString::fromLatin1("A") && !hrefNode.isNull())
2668 hrefNode = hrefNode.parentNode();
2670 if (!hrefNode.isNull()) {
2671 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
2672 if (!hreflangNode.isNull()) {
2673 QString countryCode = hreflangNode.nodeValue().string().lower();
2674 // Map the language code to an appropriate country code.
2675 if (countryCode == QString::fromLatin1("en"))
2676 countryCode = QString::fromLatin1("gb");
2677 QString flagImg = QString::fromLatin1("<img src=%1>").arg(
2678 locate("locale", QString::fromLatin1("l10n/")
2680 + QString::fromLatin1("/flag.png")));
2681 emit setStatusBarText(flagImg + u.prettyURL() + extra);
2686 emit setStatusBarText(u.htmlURL() + extra);
2690 #endif // APPLE_CHANGES
2692 void KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target,
2693 KParts::URLArgs args )
2695 bool hasTarget = false;
2697 QString target = _target;
2698 if ( target.isEmpty() && d->m_doc )
2699 target = d->m_doc->baseTarget();
2700 if ( !target.isEmpty() )
2703 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
2705 executeScript( KURL::decode_string( url.right( url.length() - 11) ), true );
2709 KURL cURL = completeURL(url);
2711 // special case for <a href="">
2712 if ( url.isEmpty() )
2713 cURL.setFileName( url );
2716 if ( !cURL.isValid() )
2717 // ### ERROR HANDLING
2720 //kdDebug( 6000 ) << "urlSelected: complete URL:" << cURL.url() << " target = " << target << endl;
2723 if ( button == LeftButton && ( state & ShiftButton ) )
2725 KIO::MetaData metaData;
2726 metaData["referrer"] = d->m_referrer;
2727 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As..." ), cURL, metaData );
2731 if (!checkLinkSecurity(cURL,
2732 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?" ),
2737 args.frameName = target;
2739 if ( d->m_bHTTPRefresh )
2741 d->m_bHTTPRefresh = false;
2742 args.metaData()["cache"] = "refresh";
2746 args.metaData().insert("main_frame_request",
2747 parentPart() == 0 ? "TRUE":"FALSE");
2748 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
2749 args.metaData().insert("ssl_activate_warnings", "TRUE");
2753 args.metaData()["referrer"] = d->m_referrer;
2754 KWQ(this)->urlSelected(cURL, button, state, args);
2758 // unknown frame names should open in a new window.
2759 khtml::ChildFrame *frame = recursiveFrameRequest( cURL, args, false );
2762 args.metaData()["referrer"] = d->m_referrer;
2763 requestObject( frame, cURL, args );
2768 if ( !d->m_bComplete && !hasTarget )
2771 if (!d->m_referrer.isEmpty())
2772 args.metaData()["referrer"] = d->m_referrer;
2774 if ( button == MidButton && (state & ShiftButton) )
2776 KParts::WindowArgs winArgs;
2777 winArgs.lowerWindow = true;
2778 KParts::ReadOnlyPart *newPart = 0;
2779 emit d->m_extension->createNewWindow( cURL, args, winArgs, newPart );
2782 emit d->m_extension->openURLRequest( cURL, args );
2783 #endif // APPLE_CHANGES
2788 void KHTMLPart::slotViewDocumentSource()
2791 if (!(url.isLocalFile()) && KHTMLPageCache::self()->isValid(d->m_cacheId))
2793 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2794 if (sourceFile.status() == 0)
2796 KHTMLPageCache::self()->saveData(d->m_cacheId, sourceFile.dataStream());
2798 url.setPath(sourceFile.name());
2802 // emit d->m_extension->openURLRequest( m_url, KParts::URLArgs( false, 0, 0, QString::fromLatin1( "text/plain" ) ) );
2803 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2806 void KHTMLPart::slotViewFrameSource()
2808 KParts::ReadOnlyPart *frame = currentFrame();
2812 KURL url = frame->url();
2813 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
2815 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
2817 if (KHTMLPageCache::self()->isValid(cacheId))
2819 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2820 if (sourceFile.status() == 0)
2822 KHTMLPageCache::self()->saveData(cacheId, sourceFile.dataStream());
2824 url.setPath(sourceFile.name());
2829 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2832 KURL KHTMLPart::backgroundURL() const
2834 // ### what about XML documents? get from CSS?
2835 if (!d->m_doc || !d->m_doc->isHTMLDocument())
2838 QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
2840 return KURL( m_url, relURL );
2843 void KHTMLPart::slotSaveBackground()
2845 KIO::MetaData metaData;
2846 metaData["referrer"] = d->m_referrer;
2847 KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save background image as"), backgroundURL(), metaData );
2850 void KHTMLPart::slotSaveDocument()
2852 KURL srcURL( m_url );
2854 if ( srcURL.fileName(false).isEmpty() )
2855 srcURL.setFileName( "index.html" );
2857 KIO::MetaData metaData;
2859 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files"), d->m_cacheId );
2862 void KHTMLPart::slotSecurity()
2864 // kdDebug( 6050 ) << "Meta Data:" << endl
2865 // << d->m_ssl_peer_cert_subject
2867 // << d->m_ssl_peer_cert_issuer
2869 // << d->m_ssl_cipher
2871 // << d->m_ssl_cipher_desc
2873 // << d->m_ssl_cipher_version
2875 // << d->m_ssl_good_from
2877 // << d->m_ssl_good_until
2879 // << d->m_ssl_cert_state
2882 KSSLInfoDlg *kid = new KSSLInfoDlg(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
2884 if (d->m_bSecurityInQuestion)
2885 kid->setSecurityInQuestion(true);
2887 if (d->m_ssl_in_use) {
2888 KSSLCertificate *x = KSSLCertificate::fromString(d->m_ssl_peer_certificate.local8Bit());
2890 // Set the chain back onto the certificate
2891 QStringList cl = QStringList::split(QString("\n"), d->m_ssl_peer_chain);
2892 QPtrList<KSSLCertificate> ncl;
2894 ncl.setAutoDelete(true);
2895 for (QStringList::Iterator it = cl.begin(); it != cl.end(); ++it) {
2896 KSSLCertificate *y = KSSLCertificate::fromString((*it).local8Bit());
2897 if (y) ncl.append(y);
2900 if (ncl.count() > 0)
2901 x->chain().setChain(ncl);
2907 d->m_ssl_cipher_desc,
2908 d->m_ssl_cipher_version,
2909 d->m_ssl_cipher_used_bits.toInt(),
2910 d->m_ssl_cipher_bits.toInt(),
2911 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt()
2919 void KHTMLPart::slotSaveFrame()
2921 if ( !d->m_activeFrame )
2922 return; // should never be the case, but one never knows :-)
2924 KURL srcURL( static_cast<KParts::ReadOnlyPart *>( d->m_activeFrame )->url() );
2926 if ( srcURL.fileName(false).isEmpty() )
2927 srcURL.setFileName( "index.html" );
2929 KIO::MetaData metaData;
2930 // Referrer unknown?
2931 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files") );
2934 void KHTMLPart::slotSetEncoding()
2936 // first Item is always auto
2937 if(d->m_paSetEncoding->currentItem() == 0)
2938 setEncoding(QString::null, false);
2940 // strip of the language to get the raw encoding again.
2941 QString enc = KGlobal::charsets()->encodingForName(d->m_paSetEncoding->currentText());
2942 setEncoding(enc, true);
2946 void KHTMLPart::slotUseStylesheet()
2948 if (d->m_doc && d->m_paUseStylesheet->currentText() != d->m_sheetUsed) {
2949 d->m_sheetUsed = d->m_paUseStylesheet->currentText();
2950 d->m_doc->updateStyleSelector();
2954 void KHTMLPart::updateActions()
2956 bool frames = false;
2958 QValueList<khtml::ChildFrame>::ConstIterator it = d->m_frames.begin();
2959 QValueList<khtml::ChildFrame>::ConstIterator end = d->m_frames.end();
2960 for (; it != end; ++it )
2961 if ( (*it).m_type == khtml::ChildFrame::Frame )
2967 d->m_paViewFrame->setEnabled( frames );
2968 d->m_paSaveFrame->setEnabled( frames );
2971 d->m_paFind->setText( i18n( "&Find in Frame..." ) );
2973 d->m_paFind->setText( i18n( "&Find..." ) );
2975 KParts::Part *frame = 0;
2978 frame = currentFrame();
2980 bool enableFindAndSelectAll = true;
2983 enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
2985 d->m_paFind->setEnabled( enableFindAndSelectAll );
2986 d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
2988 bool enablePrintFrame = false;
2992 QObject *ext = KParts::BrowserExtension::childObject( frame );
2994 enablePrintFrame = ext->metaObject()->slotNames().contains( "print()" );
2997 d->m_paPrintFrame->setEnabled( enablePrintFrame );
3002 if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
3003 bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
3005 d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
3010 bool KHTMLPart::requestFrame( khtml::RenderPart *frame, const QString &url, const QString &frameName,
3011 const QStringList ¶mNames, const QStringList ¶mValues, bool isIFrame )
3013 // kdDebug( 6050 ) << "childRequest( ..., " << url << ", " << frameName << " )" << endl;
3014 FrameIt it = d->m_frames.find( frameName );
3015 if ( it == d->m_frames.end() )
3017 khtml::ChildFrame child;
3018 // kdDebug( 6050 ) << "inserting new frame into frame map " << frameName << endl;
3019 child.m_name = frameName;
3020 it = d->m_frames.append( child );
3023 (*it).m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
3024 (*it).m_frame = frame;
3025 (*it).m_paramValues = paramNames;
3026 (*it).m_paramNames = paramValues;
3028 // Support for <frame src="javascript:string">
3029 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
3031 if (!processObjectRequest(&(*it), "about:blank", "text/html" ))
3034 KHTMLPart *newPart = static_cast<KHTMLPart *>(&*(*it).m_part);
3035 newPart->replaceContentsWithScriptResult( url );
3040 return requestObject( &(*it), completeURL( url ));
3043 QString KHTMLPart::requestFrameName()
3046 return KWQ(this)->generateFrameName();
3048 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
3052 bool KHTMLPart::requestObject( khtml::RenderPart *frame, const QString &url, const QString &serviceType,
3053 const QStringList ¶mNames, const QStringList ¶mValues )
3055 khtml::ChildFrame child;
3056 QValueList<khtml::ChildFrame>::Iterator it = d->m_objects.append( child );
3057 (*it).m_frame = frame;
3058 (*it).m_type = khtml::ChildFrame::Object;
3059 (*it).m_paramNames = paramNames;
3060 (*it).m_paramValues = paramValues;
3064 completedURL = completeURL(url);
3066 KParts::URLArgs args;
3067 args.serviceType = serviceType;
3068 return requestObject( &(*it), completedURL, args );
3071 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KURL &url, const KParts::URLArgs &_args )
3074 if (!checkLinkSecurity(url))
3077 if ( child->m_bPreloaded )
3079 // kdDebug(6005) << "KHTMLPart::requestObject preload" << endl;
3080 if ( child->m_frame && child->m_part && child->m_part->widget() )
3081 child->m_frame->setWidget( child->m_part->widget() );
3083 child->m_bPreloaded = false;
3087 KParts::URLArgs args( _args );
3091 child->m_run->abort();
3094 if ( child->m_part && !args.reload && urlcmp( child->m_part->url().url(), url.url(), true, true ) )
3095 args.serviceType = child->m_serviceType;
3097 child->m_args = args;
3098 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3099 child->m_serviceName = QString::null;
3100 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
3101 child->m_args.metaData()["referrer"] = d->m_referrer;
3104 child->m_args.metaData().insert("main_frame_request",
3105 parentPart() == 0 ? "TRUE":"FALSE");
3106 child->m_args.metaData().insert("ssl_was_in_use",
3107 d->m_ssl_in_use ? "TRUE":"FALSE");
3108 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
3111 // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
3112 if ((url.isEmpty() || url.url() == "about:blank") && args.serviceType.isEmpty())
3113 args.serviceType = QString::fromLatin1( "text/html" );
3116 return processObjectRequest( child, url, args.serviceType );
3118 if ( args.serviceType.isEmpty() ) {
3119 child->m_run = new KHTMLRun( this, child, url, child->m_args,
3120 child->m_type != khtml::ChildFrame::Frame );
3123 return processObjectRequest( child, url, args.serviceType );
3128 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KURL &_url, const QString &mimetype )
3130 //kdDebug( 6050 ) << "KHTMLPart::processObjectRequest trying to create part for " << mimetype << endl;
3132 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
3133 // by an emitting frame part (emit openURLRequest( blahurl, ... ) . A few lines below we delete the part
3134 // though -> the reference becomes invalid -> crash is likely
3137 // khtmlrun called us this way to indicate a loading error
3138 if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
3140 checkEmitLoadEvent();
3141 child->m_bCompleted = true;
3145 if (child->m_bNotify)
3147 child->m_bNotify = false;
3148 if ( !child->m_args.lockHistory() )
3149 emit d->m_extension->openURLNotify();
3153 if ( child->m_part )
3155 KHTMLPart *part = dynamic_cast<KHTMLPart *>(&*child->m_part);
3161 KParts::ReadOnlyPart *part = KWQ(this)->createPart(*child, url, mimetype);
3162 KHTMLPart *khtml_part = dynamic_cast<KHTMLPart *>(part);
3164 khtml_part->childBegin();
3166 if ( !child->m_services.contains( mimetype ) )
3168 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 );
3173 if ( child->m_frame )
3174 if (child->m_frame->partLoadingErrorNotify( child, url, mimetype ))
3175 return true; // we succeeded after all (a fallback was used)
3177 checkEmitLoadEvent();
3182 if ( child->m_part )
3184 disconnectChild(child);
3186 partManager()->removePart( (KParts::ReadOnlyPart *)child->m_part );
3188 child->m_part->deref();
3191 child->m_serviceType = mimetype;
3192 if ( child->m_frame && part->widget() )
3193 child->m_frame->setWidget( part->widget() );
3196 if ( child->m_type != khtml::ChildFrame::Object )
3197 partManager()->addPart( part, false );
3199 // kdDebug(6005) << "AH! NO FRAME!!!!!" << endl;
3202 child->m_part = part;
3203 assert( ((void*) child->m_part) != 0);
3205 connectChild(child);
3210 child->m_extension = KParts::BrowserExtension::childObject( part );
3212 if ( child->m_extension )
3214 connect( child->m_extension, SIGNAL( openURLNotify() ),
3215 d->m_extension, SIGNAL( openURLNotify() ) );
3217 connect( child->m_extension, SIGNAL( openURLRequestDelayed( const KURL &, const KParts::URLArgs & ) ),
3218 this, SLOT( slotChildURLRequest( const KURL &, const KParts::URLArgs & ) ) );
3220 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ),
3221 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ) );
3222 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs &, const KParts::WindowArgs &, KParts::ReadOnlyPart *& ) ),
3223 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & , const KParts::WindowArgs &, KParts::ReadOnlyPart *&) ) );
3225 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ),
3226 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ) );
3227 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ),
3228 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ) );
3229 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ),
3230 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ) );
3231 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ),
3232 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ) );
3234 connect( child->m_extension, SIGNAL( infoMessage( const QString & ) ),
3235 d->m_extension, SIGNAL( infoMessage( const QString & ) ) );
3237 child->m_extension->setBrowserInterface( d->m_extension->browserInterface() );
3242 checkEmitLoadEvent();
3243 // Some JS code in the load event may have destroyed the part
3244 // In that case, abort
3245 if ( !child->m_part )
3248 if ( child->m_bPreloaded )
3250 if ( child->m_frame && child->m_part )
3251 child->m_frame->setWidget( child->m_part->widget() );
3253 child->m_bPreloaded = false;
3257 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3259 // make sure the part has a way to find out about the mimetype.
3260 // we actually set it in child->m_args in requestObject already,
3261 // but it's useless if we had to use a KHTMLRun instance, as the
3262 // point the run object is to find out exactly the mimetype.
3263 child->m_args.serviceType = mimetype;
3265 child->m_bCompleted = false;
3266 if ( child->m_extension )
3267 child->m_extension->setURLArgs( child->m_args );
3270 // In these cases, the synchronous load would have finished
3271 // before we could connect the signals, so make sure to send the
3272 // completed() signal for the child by hand:
3273 if (url.isEmpty() || url.url() == "about:blank") {
3274 ReadOnlyPart *readOnlyPart = child->m_part;
3275 KHTMLPart *part = dynamic_cast<KHTMLPart *>(readOnlyPart);
3281 if(url.protocol() == "javascript" || url.url() == "about:blank") {
3282 if (!child->m_part->inherits("KHTMLPart"))
3285 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(child->m_part));
3288 if (d->m_doc && p->d->m_doc)
3289 p->d->m_doc->setBaseURL(d->m_doc->baseURL());
3290 if (!url.url().startsWith("about:")) {
3291 p->write(url.path());
3298 else if ( !url.isEmpty() )
3300 //kdDebug( 6050 ) << "opening " << url.url() << " in frame " << child->m_part << endl;
3301 return child->m_part->openURL( url );
3310 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget, const char *widgetName,
3311 QObject *parent, const char *name, const QString &mimetype,
3312 QString &serviceName, QStringList &serviceTypes,
3313 const QStringList ¶ms )
3316 if ( !serviceName.isEmpty() )
3317 constr.append( QString::fromLatin1( "Name == '%1'" ).arg( serviceName ) );
3319 KTrader::OfferList offers = KTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr, QString::null );
3321 if ( offers.isEmpty() )
3324 KService::Ptr service = *offers.begin();
3326 KLibFactory *factory = KLibLoader::self()->factory( QFile::encodeName(service->library()) );
3331 KParts::ReadOnlyPart *res = 0L;
3333 const char *className = "KParts::ReadOnlyPart";
3334 if ( service->serviceTypes().contains( "Browser/View" ) )
3335 className = "Browser/View";
3337 if ( factory->inherits( "KParts::Factory" ) )
3338 res = static_cast<KParts::ReadOnlyPart *>(static_cast<KParts::Factory *>( factory )->createPart( parentWidget, widgetName, parent, name, className, params ));
3340 res = static_cast<KParts::ReadOnlyPart *>(factory->create( parentWidget, widgetName, className ));
3345 serviceTypes = service->serviceTypes();
3346 serviceName = service->name();
3351 KParts::PartManager *KHTMLPart::partManager()
3353 if ( !d->m_manager )
3355 d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this, "khtml part manager" );
3356 d->m_manager->setAllowNestedParts( true );
3357 connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
3358 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
3359 connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ),
3360 this, SLOT( slotPartRemoved( KParts::Part * ) ) );
3363 return d->m_manager;
3368 void KHTMLPart::submitFormAgain()
3370 if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
3371 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 );
3373 delete d->m_submitForm;
3374 d->m_submitForm = 0;
3375 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
3378 void KHTMLPart::submitForm( const char *action, const QString &url, const FormData &formData, const QString &_target, const QString& contentType, const QString& boundary )
3380 kdDebug(6000) << this << ": KHTMLPart::submitForm target=" << _target << " url=" << url << endl;
3381 KURL u = completeURL( url );
3385 // ### ERROR HANDLING!
3390 // Form security checks
3393 /* This is separate for a reason. It has to be _before_ all script, etc,
3394 * AND I don't want to break anything that uses checkLinkSecurity() in
3398 // This causes crashes... needs to be fixed.
3399 if (!d->m_submitForm && u.protocol() != "https" && u.protocol() != "mailto") {
3400 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
3401 int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
3402 "\nA third party may be able to intercept and view this information."
3403 "\nAre you sure you wish to continue?"),
3405 if (rc == KMessageBox::Cancel)
3407 } else { // Going from nonSSL -> nonSSL
3408 KSSLSettings kss(true);
3409 if (kss.warnOnUnencrypted()) {
3410 int rc = KMessageBox::warningContinueCancel(NULL,
3411 i18n("Warning: Your data is about to be transmitted across the network unencrypted."
3412 "\nAre you sure you wish to continue?"),
3415 "WarnOnUnencryptedForm");
3416 // Move this setting into KSSL instead
3417 KConfig *config = kapp->config();
3418 QString grpNotifMsgs = QString::fromLatin1("Notification Messages");
3419 KConfigGroupSaver saver( config, grpNotifMsgs );
3421 if (!config->readBoolEntry("WarnOnUnencryptedForm", true)) {
3422 config->deleteEntry("WarnOnUnencryptedForm");
3424 kss.setWarnOnUnencrypted(false);
3427 if (rc == KMessageBox::Cancel)
3433 if (!d->m_submitForm && u.protocol() == "mailto") {
3434 int rc = KMessageBox::warningContinueCancel(NULL,
3435 i18n("This site is attempting to submit form data via email."),
3438 "WarnTriedEmailSubmit");
3440 if (rc == KMessageBox::Cancel) {
3445 // End form security checks
3447 #endif // APPLE_CHANGES
3449 QString urlstring = u.url();
3451 if ( urlstring.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
3452 urlstring = KURL::decode_string(urlstring);
3453 d->m_executingJavaScriptFormAction = true;
3454 executeScript( urlstring.right( urlstring.length() - 11) );
3455 d->m_executingJavaScriptFormAction = false;
3460 if (!checkLinkSecurity(u,
3461 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?" ),
3466 KParts::URLArgs args;
3468 if (!d->m_referrer.isEmpty())
3469 args.metaData()["referrer"] = d->m_referrer;
3472 args.metaData().insert("main_frame_request",
3473 parentPart() == 0 ? "TRUE":"FALSE");
3474 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
3475 args.metaData().insert("ssl_activate_warnings", "TRUE");
3477 args.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
3479 // Handle mailto: forms
3480 if (u.protocol() == "mailto") {
3481 // 1) Check for attach= and strip it
3482 QString q = u.query().mid(1);
3483 QStringList nvps = QStringList::split("&", q);
3484 bool triedToAttach = false;
3486 for (QStringList::Iterator nvp = nvps.begin(); nvp != nvps.end(); ++nvp) {
3487 QStringList pair = QStringList::split("=", *nvp);
3488 if (pair.count() >= 2) {
3489 if (pair.first().lower() == "attach") {
3490 nvp = nvps.remove(nvp);
3491 triedToAttach = true;
3498 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");
3503 if (contentType.lower() == "multipart/form-data") {
3504 // FIXME: is this correct? I suspect not
3505 bodyEnc = KURL::encode_string(formData.flattenToString());
3506 } else if (contentType.lower() == "text/plain") {
3507 // Convention seems to be to decode, and s/&/\n/
3508 QString tmpbody = formData.flattenToString();
3509 tmpbody.replace('&', '\n');
3510 tmpbody.replace('+', ' ');
3511 tmpbody = KURL::decode_string(tmpbody); // Decode the rest of it
3512 bodyEnc = KURL::encode_string(tmpbody); // Recode for the URL
3514 bodyEnc = KURL::encode_string(formData.flattenToString());
3517 nvps.append(QString("body=%1").arg(bodyEnc));
3522 if ( strcmp( action, "get" ) == 0 ) {
3523 if (u.protocol() != "mailto")
3524 u.setQuery( formData.flattenToString() );
3525 args.setDoPost( false );
3529 args.postData = formData;
3531 args.postData = formData.flatten();
3533 args.setDoPost( true );
3535 // construct some user headers if necessary
3536 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
3537 args.setContentType( "Content-Type: application/x-www-form-urlencoded" );
3538 else // contentType must be "multipart/form-data"
3539 args.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
3542 if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
3543 if( d->m_submitForm ) {
3544 kdDebug(6000) << "KHTMLPart::submitForm ABORTING!" << endl;
3547 d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
3548 d->m_submitForm->submitAction = action;
3549 d->m_submitForm->submitUrl = url;
3550 d->m_submitForm->submitFormData = formData;
3551 d->m_submitForm->target = _target;
3552 d->m_submitForm->submitContentType = contentType;
3553 d->m_submitForm->submitBoundary = boundary;
3554 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
3559 KWQ(this)->submitForm( u, args);
3561 emit d->m_extension->openURLRequest( u, args );
3568 void KHTMLPart::popupMenu( const QString &linkUrl )
3572 if ( linkUrl.isEmpty() ) // click on background
3573 popupURL = this->url();
3574 else { // click on link
3575 popupURL = completeURL( linkUrl );
3576 linkKURL = popupURL;
3579 KXMLGUIClient *client = new KHTMLPopupGUIClient( this, d->m_popupMenuXML, linkKURL );
3581 emit d->m_extension->popupMenu( client, QCursor::pos(), popupURL,
3582 QString::fromLatin1( "text/html" ), S_IFREG /*always a file*/ );
3586 emit popupMenu(linkUrl, QCursor::pos());
3591 void KHTMLPart::slotParentCompleted()
3593 if ( d->m_scheduledRedirection != noRedirectionScheduled && !d->m_redirectionTimer.isActive() )
3595 // kdDebug(6050) << this << ": Child redirection -> " << d->m_redirectURL << endl;
3596 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
3600 void KHTMLPart::slotChildStarted( KIO::Job *job )
3602 khtml::ChildFrame *child = childFrame( sender() );
3606 child->m_bCompleted = false;
3608 if ( d->m_bComplete )
3611 // WABA: Looks like this belongs somewhere else
3612 if ( !parentPart() ) // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes
3614 emit d->m_extension->openURLNotify();
3617 d->m_bComplete = false;
3618 emit started( job );
3622 void KHTMLPart::slotChildCompleted()
3624 slotChildCompleted( false );
3627 void KHTMLPart::slotChildCompleted( bool complete )
3629 khtml::ChildFrame *child = childFrame( sender() );
3633 child->m_bCompleted = true;
3634 child->m_args = KParts::URLArgs();
3636 if ( complete && parentPart() == 0 )
3637 d->m_bPendingChildRedirection = true;
3644 void KHTMLPart::slotChildURLRequest( const KURL &url, const KParts::URLArgs &args )
3646 khtml::ChildFrame *child = childFrame( sender()->parent() );
3648 QString frameName = args.frameName.lower();
3649 if ( !frameName.isEmpty() )
3651 if ( frameName == QString::fromLatin1( "_top" ) )
3653 emit d->m_extension->openURLRequest( url, args );
3656 else if ( frameName == QString::fromLatin1( "_blank" ) )
3658 emit d->m_extension->createNewWindow( url, args );
3661 else if ( frameName == QString::fromLatin1( "_parent" ) )
3663 KParts::URLArgs newArgs( args );
3664 newArgs.frameName = QString::null;
3666 emit d->m_extension->openURLRequest( url, newArgs );
3669 else if ( frameName != QString::fromLatin1( "_self" ) )
3671 khtml::ChildFrame *_frame = recursiveFrameRequest( url, args );
3675 emit d->m_extension->openURLRequest( url, args );
3683 // TODO: handle child target correctly! currently the script are always executed fur the parent
3684 QString urlStr = url.url();
3685 if ( urlStr.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
3686 executeScript( KURL::decode_string( urlStr.right( urlStr.length() - 11) ) );
3691 // Inform someone that we are about to show something else.
3692 child->m_bNotify = true;
3693 requestObject( child, url, args );
3694 } else if ( frameName==QString::fromLatin1("_self") ) // this is for embedded objects (via <object>) which want to replace the current document
3696 KParts::URLArgs newArgs( args );
3697 newArgs.frameName = QString::null;
3698 emit d->m_extension->openURLRequest( url, newArgs );
3702 #endif // APPLE_CHANGES
3704 khtml::ChildFrame *KHTMLPart::childFrame( const QObject *obj )
3706 assert( obj->inherits( "KParts::ReadOnlyPart" ) );
3707 const ReadOnlyPart *part = static_cast<const ReadOnlyPart *>( obj );
3709 FrameIt it = d->m_frames.begin();