1 // -*- c-basic-offset: 2 -*-
2 /* This file is part of the KDE project
4 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
5 * 1999 Lars Knoll <knoll@kde.org>
6 * 1999 Antti Koivisto <koivisto@kde.org>
7 * 2000 Simon Hausmann <hausmann@kde.org>
8 * 2000 Stefan Schimanski <1Stein@gmx.de>
9 * 2001 George Staikos <staikos@kde.org>
10 * Copyright (C) 2004 Apple Computer, Inc.
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
28 #include "khtml_part.h"
31 #define DIRECT_LINKAGE_TO_ECMA
32 #define QT_NO_CLIPBOARD
33 #define QT_NO_DRAGANDDROP
36 #include "khtml_pagecache.h"
38 #include "css/csshelper.h"
39 #include "css/cssproperties.h"
40 #include "css/cssstyleselector.h"
41 #include "css/css_computedstyle.h"
42 #include "css/css_valueimpl.h"
43 #include "dom/dom_string.h"
44 #include "dom/dom_element.h"
45 #include "dom/html_document.h"
46 #include "editing/markup.h"
47 #include "editing/htmlediting.h"
48 #include "editing/selection.h"
49 #include "editing/visible_position.h"
50 #include "editing/visible_text.h"
51 #include "editing/visible_units.h"
52 #include "html/html_documentimpl.h"
53 #include "html/html_baseimpl.h"
54 #include "html/html_miscimpl.h"
55 #include "html/html_imageimpl.h"
56 #include "html/html_objectimpl.h"
57 #include "rendering/render_block.h"
58 #include "rendering/render_text.h"
59 #include "rendering/render_frames.h"
60 #include "misc/htmlhashes.h"
61 #include "misc/loader.h"
62 #include "xml/dom2_eventsimpl.h"
63 #include "xml/dom2_rangeimpl.h"
64 #include "xml/xml_tokenizer.h"
68 #include "khtmlview.h"
69 #include <kparts/partmanager.h>
70 #include "ecma/kjs_proxy.h"
71 #include "khtml_settings.h"
73 #include <sys/types.h>
77 #include <kstandarddirs.h>
79 #include <kio/global.h>
81 #include <kiconloader.h>
83 #include <kcharsets.h>
84 #include <kmessagebox.h>
85 #include <kstdaction.h>
86 #include <kfiledialog.h>
88 #include <kdatastream.h>
89 #include <ktempfile.h>
90 #include <kglobalsettings.h>
92 #include <kapplication.h>
93 #if !defined(QT_NO_DRAGANDDROP)
94 #include <kmultipledrag.h>
97 #include <ksslcertchain.h>
98 #include <ksslinfodlg.h>
100 #include <qclipboard.h>
102 #include <qmetaobject.h>
103 #include <qptrlist.h>
104 #include <private/qucomextra_p.h>
106 #include "khtmlpart_p.h"
109 #include <CoreServices/CoreServices.h>
112 using khtml::ApplyStyleCommand;
113 using khtml::CHARACTER;
114 using khtml::ChildFrame;
115 using khtml::Decoder;
116 using khtml::EAffinity;
117 using khtml::EditAction;
118 using khtml::EditCommandPtr;
119 using khtml::ETextGranularity;
120 using khtml::FormData;
121 using khtml::InlineTextBox;
122 using khtml::isEndOfDocument;
123 using khtml::isStartOfDocument;
124 using khtml::PARAGRAPH;
125 using khtml::plainText;
126 using khtml::RenderObject;
127 using khtml::RenderText;
128 using khtml::RenderWidget;
129 using khtml::Selection;
130 using khtml::Tokenizer;
131 using khtml::TypingCommand;
132 using khtml::VisiblePosition;
135 using KParts::BrowserInterface;
137 const int CARET_BLINK_FREQUENCY = 500;
140 class PartStyleSheetLoader : public CachedObjectClient
143 PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
146 m_cachedSheet = Cache::requestStyleSheet(dl, url );
148 m_cachedSheet->ref( this );
150 virtual ~PartStyleSheetLoader()
152 if ( m_cachedSheet ) m_cachedSheet->deref(this);
154 virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet)
157 m_part->setUserStyleSheet( sheet.string() );
161 QGuardedPtr<KHTMLPart> m_part;
162 khtml::CachedCSSStyleSheet *m_cachedSheet;
166 FrameList::Iterator FrameList::find( const QString &name )
168 Iterator it = begin();
172 if ( (*it).m_name==name )
178 KHTMLPart::KHTMLPart( QWidget *parentWidget, const char *widgetname, QObject *parent, const char *name,
180 : KParts::ReadOnlyPart( parent, name )
183 KHTMLFactory::registerPart( this );
184 setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
186 init( new KHTMLView( this, parentWidget, widgetname ), prof );
192 KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, const char *name, GUIProfile prof )
193 : KParts::ReadOnlyPart( parent, name )
196 KHTMLFactory::registerPart( this );
197 setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
202 #endif // APPLE_CHANGES
204 void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
206 AtomicString::init();
207 if ( prof == DefaultGUI )
208 setXMLFile( "khtml.rc" );
209 else if ( prof == BrowserViewGUI )
210 setXMLFile( "khtml_browser.rc" );
214 d = new KHTMLPartPrivate(parent());
217 setWidget( d->m_view );
220 d->m_guiProfile = prof;
222 d->m_extension = new KHTMLPartBrowserExtension( this );
223 d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
225 d->m_bSecurityInQuestion = false;
226 d->m_bMousePressed = false;
228 d->m_paLoadImages = 0;
229 d->m_paViewDocument = new KAction( i18n( "View Document Source" ), 0, this, SLOT( slotViewDocumentSource() ), actionCollection(), "viewDocumentSource" );
230 d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), 0, this, SLOT( slotViewFrameSource() ), actionCollection(), "viewFrameSource" );
231 d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), 0, this, SLOT( slotSaveBackground() ), actionCollection(), "saveBackground" );
232 d->m_paSaveDocument = new KAction( i18n( "&Save As..." ), CTRL+Key_S, this, SLOT( slotSaveDocument() ), actionCollection(), "saveDocument" );
234 d->m_paSaveDocument->setShortcut( KShortcut() ); // avoid clashes
235 d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), 0, this, SLOT( slotSaveFrame() ), actionCollection(), "saveFrame" );
236 d->m_paSecurity = new KAction( i18n( "Security..." ), "decrypted", 0, this, SLOT( slotSecurity() ), actionCollection(), "security" );
237 d->m_paDebugRenderTree = new KAction( "print rendering tree to stdout", 0, this, SLOT( slotDebugRenderTree() ), actionCollection(), "debugRenderTree" );
238 d->m_paDebugDOMTree = new KAction( "print DOM tree to stdout", 0, this, SLOT( slotDebugDOMTree() ), actionCollection(), "debugDOMTree" );
240 QString foo1 = i18n("Show Images");
241 QString foo2 = i18n("Show Animated Images");
242 QString foo3 = i18n("Stop Animated Images");
244 d->m_paSetEncoding = new KSelectAction( i18n( "Set &Encoding" ), 0, this, SLOT( slotSetEncoding() ), actionCollection(), "setEncoding" );
245 QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames();
246 encodings.prepend( i18n( "Auto" ) );
247 d->m_paSetEncoding->setItems( encodings );
248 d->m_paSetEncoding->setCurrentItem(0);
250 d->m_paUseStylesheet = new KSelectAction( i18n( "&Use Stylesheet"), 0, this, SLOT( slotUseStylesheet() ), actionCollection(), "useStylesheet" );
252 d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, i18n( "Increase Font Sizes" ), "viewmag+", this, SLOT( slotIncZoom() ), actionCollection(), "incFontSizes" );
253 d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, i18n( "Decrease Font Sizes" ), "viewmag-", this, SLOT( slotDecZoom() ), actionCollection(), "decFontSizes" );
255 d->m_paFind = KStdAction::find( this, SLOT( slotFind() ), actionCollection(), "find" );
257 d->m_paFind->setShortcut( KShortcut() ); // avoid clashes
259 d->m_paPrintFrame = new KAction( i18n( "Print Frame" ), "frameprint", 0, this, SLOT( slotPrintFrame() ), actionCollection(), "printFrame" );
261 d->m_paSelectAll = KStdAction::selectAll( this, SLOT( slotSelectAll() ), actionCollection(), "selectAll" );
263 d->m_paSelectAll->setShortcut( KShortcut() ); // avoid clashes
267 // set the default java(script) flags according to the current host.
268 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled();
269 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
270 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled();
271 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled();
273 // The java, javascript, and plugin settings will be set after the settings
274 // have been initialized.
275 d->m_bJScriptEnabled = true;
276 d->m_bJScriptDebugEnabled = true;
277 d->m_bJavaEnabled = true;
278 d->m_bPluginsEnabled = true;
282 connect( this, SIGNAL( completed() ),
283 this, SLOT( updateActions() ) );
284 connect( this, SIGNAL( completed( bool ) ),
285 this, SLOT( updateActions() ) );
286 connect( this, SIGNAL( started( KIO::Job * ) ),
287 this, SLOT( updateActions() ) );
289 d->m_popupMenuXML = KXMLGUIFactory::readConfigFile( locate( "data", "khtml/khtml_popupmenu.rc", KHTMLFactory::instance() ) );
292 connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
293 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
294 connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
295 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
296 connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
297 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
300 findTextBegin(); //reset find variables
303 connect( &d->m_redirectionTimer, SIGNAL( timeout() ),
304 this, SLOT( slotRedirect() ) );
306 connect(&d->m_lifeSupportTimer, SIGNAL(timeout()), this, SLOT(slotEndLifeSupport()));
309 d->m_dcopobject = new KHTMLPartIface(this);
313 KHTMLPart::~KHTMLPart()
315 //kdDebug(6050) << "KHTMLPart::~KHTMLPart " << this << endl;
317 if ( d->m_findDialog )
318 disconnect( d->m_findDialog, SIGNAL( destroyed() ),
319 this, SLOT( slotFindDialogDestroyed() ) );
323 d->m_manager->setActivePart( 0 );
324 // Shouldn't we delete d->m_manager here ? (David)
325 // No need to, I would say. We specify "this" as parent qobject
326 // in ::partManager() (Simon)
336 disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
337 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
338 disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
339 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
340 disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
341 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
348 d->m_view->viewport()->hide();
349 d->m_view->m_part = 0;
353 delete d->m_hostExtension;
357 KHTMLFactory::deregisterPart( this );
360 bool KHTMLPart::restoreURL( const KURL &url )
362 kdDebug( 6050 ) << "KHTMLPart::restoreURL " << url.url() << endl;
367 * That's not a good idea as it will call closeURL() on all
368 * child frames, preventing them from further loading. This
369 * method gets called from restoreState() in case of a full frameset
370 * restoral, and restoreState() calls closeURL() before restoring
372 kdDebug( 6050 ) << "closing old URL" << endl;
376 d->m_bComplete = false;
377 d->m_bLoadEventEmitted = false;
378 d->m_workingURL = url;
380 // set the java(script) flags according to the current host.
382 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
383 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
384 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
385 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
387 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
388 d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled();
389 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
390 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
395 KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &)));
404 bool KHTMLPart::didOpenURL(const KURL &url)
406 bool KHTMLPart::openURL( const KURL &url )
409 kdDebug( 6050 ) << "KHTMLPart(" << this << ")::openURL " << url.url() << endl;
411 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
412 // We're about to get a redirect that happened before the document was
413 // created. This can happen when one frame may change the location of a
420 // clear last edit command
421 d->m_lastEditCommand = EditCommandPtr();
423 KWQ(this)->clearUndoRedoOperations();
427 // check to see if this is an "error://" URL. This is caused when an error
428 // occurs before this part was loaded (e.g. KonqRun), and is passed to
429 // khtmlpart so that it can display the error.
430 if ( url.protocol() == "error" && url.hasSubURL() ) {
433 * The format of the error url is that two variables are passed in the query:
434 * error = int kio error code, errText = QString error text from kio
435 * and the URL where the error happened is passed as a sub URL.
437 KURL::List urls = KURL::split( url );
438 //kdDebug() << "Handling error URL. URL count:" << urls.count() << endl;
440 if ( urls.count() > 1 ) {
441 KURL mainURL = urls.first();
442 int error = mainURL.queryItem( "error" ).toInt();
443 // error=0 isn't a valid error code, so 0 means it's missing from the URL
444 if ( error == 0 ) error = KIO::ERR_UNKNOWN;
445 QString errorText = mainURL.queryItem( "errText" );
447 d->m_workingURL = KURL::join( urls );
448 //kdDebug() << "Emitting fixed URL " << d->m_workingURL.prettyURL() << endl;
449 emit d->m_extension->setLocationBarURL( d->m_workingURL.prettyURL() );
450 htmlError( error, errorText, d->m_workingURL );
454 #endif // APPLE_CHANGES
456 KParts::URLArgs args( d->m_extension->urlArgs() );
459 // in case we have a) no frameset (don't test m_frames.count(), iframes get in there)
460 // b) the url is identical with the currently
461 // displayed one (except for the htmlref!) , c) the url request is not a POST
462 // operation and d) the caller did not request to reload the page we try to
463 // be smart and instead of reloading the whole document we just jump to the
464 // request html anchor
466 bool isFrameSet = false;
467 if ( d->m_doc->isHTMLDocument() ) {
468 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
469 isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET);
472 urlcmp( url.url(), m_url.url(), true, true ) &&
473 url.hasRef() && !args.doPost() && !args.reload )
475 kdDebug( 6050 ) << "KHTMLPart::openURL, jumping to anchor. m_url = " << url.url() << endl;
481 d->m_bComplete = true;
482 d->m_doc->setParsing(false);
484 kdDebug( 6050 ) << "completed..." << endl;
489 #endif // APPLE_CHANGES
493 kdDebug( 6050 ) << "closing old URL" << endl;
498 args.metaData().insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" );
499 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" );
500 args.metaData().insert("ssl_activate_warnings", "TRUE" );
504 d->m_cachePolicy = KIO::CC_Cache;
505 else if (args.reload)
506 d->m_cachePolicy = KIO::CC_Refresh;
508 d->m_cachePolicy = KIO::CC_Verify;
510 if ( args.doPost() && (url.protocol().startsWith("http")) )
512 d->m_job = KIO::http_post( url, args.postData, false );
513 d->m_job->addMetaData("content-type", args.contentType() );
517 d->m_job = KIO::get( url, false, false );
518 d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
521 d->m_job->addMetaData(args.metaData());
523 connect( d->m_job, SIGNAL( result( KIO::Job * ) ),
524 SLOT( slotFinished( KIO::Job * ) ) );
526 connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray &)),
527 SLOT( slotData( KIO::Job*, const QByteArray &)));
530 connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KURL&) ),
531 SLOT( slotRedirection(KIO::Job*,const KURL&) ) );
533 d->m_bComplete = false;
534 d->m_bLoadingMainResource = true;
535 d->m_bLoadEventEmitted = false;
537 // delete old status bar msg's from kjs (if it _was_ activated on last URL)
538 if( d->m_bJScriptEnabled )
540 d->m_kjsStatusBarText = QString::null;
541 d->m_kjsDefaultStatusBarText = QString::null;
544 // set the javascript flags according to the current url
546 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
547 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
548 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
550 d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled();
551 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
552 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
555 // 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
556 // data arrives) (Simon)
558 if(m_url.protocol().startsWith( "http" ) && !m_url.host().isEmpty() &&
559 m_url.path().isEmpty()) {
561 emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
563 // copy to m_workingURL after fixing m_url above
564 d->m_workingURL = m_url;
566 kdDebug( 6050 ) << "KHTMLPart::openURL now (before started) m_url = " << m_url.url() << endl;
568 connect( d->m_job, SIGNAL( speed( KIO::Job*, unsigned long ) ),
569 this, SLOT( slotJobSpeed( KIO::Job*, unsigned long ) ) );
571 connect( d->m_job, SIGNAL( percent( KIO::Job*, unsigned long ) ),
572 this, SLOT( slotJobPercent( KIO::Job*, unsigned long ) ) );
579 void KHTMLPart::didExplicitOpen()
581 d->m_bComplete = false;
582 d->m_bLoadEventEmitted = false;
586 bool KHTMLPart::closeURL()
588 if (d->m_doc && d->m_doc->tokenizer()) {
589 d->m_doc->tokenizer()->stopParsing();
594 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
599 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
600 HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
602 if ( hdoc->body() && d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted ) {
603 hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false );
605 d->m_doc->updateRendering();
606 d->m_bUnloadEventEmitted = true;
610 d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
611 d->m_bLoadingMainResource = false;
612 d->m_bLoadEventEmitted = true; // don't want that one either
613 d->m_cachePolicy = KIO::CC_Verify; // Why here?
615 KHTMLPageCache::self()->cancelFetch(this);
616 if ( d->m_doc && d->m_doc->parsing() )
618 kdDebug( 6050 ) << " was still parsing... calling end " << endl;
619 slotFinishedParsing();
620 d->m_doc->setParsing(false);
623 if ( !d->m_workingURL.isEmpty() )
625 // Aborted before starting to render
626 kdDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << m_url.prettyURL() << endl;
627 emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
630 d->m_workingURL = KURL();
632 if ( d->m_doc && d->m_doc->docLoader() )
633 khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() );
635 // tell all subframes to stop as well
636 ConstFrameIt it = d->m_frames.begin();
637 ConstFrameIt end = d->m_frames.end();
638 for (; it != end; ++it )
639 if ( !( *it ).m_part.isNull() )
640 ( *it ).m_part->closeURL();
642 d->m_bPendingChildRedirection = false;
644 // Stop any started redirections as well!! (DA)
647 #if !KHTML_NO_CPLUSPLUS_DOM
648 // null node activated.
649 emit nodeActivated(Node());
655 #if !KHTML_NO_CPLUSPLUS_DOM
657 DOM::HTMLDocument KHTMLPart::htmlDocument() const
659 if (d->m_doc && d->m_doc->isHTMLDocument())
660 return static_cast<HTMLDocumentImpl*>(d->m_doc);
662 return static_cast<HTMLDocumentImpl*>(0);
665 DOM::Document KHTMLPart::document() const
672 KParts::BrowserExtension *KHTMLPart::browserExtension() const
674 return d->m_extension;
677 KHTMLView *KHTMLPart::view() const
682 void KHTMLPart::setJScriptEnabled( bool enable )
684 if ( !enable && jScriptEnabled() && d->m_jscript ) {
685 d->m_jscript->clear();
687 d->m_bJScriptForce = enable;
688 d->m_bJScriptOverride = true;
691 bool KHTMLPart::jScriptEnabled() const
693 if ( d->m_bJScriptOverride )
694 return d->m_bJScriptForce;
695 return d->m_bJScriptEnabled;
698 void KHTMLPart::setMetaRefreshEnabled( bool enable )
700 d->m_metaRefreshEnabled = enable;
703 bool KHTMLPart::metaRefreshEnabled() const
705 return d->m_metaRefreshEnabled;
708 // Define this to disable dlopening kjs_html, when directly linking to it.
709 // You need to edit khtml/Makefile.am to add ./ecma/libkjs_html.la to LIBADD
710 // and to edit khtml/ecma/Makefile.am to s/kjs_html/libkjs_html/, remove libkhtml from LIBADD,
711 // remove LDFLAGS line, and replace kde_module with either lib (shared) or noinst (static)
712 //#define DIRECT_LINKAGE_TO_ECMA
714 #ifdef DIRECT_LINKAGE_TO_ECMA
715 extern "C" { KJSProxy *kjs_html_init(KHTMLPart *khtmlpart); }
718 KJSProxy *KHTMLPart::jScript()
720 if (!jScriptEnabled()){
726 #ifndef DIRECT_LINKAGE_TO_ECMA
727 KLibrary *lib = KLibLoader::self()->library("kjs_html");
729 setJScriptEnabled( false );
732 // look for plain C init function
733 void *sym = lib->symbol("kjs_html_init");
736 setJScriptEnabled( false );
739 typedef KJSProxy* (*initFunction)(KHTMLPart *);
740 initFunction initSym = (initFunction) sym;
741 d->m_jscript = (*initSym)(this);
744 d->m_jscript = kjs_html_init(this);
745 // d->m_kjs_lib remains 0L.
747 if (d->m_bJScriptDebugEnabled)
748 d->m_jscript->setDebugEnabled(true);
754 void KHTMLPart::replaceContentsWithScriptResult( const KURL &url )
756 QString script = KURL::decode_string(url.url().mid(strlen("javascript:")));
757 QVariant ret = executeScript(script);
759 if (ret.type() == QVariant::String) {
761 write(ret.asString());
766 QVariant KHTMLPart::executeScript( const QString &script, bool forceUserGesture )
768 return executeScript( 0, script, forceUserGesture );
771 //Enable this to see all JS scripts being executed
772 //#define KJS_VERBOSE
774 #if !KHTML_NO_CPLUSPLUS_DOM
776 QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script, bool forceUserGesture )
778 return executeScript(n.handle(), script, forceUserGesture);
783 QVariant KHTMLPart::executeScript( DOM::NodeImpl *n, const QString &script, bool forceUserGesture )
786 kdDebug(6070) << "KHTMLPart::executeScript n=" << n.nodeName().string().latin1() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " << script << endl;
788 KJSProxy *proxy = jScript();
790 if (!proxy || proxy->paused())
792 d->m_runningScripts++;
793 // If forceUserGesture is true, then make the script interpreter
794 // treat it as if triggered by a user gesture even if there is no
795 // current DOM event being processed.
796 QVariant ret = proxy->evaluate( forceUserGesture ? QString::null : m_url.url(), 0, script, n );
797 d->m_runningScripts--;
798 if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
800 DocumentImpl::updateDocumentsRendering();
803 kdDebug(6070) << "KHTMLPart::executeScript - done" << endl;
808 bool KHTMLPart::scheduleScript(DOM::NodeImpl *n, const QString& script)
810 //kdDebug(6050) << "KHTMLPart::scheduleScript "<< script << endl;
812 d->scheduledScript = script;
813 d->scheduledScriptNode.reset(n);
818 QVariant KHTMLPart::executeScheduledScript()
820 if( d->scheduledScript.isEmpty() )
823 //kdDebug(6050) << "executing delayed " << d->scheduledScript << endl;
825 QVariant ret = executeScript( d->scheduledScriptNode.get(), d->scheduledScript );
826 d->scheduledScript = QString();
827 d->scheduledScriptNode.reset();
832 void KHTMLPart::setJavaEnabled( bool enable )
834 d->m_bJavaForce = enable;
835 d->m_bJavaOverride = true;
838 bool KHTMLPart::javaEnabled() const
841 if( d->m_bJavaOverride )
842 return d->m_bJavaForce;
843 return d->m_bJavaEnabled;
849 KJavaAppletContext *KHTMLPart::javaContext()
852 return d->m_javaContext;
858 KJavaAppletContext *KHTMLPart::createJavaContext()
861 if ( !d->m_javaContext ) {
863 d->m_javaContext = new KJavaAppletContext(d->m_dcopobject, this);
865 d->m_javaContext = new KJavaAppletContext(d->m_dcopobject);
866 connect( d->m_javaContext, SIGNAL(showStatus(const QString&)),
867 this, SIGNAL(setStatusBarText(const QString&)) );
868 connect( d->m_javaContext, SIGNAL(showDocument(const QString&, const QString&)),
869 this, SLOT(slotShowDocument(const QString&, const QString&)) );
873 return d->m_javaContext;
879 void KHTMLPart::setPluginsEnabled( bool enable )
881 d->m_bPluginsForce = enable;
882 d->m_bPluginsOverride = true;
885 bool KHTMLPart::pluginsEnabled() const
887 if ( d->m_bPluginsOverride )
888 return d->m_bPluginsForce;
889 return d->m_bPluginsEnabled;
894 void KHTMLPart::slotShowDocument( const QString &url, const QString &target )
896 // this is mostly copied from KHTMLPart::slotChildURLRequest. The better approach
897 // would be to put those functions into a single one.
898 khtml::ChildFrame *child = 0;
899 KParts::URLArgs args;
900 args.frameName = target;
902 QString frameName = args.frameName.lower();
903 if ( !frameName.isEmpty() )
905 if ( frameName == QString::fromLatin1( "_top" ) )
907 emit d->m_extension->openURLRequest( url, args );
910 else if ( frameName == QString::fromLatin1( "_blank" ) )
912 emit d->m_extension->createNewWindow( url, args );
915 else if ( frameName == QString::fromLatin1( "_parent" ) )
917 KParts::URLArgs newArgs( args );
918 newArgs.frameName = QString::null;
920 emit d->m_extension->openURLRequest( url, newArgs );
923 else if ( frameName != QString::fromLatin1( "_self" ) )
925 khtml::ChildFrame *_frame = recursiveFrameRequest( url, args );
929 emit d->m_extension->openURLRequest( url, args );
937 // TODO: handle child target correctly! currently the script are always executed fur the parent
938 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
939 executeScript( KURL::decode_string( url.right( url.length() - 11) ) );
944 requestObject( child, KURL(url), args );
945 } else if ( frameName==QString::fromLatin1("_self") ) // this is for embedded objects (via <object>) which want to replace the current document
947 KParts::URLArgs newArgs( args );
948 newArgs.frameName = QString::null;
949 emit d->m_extension->openURLRequest( KURL(url), newArgs );
953 #endif // APPLE_CHANGES
955 void KHTMLPart::slotDebugDOMTree()
957 if ( d->m_doc && d->m_doc->firstChild() )
958 qDebug("%s", createMarkup(d->m_doc->firstChild()).latin1());
961 void KHTMLPart::slotDebugRenderTree()
965 d->m_doc->renderer()->printTree();
969 void KHTMLPart::setAutoloadImages( bool enable )
971 if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
975 d->m_doc->docLoader()->setAutoloadImages( enable );
978 unplugActionList( "loadImages" );
981 delete d->m_paLoadImages;
982 d->m_paLoadImages = 0;
984 else if ( !d->m_paLoadImages )
985 d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), "images_display", 0, this, SLOT( slotLoadImages() ), actionCollection(), "loadImages" );
987 if ( d->m_paLoadImages ) {
988 QPtrList<KAction> lst;
989 lst.append( d->m_paLoadImages );
990 plugActionList( "loadImages", lst );
995 bool KHTMLPart::autoloadImages() const
998 return d->m_doc->docLoader()->autoloadImages();
1003 void KHTMLPart::clear()
1005 if ( d->m_bCleared )
1007 d->m_bCleared = true;
1009 d->m_bClearing = true;
1013 ConstFrameIt it = d->m_frames.begin();
1014 ConstFrameIt end = d->m_frames.end();
1015 for(; it != end; ++it )
1017 // Stop HTMLRun jobs for frames
1019 (*it).m_run->abort();
1024 QValueList<khtml::ChildFrame>::ConstIterator it = d->m_objects.begin();
1025 QValueList<khtml::ChildFrame>::ConstIterator end = d->m_objects.end();
1026 for(; it != end; ++it )
1028 // Stop HTMLRun jobs for objects
1030 (*it).m_run->abort();
1035 findTextBegin(); // resets d->m_findNode and d->m_findPos
1038 d->m_mousePressNode.reset();
1044 // Moving past doc so that onUnload works.
1046 d->m_jscript->clear();
1051 // do not dereference the document before the jscript and view are cleared, as some destructors
1052 // might still try to access the document.
1058 d->m_decoder->deref();
1062 ConstFrameIt it = d->m_frames.begin();
1063 ConstFrameIt end = d->m_frames.end();
1064 for(; it != end; ++it )
1068 disconnectChild(&*it);
1070 partManager()->removePart( (*it).m_part );
1072 (*it).m_part->deref();
1076 d->m_frames.clear();
1079 ConstFrameIt it = d->m_objects.begin();
1080 ConstFrameIt end = d->m_objects.end();
1081 for(; it != end; ++it )
1086 partManager()->removePart( (*it).m_part );
1088 (*it).m_part->deref();
1092 d->m_objects.clear();
1095 delete d->m_javaContext;
1096 d->m_javaContext = 0;
1099 d->m_scheduledRedirection = noRedirectionScheduled;
1100 d->m_delayRedirect = 0;
1101 d->m_redirectURL = QString::null;
1102 d->m_redirectReferrer = QString::null;
1103 d->m_redirectLockHistory = true;
1104 d->m_redirectUserGesture = false;
1105 d->m_bHTTPRefresh = false;
1106 d->m_bClearing = false;
1107 d->m_frameNameId = 1;
1108 d->m_bFirstData = true;
1110 d->m_bMousePressed = false;
1112 #ifndef QT_NO_CLIPBOARD
1113 connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
1117 d->m_totalObjectCount = 0;
1118 d->m_loadedObjects = 0;
1119 d->m_jobPercent = 0;
1122 if ( !d->m_haveEncoding )
1123 d->m_encoding = QString::null;
1125 d->m_parsetime.restart();
1129 bool KHTMLPart::openFile()
1134 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
1141 void KHTMLPart::replaceDocImpl(DocumentImpl* newDoc)
1154 /*bool KHTMLPart::isSSLInUse() const
1156 return d->m_ssl_in_use;
1159 void KHTMLPart::receivedFirstData()
1161 // Leave indented one extra for easier merging.
1163 //kdDebug( 6050 ) << "begin!" << endl;
1165 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1168 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
1169 d->m_workingURL = KURL();
1171 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
1173 // When the first data arrives, the metadata has just been made available
1177 d->m_bSecurityInQuestion = false;
1178 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
1179 kdDebug(6050) << "SSL in use? " << d->m_job->queryMetaData("ssl_in_use") << endl;
1182 KHTMLPart *p = parentPart();
1183 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
1184 while (p->parentPart()) p = p->parentPart();
1186 p->d->m_paSecurity->setIcon( "halfencrypted" );
1187 p->d->m_bSecurityInQuestion = true;
1188 kdDebug(6050) << "parent setIcon half done." << endl;
1192 d->m_paSecurity->setIcon( d->m_ssl_in_use ? "encrypted" : "decrypted" );
1193 kdDebug(6050) << "setIcon " << ( d->m_ssl_in_use ? "encrypted" : "decrypted" ) << " done." << endl;
1195 // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
1197 d->m_ssl_peer_certificate = d->m_job->queryMetaData("ssl_peer_certificate");
1198 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
1199 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
1200 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
1201 d->m_ssl_cipher_desc = d->m_job->queryMetaData("ssl_cipher_desc");
1202 d->m_ssl_cipher_version = d->m_job->queryMetaData("ssl_cipher_version");
1203 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
1204 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
1205 d->m_ssl_cert_state = d->m_job->queryMetaData("ssl_cert_state");
1207 // Check for charset meta-data
1208 QString qData = d->m_job->queryMetaData("charset");
1209 if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
1210 d->m_encoding = qData;
1211 #endif // APPLE_CHANGES
1213 // Support for http-refresh
1214 qData = d->m_job->queryMetaData("http-refresh");
1215 if( !qData.isEmpty() && d->m_metaRefreshEnabled )
1217 kdDebug(6050) << "HTTP Refresh Request: " << qData << endl;
1219 int pos = qData.find( ';' );
1221 pos = qData.find( ',' );
1225 delay = qData.stripWhiteSpace().toDouble();
1227 // We want a new history item if the refresh timeout > 1 second
1228 scheduleRedirection( delay, m_url.url(), delay <= 1);
1230 scheduleRedirection( delay, m_url.url());
1235 int end_pos = qData.length();
1236 delay = qData.left(pos).stripWhiteSpace().toDouble();
1237 while ( qData[++pos] == ' ' );
1238 if ( qData.find( "url", pos, false ) == pos )
1241 while (qData[pos] == ' ' || qData[pos] == '=' )
1243 if ( qData[pos] == '"' )
1246 int index = end_pos-1;
1247 while( index > pos )
1249 if ( qData[index] == '"' )
1258 // We want a new history item if the refresh timeout > 1 second
1259 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ), delay <= 1);
1261 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ));
1264 d->m_bHTTPRefresh = true;
1267 // Support for http last-modified
1268 d->m_lastModified = d->m_job->queryMetaData("modified");
1269 //kdDebug() << "KHTMLPart::slotData metadata modified: " << d->m_lastModified << endl;
1274 void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
1276 assert ( d->m_job == kio_job );
1278 //kdDebug( 6050 ) << "slotData: " << data.size() << endl;
1280 if ( !d->m_workingURL.isEmpty() )
1281 receivedFirstData( );
1283 KHTMLPageCache::self()->addData(d->m_cacheId, data);
1284 write( data.data(), data.size() );
1287 void KHTMLPart::slotRestoreData(const QByteArray &data )
1290 if ( !d->m_workingURL.isEmpty() )
1292 long saveCacheId = d->m_cacheId;
1293 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1294 d->m_cacheId = saveCacheId;
1295 d->m_workingURL = KURL();
1298 //kdDebug( 6050 ) << "slotRestoreData: " << data.size() << endl;
1299 write( data.data(), data.size() );
1301 if (data.size() == 0)
1303 //kdDebug( 6050 ) << "slotRestoreData: <<end of data>>" << endl;
1305 if (d->m_doc && d->m_doc->parsing())
1306 end(); //will emit completed()
1310 void KHTMLPart::showError( KIO::Job* job )
1312 kdDebug() << "KHTMLPart::showError d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
1313 << " d->m_bCleared=" << d->m_bCleared << endl;
1315 if (job->error() == KIO::ERR_NO_CONTENT)
1318 if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
1319 job->showErrorDialog( /*d->m_view*/ );
1322 htmlError( job->error(), job->errorText(), d->m_workingURL );
1326 // This is a protected method, placed here because of it's relevance to showError
1327 void KHTMLPart::htmlError( int errorCode, const QString& text, const KURL& reqUrl )
1329 kdDebug(6050) << "KHTMLPart::htmlError errorCode=" << errorCode << " text=" << text << endl;
1330 // make sure we're not executing any embedded JS
1331 bool bJSFO = d->m_bJScriptForce;
1332 bool bJSOO = d->m_bJScriptOverride;
1333 d->m_bJScriptForce = false;
1334 d->m_bJScriptOverride = true;
1336 QString errText = QString::fromLatin1( "<HTML><HEAD><TITLE>" );
1337 errText += i18n( "Error while loading %1" ).arg( reqUrl.htmlURL() );
1338 errText += QString::fromLatin1( "</TITLE></HEAD><BODY><P>" );
1339 errText += i18n( "An error occured while loading <B>%1</B>:" ).arg( reqUrl.htmlURL() );
1340 errText += QString::fromLatin1( "</P><P>" );
1341 QString kioErrString = KIO::buildErrorString( errorCode, text );
1343 kioErrString.replace(QRegExp("&"), QString("&"));
1344 kioErrString.replace(QRegExp("<"), QString("<"));
1345 kioErrString.replace(QRegExp(">"), QString(">"));
1347 // In case the error string has '\n' in it, replace with <BR/>
1348 kioErrString.replace( QRegExp("\n"), "<BR/>" );
1350 errText += kioErrString;
1351 errText += QString::fromLatin1( "</P></BODY></HTML>" );
1355 d->m_bJScriptForce = bJSFO;
1356 d->m_bJScriptOverride = bJSOO;
1358 // make the working url the current url, so that reload works and
1359 // emit the progress signals to advance one step in the history
1360 // (so that 'back' works)
1361 m_url = reqUrl; // same as d->m_workingURL
1362 d->m_workingURL = KURL();
1366 // following disabled until 3.1
1368 QString errorName, techName, description;
1369 QStringList causes, solutions;
1371 QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
1372 QDataStream stream(raw, IO_ReadOnly);
1374 stream >> errorName >> techName >> description >> causes >> solutions;
1376 QString url, protocol, datetime;
1377 url = reqUrl.prettyURL();
1378 protocol = reqUrl.protocol();
1379 datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
1382 QString doc = QString::fromLatin1( "<html><head><title>" );
1383 doc += i18n( "Error: " );
1385 doc += QString::fromLatin1( " - %1</title></head><body><h1>" ).arg( url );
1386 doc += i18n( "The requested operation could not be completed" );
1387 doc += QString::fromLatin1( "</h1><h2>" );
1389 doc += QString::fromLatin1( "</h2>" );
1390 if ( techName != QString::null ) {
1391 doc += QString::fromLatin1( "<h2>" );
1392 doc += i18n( "Technical Reason: " );
1394 doc += QString::fromLatin1( "</h2>" );
1396 doc += QString::fromLatin1( "<h3>" );
1397 doc += i18n( "Details of the Request:" );
1398 doc += QString::fromLatin1( "</h3><ul><li>" );
1399 doc += i18n( "URL: %1" ).arg( url );
1400 doc += QString::fromLatin1( "</li><li>" );
1401 if ( protocol != QString::null ) {
1402 // uncomment for 3.1... i18n change
1403 // doc += i18n( "Protocol: %1" ).arg( protocol ).arg( protocol );
1404 doc += QString::fromLatin1( "</li><li>" );
1406 doc += i18n( "Date and Time: %1" ).arg( datetime );
1407 doc += QString::fromLatin1( "</li><li>" );
1408 doc += i18n( "Additional Information: %1" ).arg( text );
1409 doc += QString::fromLatin1( "</li></ul><h3>" );
1410 doc += i18n( "Description:" );
1411 doc += QString::fromLatin1( "</h3><p>" );
1413 doc += QString::fromLatin1( "</p>" );
1414 if ( causes.count() ) {
1415 doc += QString::fromLatin1( "<h3>" );
1416 doc += i18n( "Possible Causes:" );
1417 doc += QString::fromLatin1( "</h3><ul><li>" );
1418 doc += causes.join( "</li><li>" );
1419 doc += QString::fromLatin1( "</li></ul>" );
1421 if ( solutions.count() ) {
1422 doc += QString::fromLatin1( "<h3>" );
1423 doc += i18n( "Possible Solutions:" );
1424 doc += QString::fromLatin1( "</h3><ul><li>" );
1425 doc += solutions.join( "</li><li>" );
1426 doc += QString::fromLatin1( "</li></ul>" );
1428 doc += QString::fromLatin1( "</body></html>" );
1436 void KHTMLPart::slotFinished( KIO::Job * job )
1440 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
1443 emit canceled( job->errorString() );
1445 // TODO: what else ?
1452 //kdDebug( 6050 ) << "slotFinished" << endl;
1454 KHTMLPageCache::self()->endData(d->m_cacheId);
1456 if ( d->m_doc && d->m_doc->docLoader()->expireDate() && m_url.protocol().lower().startsWith("http"))
1457 KIO::http_update_cache(m_url, false, d->m_doc->docLoader()->expireDate());
1459 d->m_workingURL = KURL();
1462 if (d->m_doc->parsing())
1463 end(); //will emit completed()
1467 void KHTMLPart::childBegin()
1469 // We need to do this when the child is created so as to avoid the bogus state of the parent's
1470 // child->m_bCompleted being false but the child's m_bComplete being true. If the child gets
1471 // an error early on, we had trouble where checkingComplete on the child was a NOP because
1472 // it thought it was already complete, and thus the parent was never signaled, and never set
1473 // its child->m_bComplete.
1474 d->m_bComplete = false;
1478 void KHTMLPart::begin( const KURL &url, int xOffset, int yOffset )
1481 // If we aren't loading an actual URL, then we need to make sure
1482 // that we have at least an empty document. createEmptyDocument will
1483 // do that if we don't have a document already.
1484 if (d->m_workingURL.isEmpty()) {
1485 KWQ(this)->createEmptyDocument();
1492 KWQ(this)->partClearedInBegin();
1495 // Only do this after clearing the part, so that JavaScript can
1496 // clean up properly if it was on for the last load.
1498 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
1500 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
1503 d->m_bCleared = false;
1505 d->m_bComplete = false;
1506 d->m_bLoadEventEmitted = false;
1507 d->m_bLoadingMainResource = true;
1511 KHTMLFactory::vLinks()->insert( KWQ(this)->requestedURLString() );
1513 QString urlString = url.url();
1514 KHTMLFactory::vLinks()->insert( urlString );
1515 QString urlString2 = url.prettyURL();
1516 if ( urlString != urlString2 ) {
1517 KHTMLFactory::vLinks()->insert( urlString2 );
1525 KParts::URLArgs args( d->m_extension->urlArgs() );
1526 args.xOffset = xOffset;
1527 args.yOffset = yOffset;
1528 d->m_extension->setURLArgs( args );
1531 ref.setUser(QSTRING_NULL);
1532 ref.setPass(QSTRING_NULL);
1533 ref.setRef(QSTRING_NULL);
1534 d->m_referrer = ref.url();
1539 // We don't need KDE chained URI handling or window caption setting
1540 if ( !m_url.isEmpty() )
1545 if ( !m_url.isEmpty() )
1547 KURL::List lst = KURL::split( m_url );
1548 if ( !lst.isEmpty() )
1549 baseurl = *lst.begin();
1551 KURL title( baseurl );
1552 title.setRef( QString::null );
1553 title.setQuery( QString::null );
1554 emit setWindowCaption( title.url() );
1557 emit setWindowCaption( i18n( "no title", "* Unknown *" ) );
1560 if (args.serviceType == "text/xml" || args.serviceType == "application/xml" || args.serviceType == "application/xhtml+xml" ||
1561 args.serviceType == "text/xsl" || args.serviceType == "application/rss+xml" || args.serviceType == "application/atom+xml")
1562 d->m_doc = DOMImplementationImpl::instance()->createDocument( d->m_view );
1564 d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
1567 if (!d->m_doc->attached())
1568 d->m_doc->attach( );
1569 d->m_doc->setURL( m_url.url() );
1570 // We prefer m_baseURL over m_url because m_url changes when we are
1571 // about to load a new page.
1572 d->m_doc->setBaseURL( baseurl.url() );
1575 d->m_doc->setDecoder(d->m_decoder);
1578 d->m_doc->docLoader()->setShowAnimations( KHTMLFactory::defaultHTMLSettings()->showAnimations() );
1580 d->m_doc->docLoader()->setShowAnimations( d->m_settings->showAnimations() );
1584 KWQ(this)->updatePolicyBaseURL();
1588 d->m_paUseStylesheet->setItems(QStringList());
1589 d->m_paUseStylesheet->setEnabled( false );
1593 setAutoloadImages( KHTMLFactory::defaultHTMLSettings()->autoLoadImages() );
1594 QString userStyleSheet = KHTMLFactory::defaultHTMLSettings()->userStyleSheet();
1596 setAutoloadImages( d->m_settings->autoLoadImages() );
1597 QString userStyleSheet = d->m_settings->userStyleSheet();
1600 if ( !userStyleSheet.isEmpty() )
1601 setUserStyleSheet( KURL( userStyleSheet ) );
1604 KWQ(this)->restoreDocumentState();
1606 d->m_doc->setRestoreState(args.docState);
1609 d->m_doc->implicitOpen();
1612 d->m_view->resizeContents( 0, 0 );
1613 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
1616 emit d->m_extension->enableAction( "print", true );
1620 void KHTMLPart::write( const char *str, int len )
1622 if ( !d->m_decoder ) {
1623 d->m_decoder = new Decoder;
1624 if (!d->m_encoding.isNull())
1625 d->m_decoder->setEncoding(d->m_encoding.latin1(),
1626 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
1628 // Inherit the default encoding from the parent frame if there is one.
1629 const char *defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
1630 ? parentPart()->d->m_decoder->encoding() : settings()->encoding().latin1();
1631 d->m_decoder->setEncoding(defaultEncoding, Decoder::DefaultEncoding);
1635 d->m_doc->setDecoder(d->m_decoder);
1642 len = strlen( str );
1644 QString decoded = d->m_decoder->decode( str, len );
1646 if(decoded.isEmpty()) return;
1648 if(d->m_bFirstData) {
1649 // determine the parse mode
1650 d->m_doc->determineParseMode( decoded );
1651 d->m_bFirstData = false;
1653 //kdDebug(6050) << "KHTMLPart::write haveEnc = " << d->m_haveEncoding << endl;
1654 // ### this is still quite hacky, but should work a lot better than the old solution
1655 if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
1656 d->m_doc->recalcStyle( NodeImpl::Force );
1660 jScript()->appendSourceFile(m_url.url(),decoded);
1661 Tokenizer* t = d->m_doc->tokenizer();
1664 t->write( decoded, true );
1667 void KHTMLPart::write( const QString &str )
1672 if(d->m_bFirstData) {
1673 // determine the parse mode
1674 d->m_doc->setParseMode( DocumentImpl::Strict );
1675 d->m_bFirstData = false;
1678 jScript()->appendSourceFile(m_url.url(),str);
1679 Tokenizer* t = d->m_doc->tokenizer();
1681 t->write( str, true );
1684 void KHTMLPart::end()
1686 d->m_bLoadingMainResource = false;
1690 void KHTMLPart::endIfNotLoading()
1692 if (d->m_bLoadingMainResource)
1695 // make sure nothing's left in there...
1697 write(d->m_decoder->flush());
1699 d->m_doc->finishParsing();
1701 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
1702 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1703 // become true. An example is when a subframe is a pure text doc, and that subframe is the
1704 // last one to complete.
1708 void KHTMLPart::stop()
1710 // make sure nothing's left in there...
1711 Tokenizer* t = d->m_doc ? d->m_doc->tokenizer() : 0;
1715 d->m_doc->finishParsing();
1717 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
1718 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1719 // become true. An example is when a subframe is a pure text doc, and that subframe is the
1720 // last one to complete.
1726 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
1728 if (!d->m_view) return;
1729 d->m_view->paint(p, rc, yOff, more);
1734 void KHTMLPart::stopAnimations()
1737 d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
1739 ConstFrameIt it = d->m_frames.begin();
1740 ConstFrameIt end = d->m_frames.end();
1741 for (; it != end; ++it )
1742 if ( !( *it ).m_part.isNull() && ( *it ).m_part->inherits( "KHTMLPart" ) ) {
1743 KParts::ReadOnlyPart* p = ( *it ).m_part;
1744 static_cast<KHTMLPart*>( p )->stopAnimations();
1748 void KHTMLPart::gotoAnchor()
1750 if (m_url.hasRef()) {
1751 QString ref = m_url.encodedHtmlRef();
1752 if (!gotoAnchor(ref)) {
1753 // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
1754 // Decoding here has to match encoding in completeURL, which means it has to use the
1755 // page's encoding rather than UTF-8.
1758 gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()->mibEnum()));
1760 gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()));
1766 void KHTMLPart::slotFinishedParsing()
1768 d->m_doc->setParsing(false);
1771 return; // We are probably being destructed.
1776 return; // We are being destroyed by something checkCompleted called.
1778 // check if the scrollbars are really needed for the content
1779 // if not, remove them, relayout, and repaint
1781 d->m_view->restoreScrollBar();
1785 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
1788 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1789 KHTMLPart* p = this;
1792 p->d->m_totalObjectCount++;
1793 p = p->parentPart();
1794 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount )
1795 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1801 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
1804 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1805 KHTMLPart* p = this;
1808 p->d->m_loadedObjects++;
1809 p = p->parentPart();
1810 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount && d->m_jobPercent >= 100 )
1811 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1815 // We really only need to call checkCompleted when our own resources are done loading.
1816 // So we should check that d->m_doc->docLoader() == dl here.
1817 // That might help with performance by skipping some unnecessary work, but it's too
1818 // risky to make that change right now (2005-02-07), because we might be accidentally
1819 // depending on the extra checkCompleted calls.
1827 void KHTMLPart::slotProgressUpdate()
1830 if ( d->m_loadedObjects < d->m_totalObjectCount )
1831 percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
1833 percent = d->m_jobPercent;
1835 if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
1836 emit d->m_extension->infoMessage( i18n( "%1 of 1 Image loaded", "%1 of %n Images loaded", d->m_totalObjectCount ).arg( d->m_loadedObjects ) );
1838 emit d->m_extension->loadingProgress( percent );
1841 void KHTMLPart::slotJobSpeed( KIO::Job* /*job*/, unsigned long speed )
1843 emit d->m_extension->speedProgress( speed );
1846 void KHTMLPart::slotJobPercent( KIO::Job* /*job*/, unsigned long percent )
1848 d->m_jobPercent = percent;
1850 if ( !parentPart() )
1851 QTimer::singleShot( 0, this, SLOT( slotProgressUpdate() ) );
1856 void KHTMLPart::checkCompleted()
1858 // kdDebug( 6050 ) << "KHTMLPart::checkCompleted() parsing: " << d->m_doc->parsing() << endl;
1859 // kdDebug( 6050 ) << " complete: " << d->m_bComplete << endl;
1862 // restore the cursor position
1863 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
1865 if (d->m_focusNodeNumber >= 0)
1866 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
1868 d->m_doc->setFocusNode(0);
1869 d->m_focusNodeRestored = true;
1873 // Any frame that hasn't completed yet ?
1874 ConstFrameIt it = d->m_frames.begin();
1875 ConstFrameIt end = d->m_frames.end();
1876 for (; it != end; ++it )
1877 if ( !(*it).m_bCompleted )
1880 // Have we completed before?
1881 if ( d->m_bComplete )
1884 // Are we still parsing?
1885 if ( d->m_doc && d->m_doc->parsing() )
1888 // Still waiting for images/scripts from the loader ?
1890 if ( d->m_doc && d->m_doc->docLoader() )
1891 requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
1897 // Now do what should be done when we are really completed.
1898 d->m_bComplete = true;
1900 checkEmitLoadEvent(); // if we didn't do it before
1903 // check that the view has not been moved by the user
1904 if ( !m_url.hasRef() && d->m_view->contentsY() == 0 )
1905 d->m_view->setContentsPos( d->m_extension->urlArgs().xOffset,
1906 d->m_extension->urlArgs().yOffset );
1909 if ( d->m_scheduledRedirection != noRedirectionScheduled )
1911 // Do not start redirection for frames here! That action is
1912 // deferred until the parent emits a completed signal.
1913 if ( parentPart() == 0 )
1914 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1916 emit completed( true );
1920 if ( d->m_bPendingChildRedirection )
1921 emit completed ( true );
1927 // find the alternate stylesheets
1930 sheets = d->m_doc->availableStyleSheets();
1931 d->m_paUseStylesheet->setItems( sheets );
1932 d->m_paUseStylesheet->setEnabled( !sheets.isEmpty() );
1933 if (!sheets.isEmpty())
1935 d->m_paUseStylesheet->setCurrentItem(kMax(sheets.findIndex(d->m_sheetUsed), 0));
1936 slotUseStylesheet();
1940 emit setStatusBarText(i18n("Done."));
1944 kdDebug(6050) << "DONE: " <<d->m_parsetime.elapsed() << endl;
1948 void KHTMLPart::checkEmitLoadEvent()
1950 if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
1952 ConstFrameIt it = d->m_frames.begin();
1953 ConstFrameIt end = d->m_frames.end();
1954 for (; it != end; ++it )
1955 if ( !(*it).m_bCompleted ) // still got a frame running -> too early
1959 // All frames completed -> set their domain to the frameset's domain
1960 // This must only be done when loading the frameset initially (#22039),
1961 // not when following a link in a frame (#44162).
1964 DOMString domain = d->m_doc->domain();
1965 ConstFrameIt it = d->m_frames.begin();
1966 ConstFrameIt end = d->m_frames.end();
1967 for (; it != end; ++it )
1969 KParts::ReadOnlyPart *p = (*it).m_part;
1970 if ( p && p->inherits( "KHTMLPart" ))
1972 KHTMLPart* htmlFrame = static_cast<KHTMLPart *>(p);
1973 if (htmlFrame->d->m_doc)
1975 kdDebug() << "KHTMLPart::checkCompleted setting frame domain to " << domain.string() << endl;
1976 htmlFrame->d->m_doc->setDomain( domain );
1982 d->m_bLoadEventEmitted = true;
1983 d->m_bUnloadEventEmitted = false;
1985 d->m_doc->implicitClose();
1988 const KHTMLSettings *KHTMLPart::settings() const
1990 return d->m_settings;
1993 #ifndef KDE_NO_COMPAT
1994 KURL KHTMLPart::baseURL() const
1996 if ( !d->m_doc ) return KURL();
1998 return d->m_doc->baseURL();
2001 QString KHTMLPart::baseTarget() const
2003 if ( !d->m_doc ) return QString::null;
2005 return d->m_doc->baseTarget();
2009 KURL KHTMLPart::completeURL( const QString &url )
2011 if ( !d->m_doc ) return url;
2015 return KURL(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
2018 return KURL( d->m_doc->completeURL( url ) );
2021 void KHTMLPart::scheduleRedirection( double delay, const QString &url, bool doLockHistory)
2023 kdDebug(6050) << "KHTMLPart::scheduleRedirection delay=" << delay << " url=" << url << endl;
2024 if (delay < 0 || delay > INT_MAX / 1000)
2026 if ( d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect )
2028 d->m_scheduledRedirection = redirectionScheduled;
2029 d->m_delayRedirect = delay;
2030 d->m_redirectURL = url;
2031 d->m_redirectReferrer = QString::null;
2032 d->m_redirectLockHistory = doLockHistory;
2033 d->m_redirectUserGesture = false;
2035 d->m_redirectionTimer.stop();
2036 if ( d->m_bComplete )
2037 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
2041 void KHTMLPart::scheduleLocationChange(const QString &url, const QString &referrer, bool lockHistory, bool userGesture)
2043 // Handle a location change of a page with no document as a special case.
2044 // This may happen when a frame changes the location of another frame.
2045 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
2046 d->m_delayRedirect = 0;
2047 d->m_redirectURL = url;
2048 d->m_redirectReferrer = referrer;
2049 d->m_redirectLockHistory = lockHistory;
2050 d->m_redirectUserGesture = userGesture;
2051 d->m_redirectionTimer.stop();
2053 d->m_redirectionTimer.start(0, true);
2056 bool KHTMLPart::isScheduledLocationChangePending() const
2058 switch (d->m_scheduledRedirection) {
2059 case noRedirectionScheduled:
2060 case redirectionScheduled:
2062 case historyNavigationScheduled:
2063 case locationChangeScheduled:
2064 case locationChangeScheduledDuringLoad:
2070 void KHTMLPart::scheduleHistoryNavigation( int steps )
2073 // navigation will always be allowed in the 0 steps case, which is OK because
2074 // that's supposed to force a reload.
2075 if (!KWQ(this)->canGoBackOrForward(steps)) {
2076 cancelRedirection();
2081 d->m_scheduledRedirection = historyNavigationScheduled;
2082 d->m_delayRedirect = 0;
2083 d->m_redirectURL = QString::null;
2084 d->m_redirectReferrer = QString::null;
2085 d->m_scheduledHistoryNavigationSteps = steps;
2086 d->m_redirectionTimer.stop();
2088 d->m_redirectionTimer.start(0, true);
2091 void KHTMLPart::cancelRedirection(bool cancelWithLoadInProgress)
2094 d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
2095 d->m_scheduledRedirection = noRedirectionScheduled;
2096 d->m_redirectionTimer.stop();
2100 void KHTMLPart::slotRedirect()
2102 if (d->m_scheduledRedirection == historyNavigationScheduled) {
2103 d->m_scheduledRedirection = noRedirectionScheduled;
2105 // Special case for go(0) from a frame -> reload only the frame
2106 // go(i!=0) from a frame navigates into the history of the frame only,
2107 // in both IE and NS (but not in Mozilla).... we can't easily do that
2109 if (d->m_scheduledHistoryNavigationSteps == 0) // add && parentPart() to get only frames, but doesn't matter
2110 openURL( url() ); /// ## need args.reload=true?
2112 if (d->m_extension) {
2113 BrowserInterface *interface = d->m_extension->browserInterface();
2115 interface->callMethod( "goHistory(int)", d->m_scheduledHistoryNavigationSteps );
2121 QString u = d->m_redirectURL;
2123 d->m_scheduledRedirection = noRedirectionScheduled;
2124 d->m_delayRedirect = 0;
2125 d->m_redirectURL = QString::null;
2126 if ( u.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
2128 QString script = KURL::decode_string( u.right( u.length() - 11 ) );
2129 //kdDebug( 6050 ) << "KHTMLPart::slotRedirect script=" << script << endl;
2130 QVariant res = executeScript( script, d->m_redirectUserGesture );
2131 if ( res.type() == QVariant::String ) {
2133 write( res.asString() );
2138 KParts::URLArgs args;
2139 if ( urlcmp( u, m_url.url(), true, false ) )
2142 args.setLockHistory( d->m_redirectLockHistory );
2143 if (!d->m_redirectReferrer.isEmpty())
2144 args.metaData()["referrer"] = d->m_redirectReferrer;
2145 d->m_redirectReferrer = QString::null;
2147 urlSelected( u, 0, 0, "_self", args );
2150 void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url)
2152 // the slave told us that we got redirected
2153 // kdDebug( 6050 ) << "redirection by KIO to " << url.url() << endl;
2154 emit d->m_extension->setLocationBarURL( url.prettyURL() );
2155 d->m_workingURL = url;
2160 bool KHTMLPart::setEncoding( const QString &name, bool override )
2162 d->m_encoding = name;
2163 d->m_haveEncoding = override;
2165 if( !m_url.isEmpty() ) {
2170 d->m_restored = true;
2172 d->m_restored = false;
2180 QString KHTMLPart::encoding() const
2182 if(d->m_haveEncoding && !d->m_encoding.isEmpty())
2183 return d->m_encoding;
2185 if(d->m_decoder && d->m_decoder->encoding())
2186 return QString(d->m_decoder->encoding());
2188 return(settings()->encoding());
2191 void KHTMLPart::setUserStyleSheet(const KURL &url)
2193 if ( d->m_doc && d->m_doc->docLoader() )
2194 (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
2197 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
2200 d->m_doc->setUserStyleSheet( styleSheet );
2203 bool KHTMLPart::gotoAnchor( const QString &name )
2208 NodeImpl *n = d->m_doc->getElementById(name);
2210 HTMLCollectionImpl *anchors =
2211 new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
2213 n = anchors->namedItem(name, !d->m_doc->inCompatMode());
2217 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
2219 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2220 if (!n && !(name.isEmpty() || name.lower() == "top")) {
2221 kdDebug(6050) << "KHTMLPart::gotoAnchor node '" << name << "' not found" << endl;
2225 // We need to update the layout before scrolling, otherwise we could
2226 // really mess things up if an anchor scroll comes at a bad moment.
2228 d->m_doc->updateRendering();
2229 // Only do a layout if changes have occurred that make it necessary.
2230 if ( d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() ) {
2231 d->m_view->layout();
2237 static_cast<HTMLElementImpl *>(n)->getUpperLeftCorner(x, y);
2239 // Scroll to actual top left of element with no slop, since some pages expect anchors to be exactly scrolled to.
2241 // Call recursive version so this will expose correctly from within nested frames.
2242 d->m_view->setContentsPosRecursive(x, y);
2244 d->m_view->setContentsPos(x, y);
2250 void KHTMLPart::setStandardFont( const QString &name )
2252 d->m_settings->setStdFontName(name);
2255 void KHTMLPart::setFixedFont( const QString &name )
2257 d->m_settings->setFixedFontName(name);
2262 void KHTMLPart::setURLCursor( const QCursor &c )
2264 d->m_linkCursor = c;
2269 QCursor KHTMLPart::urlCursor() const
2272 // Don't load the link cursor until it's actually used.
2273 // Also, we don't need setURLCursor.
2274 // This speeds up startup time.
2275 return KCursor::handCursor();
2277 return d->m_linkCursor;
2281 bool KHTMLPart::onlyLocalReferences() const
2283 return d->m_onlyLocalReferences;
2286 void KHTMLPart::setOnlyLocalReferences(bool enable)
2288 d->m_onlyLocalReferences = enable;
2293 void KHTMLPart::findTextBegin(NodeImpl *startNode, int startPos)
2295 d->m_findPos = startPos;
2296 d->m_findNode = startNode;
2299 bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensitive, bool isRegExp )
2304 if(!d->m_findNode) {
2305 if (d->m_doc->isHTMLDocument())
2306 d->m_findNode = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
2308 d->m_findNode = d->m_doc;
2311 if ( !d->m_findNode )
2313 kdDebug() << "KHTMLPart::findTextNext no findNode -> return false" << endl;
2316 if ( d->m_findNode->id() == ID_FRAMESET )
2318 kdDebug() << "KHTMLPart::findTextNext FRAMESET -> return false" << endl;
2324 if( (d->m_findNode->nodeType() == Node::TEXT_NODE || d->m_findNode->nodeType() == Node::CDATA_SECTION_NODE) && d->m_findNode->renderer() )
2326 DOMString nodeText = d->m_findNode->nodeValue();
2327 DOMStringImpl *t = nodeText.implementation();
2328 QConstString s(t->s, t->l);
2332 QRegExp matcher( str );
2333 matcher.setCaseSensitive( caseSensitive );
2334 d->m_findPos = matcher.search(s.string(), d->m_findPos+1);
2335 if ( d->m_findPos != -1 )
2336 matchLen = matcher.matchedLength();
2339 d->m_findPos = s.string().find(str, d->m_findPos+1, caseSensitive);
2340 matchLen = str.length();
2343 if(d->m_findPos != -1)
2346 static_cast<khtml::RenderText *>(d->m_findNode->renderer())
2347 ->posOfChar(d->m_findPos, x, y);
2348 d->m_view->setContentsPos(x-50, y-50);
2349 Position p1(d->m_findNode, d->m_findPos);
2350 Position p2(d->m_findNode, d->m_findPos + matchLen);
2351 setSelection(Selection(p1, khtml::DOWNSTREAM, p2, khtml::SEL_PREFER_UPSTREAM_AFFINITY));
2361 next = d->m_findNode->firstChild();
2363 if(!next) next = d->m_findNode->nextSibling();
2364 while(d->m_findNode && !next) {
2365 d->m_findNode = d->m_findNode->parentNode();
2366 if( d->m_findNode ) {
2367 next = d->m_findNode->nextSibling();
2373 next = d->m_findNode->lastChild();
2375 if (!next ) next = d->m_findNode->previousSibling();
2376 while ( d->m_findNode && !next )
2378 d->m_findNode = d->m_findNode->parentNode();
2381 next = d->m_findNode->previousSibling();
2386 d->m_findNode = next;
2387 if(!d->m_findNode) return false;
2391 #endif // APPLE_CHANGES
2393 QString KHTMLPart::text(const DOM::Range &r) const
2395 return plainText(r);
2398 QString KHTMLPart::selectedText() const
2400 return text(selection().toRange());
2403 bool KHTMLPart::hasSelection() const
2405 return d->m_selection.isCaretOrRange();
2408 const Selection &KHTMLPart::selection() const
2410 return d->m_selection;
2413 ETextGranularity KHTMLPart::selectionGranularity() const
2415 return d->m_selectionGranularity;
2418 void KHTMLPart::setSelectionGranularity(ETextGranularity granularity) const
2420 d->m_selectionGranularity = granularity;
2423 const Selection &KHTMLPart::dragCaret() const
2425 return d->m_dragCaret;
2428 const Selection &KHTMLPart::mark() const
2433 void KHTMLPart::setMark(const Selection &s)
2438 void KHTMLPart::setSelection(const Selection &s, bool closeTyping, bool keepTypingStyle)
2440 if (d->m_selection == s) {
2444 clearCaretRectIfNeeded();
2447 Selection oldSelection = d->m_selection;
2452 setFocusNodeIfNeeded();
2454 selectionLayoutChanged();
2456 // Always clear the x position used for vertical arrow navigation.
2457 // It will be restored by the vertical arrow navigation code if necessary.
2458 d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
2461 TypingCommand::closeTyping(lastEditCommand());
2463 if (!keepTypingStyle)
2467 KWQ(this)->respondToChangedSelection(oldSelection, closeTyping);
2470 emitSelectionChanged();
2473 void KHTMLPart::setDragCaret(const Selection &dragCaret)
2475 if (d->m_dragCaret != dragCaret) {
2476 d->m_dragCaret.needsCaretRepaint();
2477 d->m_dragCaret = dragCaret;
2478 d->m_dragCaret.needsCaretRepaint();
2482 void KHTMLPart::clearSelection()
2484 setSelection(Selection());
2487 void KHTMLPart::invalidateSelection()
2489 clearCaretRectIfNeeded();
2490 d->m_selection.setNeedsLayout();
2491 selectionLayoutChanged();
2494 void KHTMLPart::setCaretVisible(bool flag)
2496 if (d->m_caretVisible == flag)
2498 clearCaretRectIfNeeded();
2500 setFocusNodeIfNeeded();
2501 d->m_caretVisible = flag;
2502 selectionLayoutChanged();
2506 void KHTMLPart::slotClearSelection()
2512 void KHTMLPart::clearCaretRectIfNeeded()
2514 if (d->m_caretPaint) {
2515 d->m_caretPaint = false;
2516 d->m_selection.needsCaretRepaint();
2520 // Helper function that tells whether a particular node is an element that has an entire
2521 // KHTMLPart and KHTMLView, a <frame>, <iframe>, or <object>.
2522 static bool isFrame(const NodeImpl *n)
2526 RenderObject *renderer = n->renderer();
2527 if (!renderer || !renderer->isWidget())
2529 QWidget *widget = static_cast<RenderWidget *>(renderer)->widget();
2530 return widget && widget->inherits("KHTMLView");
2533 void KHTMLPart::setFocusNodeIfNeeded()
2535 if (!xmlDocImpl() || d->m_selection.isNone() || !d->m_isFocused)
2538 NodeImpl *n = d->m_selection.start().node();
2539 NodeImpl *target = (n && n->isContentEditable()) ? n : 0;
2541 while (n && n != d->m_selection.end().node()) {
2542 if (n->isContentEditable()) {
2546 n = n->traverseNextNode();
2549 assert(target == 0 || target->isContentEditable());
2552 for ( ; target; target = target->parentNode()) {
2553 // We don't want to set focus on a subframe when selecting in a parent frame,
2554 // so add the !isFrame check here. There's probably a better way to make this
2555 // work in the long term, but this is the safest fix at this time.
2556 if (target->isMouseFocusable() && !isFrame(target)) {
2557 xmlDocImpl()->setFocusNode(target);
2561 xmlDocImpl()->setFocusNode(0);
2565 void KHTMLPart::selectionLayoutChanged()
2567 // kill any caret blink timer now running
2568 if (d->m_caretBlinkTimer >= 0) {
2569 killTimer(d->m_caretBlinkTimer);
2570 d->m_caretBlinkTimer = -1;
2573 // see if a new caret blink timer needs to be started
2574 if (d->m_caretVisible && d->m_caretBlinks &&
2575 d->m_selection.isCaret() && d->m_selection.start().node()->isContentEditable()) {
2576 d->m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
2577 d->m_caretPaint = true;
2578 d->m_selection.needsCaretRepaint();
2582 d->m_doc->updateSelection();
2585 void KHTMLPart::setXPosForVerticalArrowNavigation(int x)
2587 d->m_xPosForVerticalArrowNavigation = x;
2590 int KHTMLPart::xPosForVerticalArrowNavigation() const
2592 return d->m_xPosForVerticalArrowNavigation;
2595 void KHTMLPart::timerEvent(QTimerEvent *e)
2597 if (e->timerId() == d->m_caretBlinkTimer &&
2598 d->m_caretVisible &&
2600 d->m_selection.isCaret()) {
2601 if (d->m_bMousePressed) {
2602 if (!d->m_caretPaint) {
2603 d->m_caretPaint = true;
2604 d->m_selection.needsCaretRepaint();
2608 d->m_caretPaint = !d->m_caretPaint;
2609 d->m_selection.needsCaretRepaint();
2614 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
2616 if (d->m_caretPaint)
2617 d->m_selection.paintCaret(p, rect);
2620 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
2622 d->m_dragCaret.paintCaret(p, rect);
2627 void KHTMLPart::overURL( const QString &url, const QString &target, bool shiftPressed )
2629 if ( !d->m_kjsStatusBarText.isEmpty() && !shiftPressed ) {
2631 emit setStatusBarText( d->m_kjsStatusBarText );
2632 d->m_kjsStatusBarText = QString::null;
2638 if ( url.isEmpty() )
2640 emit setStatusBarText(completeURL(url).htmlURL());
2644 if (url.find( QString::fromLatin1( "javascript:" ),0, false ) != -1 )
2646 emit setStatusBarText( KURL::decode_string( url.mid( url.find( "javascript:", 0, false ) ) ) );
2650 KURL u = completeURL(url);
2652 // special case for <a href="">
2653 if ( url.isEmpty() )
2654 u.setFileName( url );
2658 KMimeType::Ptr typ = KMimeType::findByURL( u );
2661 com = typ->comment( u, false );
2663 if ( u.isMalformed() )
2665 emit setStatusBarText(u.htmlURL());
2669 if ( u.isLocalFile() )
2671 // TODO : use KIO::stat() and create a KFileItem out of its result,
2672 // to use KFileItem::statusBarText()
2673 QCString path = QFile::encodeName( u.path() );
2676 bool ok = !stat( path.data(), &buff );
2679 if (ok) ok = !lstat( path.data(), &lbuff );
2681 QString text = u.htmlURL();
2682 QString text2 = text;
2684 if (ok && S_ISLNK( lbuff.st_mode ) )
2688 tmp = i18n( "Symbolic Link");
2690 tmp = i18n("%1 (Link)").arg(com);
2691 char buff_two[1024];
2693 int n = readlink ( path.data(), buff_two, 1022);
2698 emit setStatusBarText(text2);
2707 else if ( ok && S_ISREG( buff.st_mode ) )
2709 if (buff.st_size < 1024)
2710 text = i18n("%2 (%1 bytes)").arg((long) buff.st_size).arg(text2); // always put the URL last, in case it contains '%'
2713 float d = (float) buff.st_size/1024.0;
2714 text = i18n("%1 (%2 K)").arg(text2).arg(KGlobal::locale()->formatNumber(d, 2)); // was %.2f
2719 else if ( ok && S_ISDIR( buff.st_mode ) )
2729 emit setStatusBarText(text);
2734 if (target == QString::fromLatin1("_blank"))
2736 extra = i18n(" (In new window)");
2738 else if (!target.isEmpty() &&
2739 (target != QString::fromLatin1("_top")) &&
2740 (target != QString::fromLatin1("_self")) &&
2741 (target != QString::fromLatin1("_parent")))
2743 extra = i18n(" (In other frame)");
2746 if (u.protocol() == QString::fromLatin1("mailto")) {
2747 QString mailtoMsg/* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
2748 mailtoMsg += i18n("Email to: ") + KURL::decode_string(u.path());
2749 QStringList queries = QStringList::split('&', u.query().mid(1));
2750 for (QStringList::Iterator it = queries.begin(); it != queries.end(); ++it)
2751 if ((*it).startsWith(QString::fromLatin1("subject=")))
2752 mailtoMsg += i18n(" - Subject: ") + KURL::decode_string((*it).mid(8));
2753 else if ((*it).startsWith(QString::fromLatin1("cc=")))
2754 mailtoMsg += i18n(" - CC: ") + KURL::decode_string((*it).mid(3));
2755 else if ((*it).startsWith(QString::fromLatin1("bcc=")))
2756 mailtoMsg += i18n(" - BCC: ") + KURL::decode_string((*it).mid(4));
2757 mailtoMsg.replace(QRegExp("&"), QString("&"));
2758 mailtoMsg.replace(QRegExp("<"), QString("<"));
2759 mailtoMsg.replace(QRegExp(">"), QString(">"));
2760 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), "");
2761 emit setStatusBarText(mailtoMsg);
2764 // Is this check neccessary at all? (Frerich)
2766 else if (u.protocol() == QString::fromLatin1("http")) {
2767 DOM::Node hrefNode = nodeUnderMouse().parentNode();
2768 while (hrefNode.nodeName().string() != QString::fromLatin1("A") && !hrefNode.isNull())
2769 hrefNode = hrefNode.parentNode();
2771 if (!hrefNode.isNull()) {
2772 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
2773 if (!hreflangNode.isNull()) {
2774 QString countryCode = hreflangNode.nodeValue().string().lower();
2775 // Map the language code to an appropriate country code.
2776 if (countryCode == QString::fromLatin1("en"))
2777 countryCode = QString::fromLatin1("gb");
2778 QString flagImg = QString::fromLatin1("<img src=%1>").arg(
2779 locate("locale", QString::fromLatin1("l10n/")
2781 + QString::fromLatin1("/flag.png")));
2782 emit setStatusBarText(flagImg + u.prettyURL() + extra);
2787 emit setStatusBarText(u.htmlURL() + extra);
2791 #endif // APPLE_CHANGES
2793 void KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target,
2794 KParts::URLArgs args )
2796 bool hasTarget = false;
2798 QString target = _target;
2799 if ( target.isEmpty() && d->m_doc )
2800 target = d->m_doc->baseTarget();
2801 if ( !target.isEmpty() )
2804 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
2806 executeScript( KURL::decode_string( url.right( url.length() - 11) ), true );
2810 KURL cURL = completeURL(url);
2812 // special case for <a href="">
2813 if ( url.isEmpty() )
2814 cURL.setFileName( url );
2817 if ( !cURL.isValid() )
2818 // ### ERROR HANDLING
2821 //kdDebug( 6000 ) << "urlSelected: complete URL:" << cURL.url() << " target = " << target << endl;
2824 if ( button == LeftButton && ( state & ShiftButton ) )
2826 KIO::MetaData metaData;
2827 metaData["referrer"] = d->m_referrer;
2828 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As..." ), cURL, metaData );
2832 if (!checkLinkSecurity(cURL,
2833 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?" ),
2838 args.frameName = target;
2840 if ( d->m_bHTTPRefresh )
2842 d->m_bHTTPRefresh = false;
2843 args.metaData()["cache"] = "refresh";
2847 args.metaData().insert("main_frame_request",
2848 parentPart() == 0 ? "TRUE":"FALSE");
2849 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
2850 args.metaData().insert("ssl_activate_warnings", "TRUE");
2854 args.metaData()["referrer"] = d->m_referrer;
2855 KWQ(this)->urlSelected(cURL, button, state, args);
2859 // unknown frame names should open in a new window.
2860 khtml::ChildFrame *frame = recursiveFrameRequest( cURL, args, false );
2863 args.metaData()["referrer"] = d->m_referrer;
2864 requestObject( frame, cURL, args );
2869 if ( !d->m_bComplete && !hasTarget )
2872 if (!d->m_referrer.isEmpty())
2873 args.metaData()["referrer"] = d->m_referrer;
2875 if ( button == MidButton && (state & ShiftButton) )
2877 KParts::WindowArgs winArgs;
2878 winArgs.lowerWindow = true;
2879 KParts::ReadOnlyPart *newPart = 0;
2880 emit d->m_extension->createNewWindow( cURL, args, winArgs, newPart );
2883 emit d->m_extension->openURLRequest( cURL, args );
2884 #endif // APPLE_CHANGES
2889 void KHTMLPart::slotViewDocumentSource()
2892 if (!(url.isLocalFile()) && KHTMLPageCache::self()->isValid(d->m_cacheId))
2894 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2895 if (sourceFile.status() == 0)
2897 KHTMLPageCache::self()->saveData(d->m_cacheId, sourceFile.dataStream());
2899 url.setPath(sourceFile.name());
2903 // emit d->m_extension->openURLRequest( m_url, KParts::URLArgs( false, 0, 0, QString::fromLatin1( "text/plain" ) ) );
2904 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2907 void KHTMLPart::slotViewFrameSource()
2909 KParts::ReadOnlyPart *frame = currentFrame();
2913 KURL url = frame->url();
2914 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
2916 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
2918 if (KHTMLPageCache::self()->isValid(cacheId))
2920 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2921 if (sourceFile.status() == 0)
2923 KHTMLPageCache::self()->saveData(cacheId, sourceFile.dataStream());
2925 url.setPath(sourceFile.name());
2930 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2933 KURL KHTMLPart::backgroundURL() const
2935 // ### what about XML documents? get from CSS?
2936 if (!d->m_doc || !d->m_doc->isHTMLDocument())
2939 QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
2941 return KURL( m_url, relURL );
2944 void KHTMLPart::slotSaveBackground()
2946 KIO::MetaData metaData;
2947 metaData["referrer"] = d->m_referrer;
2948 KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save background image as"), backgroundURL(), metaData );
2951 void KHTMLPart::slotSaveDocument()
2953 KURL srcURL( m_url );
2955 if ( srcURL.fileName(false).isEmpty() )
2956 srcURL.setFileName( "index.html" );
2958 KIO::MetaData metaData;
2960 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files"), d->m_cacheId );
2963 void KHTMLPart::slotSecurity()
2965 // kdDebug( 6050 ) << "Meta Data:" << endl
2966 // << d->m_ssl_peer_cert_subject
2968 // << d->m_ssl_peer_cert_issuer
2970 // << d->m_ssl_cipher
2972 // << d->m_ssl_cipher_desc
2974 // << d->m_ssl_cipher_version
2976 // << d->m_ssl_good_from
2978 // << d->m_ssl_good_until
2980 // << d->m_ssl_cert_state
2983 KSSLInfoDlg *kid = new KSSLInfoDlg(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
2985 if (d->m_bSecurityInQuestion)
2986 kid->setSecurityInQuestion(true);
2988 if (d->m_ssl_in_use) {
2989 KSSLCertificate *x = KSSLCertificate::fromString(d->m_ssl_peer_certificate.local8Bit());
2991 // Set the chain back onto the certificate
2992 QStringList cl = QStringList::split(QString("\n"), d->m_ssl_peer_chain);
2993 QPtrList<KSSLCertificate> ncl;
2995 ncl.setAutoDelete(true);
2996 for (QStringList::Iterator it = cl.begin(); it != cl.end(); ++it) {
2997 KSSLCertificate *y = KSSLCertificate::fromString((*it).local8Bit());
2998 if (y) ncl.append(y);
3001 if (ncl.count() > 0)
3002 x->chain().setChain(ncl);
3008 d->m_ssl_cipher_desc,
3009 d->m_ssl_cipher_version,
3010 d->m_ssl_cipher_used_bits.toInt(),
3011 d->m_ssl_cipher_bits.toInt(),
3012 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt()
3020 void KHTMLPart::slotSaveFrame()
3022 if ( !d->m_activeFrame )
3023 return; // should never be the case, but one never knows :-)
3025 KURL srcURL( static_cast<KParts::ReadOnlyPart *>( d->m_activeFrame )->url() );
3027 if ( srcURL.fileName(false).isEmpty() )
3028 srcURL.setFileName( "index.html" );
3030 KIO::MetaData metaData;
3031 // Referrer unknown?
3032 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files") );
3035 void KHTMLPart::slotSetEncoding()
3037 // first Item is always auto
3038 if(d->m_paSetEncoding->currentItem() == 0)
3039 setEncoding(QString::null, false);
3041 // strip of the language to get the raw encoding again.
3042 QString enc = KGlobal::charsets()->encodingForName(d->m_paSetEncoding->currentText());
3043 setEncoding(enc, true);
3047 void KHTMLPart::slotUseStylesheet()
3049 if (d->m_doc && d->m_paUseStylesheet->currentText() != d->m_sheetUsed) {
3050 d->m_sheetUsed = d->m_paUseStylesheet->currentText();
3051 d->m_doc->updateStyleSelector();
3055 void KHTMLPart::updateActions()
3057 bool frames = false;
3059 QValueList<khtml::ChildFrame>::ConstIterator it = d->m_frames.begin();
3060 QValueList<khtml::ChildFrame>::ConstIterator end = d->m_frames.end();
3061 for (; it != end; ++it )
3062 if ( (*it).m_type == khtml::ChildFrame::Frame )
3068 d->m_paViewFrame->setEnabled( frames );
3069 d->m_paSaveFrame->setEnabled( frames );
3072 d->m_paFind->setText( i18n( "&Find in Frame..." ) );
3074 d->m_paFind->setText( i18n( "&Find..." ) );
3076 KParts::Part *frame = 0;
3079 frame = currentFrame();
3081 bool enableFindAndSelectAll = true;
3084 enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
3086 d->m_paFind->setEnabled( enableFindAndSelectAll );
3087 d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
3089 bool enablePrintFrame = false;
3093 QObject *ext = KParts::BrowserExtension::childObject( frame );
3095 enablePrintFrame = ext->metaObject()->slotNames().contains( "print()" );
3098 d->m_paPrintFrame->setEnabled( enablePrintFrame );
3103 if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
3104 bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
3106 d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
3111 bool KHTMLPart::requestFrame( khtml::RenderPart *frame, const QString &url, const QString &frameName,
3112 const QStringList ¶mNames, const QStringList ¶mValues, bool isIFrame )
3114 // kdDebug( 6050 ) << "childRequest( ..., " << url << ", " << frameName << " )" << endl;
3115 FrameIt it = d->m_frames.find( frameName );
3116 if ( it == d->m_frames.end() )
3118 khtml::ChildFrame child;
3119 // kdDebug( 6050 ) << "inserting new frame into frame map " << frameName << endl;
3120 child.m_name = frameName;
3121 it = d->m_frames.append( child );
3124 (*it).m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
3125 (*it).m_frame = frame;
3126 (*it).m_paramValues = paramNames;
3127 (*it).m_paramNames = paramValues;
3129 // Support for <frame src="javascript:string">
3130 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
3132 if (!processObjectRequest(&(*it), "about:blank", "text/html" ))
3135 KHTMLPart *newPart = static_cast<KHTMLPart *>(&*(*it).m_part);
3136 newPart->replaceContentsWithScriptResult( url );
3141 return requestObject( &(*it), completeURL( url ));
3144 QString KHTMLPart::requestFrameName()
3147 return KWQ(this)->generateFrameName();
3149 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
3153 bool KHTMLPart::requestObject( khtml::RenderPart *frame, const QString &url, const QString &serviceType,
3154 const QStringList ¶mNames, const QStringList ¶mValues )
3156 khtml::ChildFrame child;
3157 QValueList<khtml::ChildFrame>::Iterator it = d->m_objects.append( child );
3158 (*it).m_frame = frame;
3159 (*it).m_type = khtml::ChildFrame::Object;
3160 (*it).m_paramNames = paramNames;
3161 (*it).m_paramValues = paramValues;
3162 (*it).m_hasFallbackContent = frame->hasFallbackContent();
3166 completedURL = completeURL(url);
3168 KParts::URLArgs args;
3169 args.serviceType = serviceType;
3170 return requestObject( &(*it), completedURL, args );
3173 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KURL &url, const KParts::URLArgs &_args )
3176 if (!checkLinkSecurity(url))
3179 if ( child->m_bPreloaded )
3181 // kdDebug(6005) << "KHTMLPart::requestObject preload" << endl;
3182 if ( child->m_frame && child->m_part && child->m_part->widget() )
3183 child->m_frame->setWidget( child->m_part->widget() );
3185 child->m_bPreloaded = false;
3189 KParts::URLArgs args( _args );
3193 child->m_run->abort();
3196 if ( child->m_part && !args.reload && urlcmp( child->m_part->url().url(), url.url(), true, true ) )
3197 args.serviceType = child->m_serviceType;
3199 child->m_args = args;
3200 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3201 child->m_serviceName = QString::null;
3202 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
3203 child->m_args.metaData()["referrer"] = d->m_referrer;
3206 child->m_args.metaData().insert("main_frame_request",
3207 parentPart() == 0 ? "TRUE":"FALSE");
3208 child->m_args.metaData().insert("ssl_was_in_use",
3209 d->m_ssl_in_use ? "TRUE":"FALSE");
3210 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
3213 // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
3214 if ((url.isEmpty() || url.url() == "about:blank") && args.serviceType.isEmpty())
3215 args.serviceType = QString::fromLatin1( "text/html" );
3218 return processObjectRequest( child, url, args.serviceType );
3220 if ( args.serviceType.isEmpty() ) {
3221 child->m_run = new KHTMLRun( this, child, url, child->m_args,
3222 child->m_type != khtml::ChildFrame::Frame );
3225 return processObjectRequest( child, url, args.serviceType );
3230 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KURL &_url, const QString &mimetype )
3232 //kdDebug( 6050 ) << "KHTMLPart::processObjectRequest trying to create part for " << mimetype << endl;
3234 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
3235 // by an emitting frame part (emit openURLRequest( blahurl, ... ) . A few lines below we delete the part
3236 // though -> the reference becomes invalid -> crash is likely
3239 // khtmlrun called us this way to indicate a loading error
3240 if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
3242 checkEmitLoadEvent();
3243 child->m_bCompleted = true;
3247 if (child->m_bNotify)
3249 child->m_bNotify = false;
3250 if ( !child->m_args.lockHistory() )
3251 emit d->m_extension->openURLNotify();
3255 if ( child->m_part )
3257 KHTMLPart *part = static_cast<KHTMLPart *>(&*child->m_part);
3258 if (part && part->inherits("KHTMLPart")) {
3259 KParts::URLArgs args;
3260 if (!d->m_referrer.isEmpty())
3261 args.metaData()["referrer"] = d->m_referrer;
3262 KWQ(part)->openURLRequest(url, args);
3267 KParts::ReadOnlyPart *part = KWQ(this)->createPart(*child, url, mimetype);
3268 KHTMLPart *khtml_part = static_cast<KHTMLPart *>(part);
3269 if (khtml_part && khtml_part->inherits("KHTMLPart"))
3270 khtml_part->childBegin();
3272 if ( !child->m_services.contains( mimetype ) )
3274 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 );
3278 checkEmitLoadEvent();
3283 if ( child->m_part )
3285 disconnectChild(child);
3287 partManager()->removePart( (KParts::ReadOnlyPart *)child->m_part );
3289 child->m_part->deref();
3292 child->m_serviceType = mimetype;
3293 if ( child->m_frame && part->widget() )
3294 child->m_frame->setWidget( part->widget() );
3297 if ( child->m_type != khtml::ChildFrame::Object )
3298 partManager()->addPart( part, false );
3300 // kdDebug(6005) << "AH! NO FRAME!!!!!" << endl;
3303 child->m_part = part;
3304 assert( ((void*) child->m_part) != 0);
3306 connectChild(child);
3311 child->m_extension = KParts::BrowserExtension::childObject( part );
3313 if ( child->m_extension )
3315 connect( child->m_extension, SIGNAL( openURLNotify() ),
3316 d->m_extension, SIGNAL( openURLNotify() ) );
3318 connect( child->m_extension, SIGNAL( openURLRequestDelayed( const KURL &, const KParts::URLArgs & ) ),
3319 this, SLOT( slotChildURLRequest( const KURL &, const KParts::URLArgs & ) ) );
3321 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ),
3322 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ) );
3323 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs &, const KParts::WindowArgs &, KParts::ReadOnlyPart *& ) ),
3324 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & , const KParts::WindowArgs &, KParts::ReadOnlyPart *&) ) );
3326 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ),
3327 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ) );
3328 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ),
3329 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ) );
3330 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ),
3331 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ) );
3332 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ),
3333 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ) );
3335 connect( child->m_extension, SIGNAL( infoMessage( const QString & ) ),
3336 d->m_extension, SIGNAL( infoMessage( const QString & ) ) );
3338 child->m_extension->setBrowserInterface( d->m_extension->browserInterface() );
3343 checkEmitLoadEvent();
3344 // Some JS code in the load event may have destroyed the part
3345 // In that case, abort
3346 if ( !child->m_part )
3349 if ( child->m_bPreloaded )
3351 if ( child->m_frame && child->m_part )
3352 child->m_frame->setWidget( child->m_part->widget() );
3354 child->m_bPreloaded = false;
3358 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3360 // make sure the part has a way to find out about the mimetype.
3361 // we actually set it in child->m_args in requestObject already,
3362 // but it's useless if we had to use a KHTMLRun instance, as the
3363 // point the run object is to find out exactly the mimetype.
3364 child->m_args.serviceType = mimetype;
3366 child->m_bCompleted = false;
3367 if ( child->m_extension )
3368 child->m_extension->setURLArgs( child->m_args );
3371 // In these cases, the synchronous load would have finished
3372 // before we could connect the signals, so make sure to send the
3373 // completed() signal for the child by hand
3374 // FIXME: In this case the KHTMLPart will have finished loading before
3375 // it's being added to the child list. It would be a good idea to
3376 // create the child first, then invoke the loader separately
3377 if (url.isEmpty() || url.url() == "about:blank") {
3378 ReadOnlyPart *readOnlyPart = child->m_part;
3379 KHTMLPart *part = static_cast<KHTMLPart *>(readOnlyPart);
3380 if (part && part->inherits("KHTMLPart")) {
3382 part->checkCompleted();
3386 if(url.protocol() == "javascript" || url.url() == "about:blank") {
3387 if (!child->m_part->inherits("KHTMLPart"))
3390 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(child->m_part));
3393 if (d->m_doc && p->d->m_doc)
3394 p->d->m_doc->setBaseURL(d->m_doc->baseURL());
3395 if (!url.url().startsWith("about:")) {
3396 p->write(url.path());
3403 else if ( !url.isEmpty() )
3405 //kdDebug( 6050 ) << "opening " << url.url() << " in frame " << child->m_part << endl;
3406 return child->m_part->openURL( url );
3415 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget, const char *widgetName,
3416 QObject *parent, const char *name, const QString &mimetype,
3417 QString &serviceName, QStringList &serviceTypes,
3418 const QStringList ¶ms )
3421 if ( !serviceName.isEmpty() )
3422 constr.append( QString::fromLatin1( "Name == '%1'" ).arg( serviceName ) );
3424 KTrader::OfferList offers = KTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr, QString::null );
3426 if ( offers.isEmpty() )
3429 KService::Ptr service = *offers.begin();
3431 KLibFactory *factory = KLibLoader::self()->factory( QFile::encodeName(service->library()) );
3436 KParts::ReadOnlyPart *res = 0L;
3438 const char *className = "KParts::ReadOnlyPart";
3439 if ( service->serviceTypes().contains( "Browser/View" ) )
3440 className = "Browser/View";
3442 if ( factory->inherits( "KParts::Factory" ) )
3443 res = static_cast<KParts::ReadOnlyPart *>(static_cast<KParts::Factory *>( factory )->createPart( parentWidget, widgetName, parent, name, className, params ));
3445 res = static_cast<KParts::ReadOnlyPart *>(factory->create( parentWidget, widgetName, className ));
3450 serviceTypes = service->serviceTypes();
3451 serviceName = service->name();
3456 KParts::PartManager *KHTMLPart::partManager()
3458 if ( !d->m_manager )
3460 d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this, "khtml part manager" );
3461 d->m_manager->setAllowNestedParts( true );
3462 connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
3463 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
3464 connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ),
3465 this, SLOT( slotPartRemoved( KParts::Part * ) ) );
3468 return d->m_manager;
3473 void KHTMLPart::submitFormAgain()
3475 if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
3476 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 );
3478 delete d->m_submitForm;
3479 d->m_submitForm = 0;
3480 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
3483 void KHTMLPart::submitForm( const char *action, const QString &url, const FormData &formData, const QString &_target, const QString& contentType, const QString& boundary )
3485 kdDebug(6000) << this << ": KHTMLPart::submitForm target=" << _target << " url=" << url << endl;
3486 KURL u = completeURL( url );
3490 // ### ERROR HANDLING!
3495 // Form security checks
3498 /* This is separate for a reason. It has to be _before_ all script, etc,
3499 * AND I don't want to break anything that uses checkLinkSecurity() in
3503 // This causes crashes... needs to be fixed.
3504 if (!d->m_submitForm && u.protocol() != "https" && u.protocol() != "mailto") {
3505 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
3506 int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
3507 "\nA third party may be able to intercept and view this information."
3508 "\nAre you sure you wish to continue?"),
3510 if (rc == KMessageBox::Cancel)
3512 } else { // Going from nonSSL -> nonSSL
3513 KSSLSettings kss(true);
3514 if (kss.warnOnUnencrypted()) {
3515 int rc = KMessageBox::warningContinueCancel(NULL,
3516 i18n("Warning: Your data is about to be transmitted across the network unencrypted."
3517 "\nAre you sure you wish to continue?"),
3520 "WarnOnUnencryptedForm");
3521 // Move this setting into KSSL instead
3522 KConfig *config = kapp->config();
3523 QString grpNotifMsgs = QString::fromLatin1("Notification Messages");
3524 KConfigGroupSaver saver( config, grpNotifMsgs );
3526 if (!config->readBoolEntry("WarnOnUnencryptedForm", true)) {
3527 config->deleteEntry("WarnOnUnencryptedForm");
3529 kss.setWarnOnUnencrypted(false);
3532 if (rc == KMessageBox::Cancel)
3538 if (!d->m_submitForm && u.protocol() == "mailto") {
3539 int rc = KMessageBox::warningContinueCancel(NULL,
3540 i18n("This site is attempting to submit form data via email."),
3543 "WarnTriedEmailSubmit");
3545 if (rc == KMessageBox::Cancel) {
3550 // End form security checks
3552 #endif // APPLE_CHANGES
3554 QString urlstring = u.url();
3556 if ( urlstring.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
3557 urlstring = KURL::decode_string(urlstring);
3558 d->m_executingJavaScriptFormAction = true;
3559 executeScript( urlstring.right( urlstring.length() - 11) );
3560 d->m_executingJavaScriptFormAction = false;
3565 if (!checkLinkSecurity(u,
3566 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?" ),
3571 KParts::URLArgs args;
3573 if (!d->m_referrer.isEmpty())
3574 args.metaData()["referrer"] = d->m_referrer;
3577 args.metaData().insert("main_frame_request",
3578 parentPart() == 0 ? "TRUE":"FALSE");
3579 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
3580 args.metaData().insert("ssl_activate_warnings", "TRUE");
3582 args.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
3584 // Handle mailto: forms
3585 if (u.protocol() == "mailto") {
3586 // 1) Check for attach= and strip it
3587 QString q = u.query().mid(1);
3588 QStringList nvps = QStringList::split("&", q);
3589 bool triedToAttach = false;
3591 for (QStringList::Iterator nvp = nvps.begin(); nvp != nvps.end(); ++nvp) {
3592 QStringList pair = QStringList::split("=", *nvp);
3593 if (pair.count() >= 2) {
3594 if (pair.first().lower() == "attach") {
3595 nvp = nvps.remove(nvp);
3596 triedToAttach = true;
3603 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");
3608 if (contentType.lower() == "multipart/form-data") {
3609 // FIXME: is this correct? I suspect not
3610 bodyEnc = KURL::encode_string(formData.flattenToString());
3611 } else if (contentType.lower() == "text/plain") {
3612 // Convention seems to be to decode, and s/&/\n/
3613 QString tmpbody = formData.flattenToString();
3614 tmpbody.replace('&', '\n');
3615 tmpbody.replace('+', ' ');
3616 tmpbody = KURL::decode_string(tmpbody); // Decode the rest of it
3617 bodyEnc = KURL::encode_string(tmpbody); // Recode for the URL
3619 bodyEnc = KURL::encode_string(formData.flattenToString());
3622 nvps.append(QString("body=%1").arg(bodyEnc));
3627 if ( strcmp( action, "get" ) == 0 ) {
3628 if (u.protocol() != "mailto")
3629 u.setQuery( formData.flattenToString() );
3630 args.setDoPost( false );
3634 args.postData = formData;
3636 args.postData = formData.flatten();
3638 args.setDoPost( true );
3640 // construct some user headers if necessary
3641 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
3642 args.setContentType( "Content-Type: application/x-www-form-urlencoded" );
3643 else // contentType must be "multipart/form-data"
3644 args.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
3647 if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
3648 if( d->m_submitForm ) {
3649 kdDebug(6000) << "KHTMLPart::submitForm ABORTING!" << endl;
3652 d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
3653 d->m_submitForm->submitAction = action;
3654 d->m_submitForm->submitUrl = url;
3655 d->m_submitForm->submitFormData = formData;
3656 d->m_submitForm->target = _target;
3657 d->m_submitForm->submitContentType = contentType;
3658 d->m_submitForm->submitBoundary = boundary;
3659 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
3664 KWQ(this)->submitForm( u, args);
3666 emit d->m_extension->openURLRequest( u, args );
3673 void KHTMLPart::popupMenu( const QString &linkUrl )
3677 if ( linkUrl.isEmpty() ) // click on background
3678 popupURL = this->url();
3679 else { // click on link
3680 popupURL = completeURL( linkUrl );
3681 linkKURL = popupURL;
3684 KXMLGUIClient *client = new KHTMLPopupGUIClient( this, d->m_popupMenuXML, linkKURL );
3686 emit d->m_extension->popupMenu( client, QCursor::pos(), popupURL,
3687 QString::fromLatin1( "text/html" ), S_IFREG /*always a file*/ );
3691 emit popupMenu(linkUrl, QCursor::pos());
3696 void KHTMLPart::slotParentCompleted()
3698 if ( d->m_scheduledRedirection != noRedirectionScheduled && !d->m_redirectionTimer.isActive() )
3700 // kdDebug(6050) << this << ": Child redirection -> " << d->m_redirectURL << endl;
3701 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
3705 void KHTMLPart::slotChildStarted( KIO::Job *job )