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) 2003 Apple Computer, Inc.
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
29 #include "khtml_part.h"
32 #define DIRECT_LINKAGE_TO_ECMA
33 #define QT_NO_CLIPBOARD
34 #define QT_NO_DRAGANDDROP
37 #include "khtml_pagecache.h"
39 #include "dom/dom_string.h"
40 #include "dom/dom_element.h"
41 #include "editing/htmlediting.h"
42 #include "html/html_documentimpl.h"
43 #include "html/html_baseimpl.h"
44 #include "html/html_miscimpl.h"
45 #include "html/html_imageimpl.h"
46 #include "rendering/render_text.h"
47 #include "rendering/render_frames.h"
48 #include "misc/htmlhashes.h"
49 #include "misc/loader.h"
50 #include "xml/dom_selection.h"
51 #include "xml/dom2_eventsimpl.h"
52 #include "xml/xml_tokenizer.h"
53 #include "css/cssstyleselector.h"
54 #include "css/csshelper.h"
57 #include "khtmlview.h"
58 #include <kparts/partmanager.h>
59 #include "ecma/kjs_proxy.h"
60 #include "khtml_settings.h"
62 #include <sys/types.h>
66 #include <kstandarddirs.h>
68 #include <kio/global.h>
70 #include <kiconloader.h>
72 #include <kcharsets.h>
73 #include <kmessagebox.h>
74 #include <kstdaction.h>
75 #include <kfiledialog.h>
77 #include <kdatastream.h>
78 #include <ktempfile.h>
79 #include <kglobalsettings.h>
81 #include <kapplication.h>
82 #if !defined(QT_NO_DRAGANDDROP)
83 #include <kmultipledrag.h>
86 #include <ksslcertchain.h>
87 #include <ksslinfodlg.h>
90 #include <qclipboard.h>
92 #include <qmetaobject.h>
93 #include <private/qucomextra_p.h>
95 #include "khtmlpart_p.h"
98 #include <CoreServices/CoreServices.h>
101 using khtml::Decoder;
102 using khtml::DeleteSelectionCommand;
103 using khtml::EditCommand;
104 using khtml::InlineTextBox;
105 using khtml::PasteMarkupCommand;
106 using khtml::RenderObject;
107 using khtml::RenderText;
108 using khtml::Tokenizer;
109 using khtml::TypingCommand;
111 using KParts::BrowserInterface;
113 enum { CARET_BLINK_FREQUENCY = 500 };
116 class PartStyleSheetLoader : public CachedObjectClient
119 PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
122 m_cachedSheet = Cache::requestStyleSheet(dl, url );
124 m_cachedSheet->ref( this );
126 virtual ~PartStyleSheetLoader()
128 if ( m_cachedSheet ) m_cachedSheet->deref(this);
130 virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet)
133 m_part->setUserStyleSheet( sheet.string() );
137 QGuardedPtr<KHTMLPart> m_part;
138 khtml::CachedCSSStyleSheet *m_cachedSheet;
143 FrameList::Iterator FrameList::find( const QString &name )
145 Iterator it = begin();
149 if ( (*it).m_name==name )
155 KHTMLPart::KHTMLPart( QWidget *parentWidget, const char *widgetname, QObject *parent, const char *name,
157 : KParts::ReadOnlyPart( parent, name )
160 KHTMLFactory::registerPart( this );
161 setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
163 init( new KHTMLView( this, parentWidget, widgetname ), prof );
169 KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, const char *name, GUIProfile prof )
170 : KParts::ReadOnlyPart( parent, name )
173 KHTMLFactory::registerPart( this );
174 setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
179 #endif // APPLE_CHANGES
181 void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
183 AtomicString::init();
184 if ( prof == DefaultGUI )
185 setXMLFile( "khtml.rc" );
186 else if ( prof == BrowserViewGUI )
187 setXMLFile( "khtml_browser.rc" );
191 d = new KHTMLPartPrivate(parent());
194 setWidget( d->m_view );
197 d->m_guiProfile = prof;
199 d->m_extension = new KHTMLPartBrowserExtension( this );
200 d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
202 d->m_bSecurityInQuestion = false;
203 d->m_bMousePressed = false;
205 d->m_paLoadImages = 0;
206 d->m_paViewDocument = new KAction( i18n( "View Document Source" ), 0, this, SLOT( slotViewDocumentSource() ), actionCollection(), "viewDocumentSource" );
207 d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), 0, this, SLOT( slotViewFrameSource() ), actionCollection(), "viewFrameSource" );
208 d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), 0, this, SLOT( slotSaveBackground() ), actionCollection(), "saveBackground" );
209 d->m_paSaveDocument = new KAction( i18n( "&Save As..." ), CTRL+Key_S, this, SLOT( slotSaveDocument() ), actionCollection(), "saveDocument" );
211 d->m_paSaveDocument->setShortcut( KShortcut() ); // avoid clashes
212 d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), 0, this, SLOT( slotSaveFrame() ), actionCollection(), "saveFrame" );
213 d->m_paSecurity = new KAction( i18n( "Security..." ), "decrypted", 0, this, SLOT( slotSecurity() ), actionCollection(), "security" );
214 d->m_paDebugRenderTree = new KAction( "print rendering tree to stdout", 0, this, SLOT( slotDebugRenderTree() ), actionCollection(), "debugRenderTree" );
215 d->m_paDebugDOMTree = new KAction( "print DOM tree to stdout", 0, this, SLOT( slotDebugDOMTree() ), actionCollection(), "debugDOMTree" );
217 QString foo1 = i18n("Show Images");
218 QString foo2 = i18n("Show Animated Images");
219 QString foo3 = i18n("Stop Animated Images");
221 d->m_paSetEncoding = new KSelectAction( i18n( "Set &Encoding" ), 0, this, SLOT( slotSetEncoding() ), actionCollection(), "setEncoding" );
222 QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames();
223 encodings.prepend( i18n( "Auto" ) );
224 d->m_paSetEncoding->setItems( encodings );
225 d->m_paSetEncoding->setCurrentItem(0);
227 d->m_paUseStylesheet = new KSelectAction( i18n( "&Use Stylesheet"), 0, this, SLOT( slotUseStylesheet() ), actionCollection(), "useStylesheet" );
229 d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, i18n( "Increase Font Sizes" ), "viewmag+", this, SLOT( slotIncZoom() ), actionCollection(), "incFontSizes" );
230 d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, i18n( "Decrease Font Sizes" ), "viewmag-", this, SLOT( slotDecZoom() ), actionCollection(), "decFontSizes" );
232 d->m_paFind = KStdAction::find( this, SLOT( slotFind() ), actionCollection(), "find" );
234 d->m_paFind->setShortcut( KShortcut() ); // avoid clashes
236 d->m_paPrintFrame = new KAction( i18n( "Print Frame" ), "frameprint", 0, this, SLOT( slotPrintFrame() ), actionCollection(), "printFrame" );
238 d->m_paSelectAll = KStdAction::selectAll( this, SLOT( slotSelectAll() ), actionCollection(), "selectAll" );
240 d->m_paSelectAll->setShortcut( KShortcut() ); // avoid clashes
244 // set the default java(script) flags according to the current host.
245 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled();
246 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
247 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled();
248 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled();
250 // The java, javascript, and plugin settings will be set after the settings
251 // have been initialized.
252 d->m_bJScriptEnabled = true;
253 d->m_bJScriptDebugEnabled = true;
254 d->m_bJavaEnabled = true;
255 d->m_bPluginsEnabled = true;
259 connect( this, SIGNAL( completed() ),
260 this, SLOT( updateActions() ) );
261 connect( this, SIGNAL( completed( bool ) ),
262 this, SLOT( updateActions() ) );
263 connect( this, SIGNAL( started( KIO::Job * ) ),
264 this, SLOT( updateActions() ) );
266 d->m_popupMenuXML = KXMLGUIFactory::readConfigFile( locate( "data", "khtml/khtml_popupmenu.rc", KHTMLFactory::instance() ) );
269 connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
270 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
271 connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
272 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
273 connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
274 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
276 findTextBegin(); //reset find variables
278 connect( &d->m_redirectionTimer, SIGNAL( timeout() ),
279 this, SLOT( slotRedirect() ) );
282 d->m_dcopobject = new KHTMLPartIface(this);
286 KHTMLPart::~KHTMLPart()
288 //kdDebug(6050) << "KHTMLPart::~KHTMLPart " << this << endl;
290 if ( d->m_findDialog )
291 disconnect( d->m_findDialog, SIGNAL( destroyed() ),
292 this, SLOT( slotFindDialogDestroyed() ) );
296 d->m_manager->setActivePart( 0 );
297 // Shouldn't we delete d->m_manager here ? (David)
298 // No need to, I would say. We specify "this" as parent qobject
299 // in ::partManager() (Simon)
309 disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
310 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
311 disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
312 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
313 disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
314 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
321 d->m_view->viewport()->hide();
322 d->m_view->m_part = 0;
326 delete d->m_hostExtension;
330 KHTMLFactory::deregisterPart( this );
333 bool KHTMLPart::restoreURL( const KURL &url )
335 kdDebug( 6050 ) << "KHTMLPart::restoreURL " << url.url() << endl;
340 * That's not a good idea as it will call closeURL() on all
341 * child frames, preventing them from further loading. This
342 * method gets called from restoreState() in case of a full frameset
343 * restoral, and restoreState() calls closeURL() before restoring
345 kdDebug( 6050 ) << "closing old URL" << endl;
349 d->m_bComplete = false;
350 d->m_bLoadEventEmitted = false;
351 d->m_workingURL = url;
353 // set the java(script) flags according to the current host.
355 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
356 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
357 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
358 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
360 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
361 d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled();
362 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
363 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
368 KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &)));
377 bool KHTMLPart::didOpenURL(const KURL &url)
379 bool KHTMLPart::openURL( const KURL &url )
382 kdDebug( 6050 ) << "KHTMLPart(" << this << ")::openURL " << url.url() << endl;
384 if (d->m_scheduledRedirection == redirectionDuringLoad){
385 // We're about to get a redirect that happened before the document was
386 // created. This can happen when one frame may change the location of a
393 // clear last edit command
394 d->m_lastEditCommand = EditCommand();
396 KWQ(this)->clearUndoRedoOperations();
400 // check to see if this is an "error://" URL. This is caused when an error
401 // occurs before this part was loaded (e.g. KonqRun), and is passed to
402 // khtmlpart so that it can display the error.
403 if ( url.protocol() == "error" && url.hasSubURL() ) {
406 * The format of the error url is that two variables are passed in the query:
407 * error = int kio error code, errText = QString error text from kio
408 * and the URL where the error happened is passed as a sub URL.
410 KURL::List urls = KURL::split( url );
411 //kdDebug() << "Handling error URL. URL count:" << urls.count() << endl;
413 if ( urls.count() > 1 ) {
414 KURL mainURL = urls.first();
415 int error = mainURL.queryItem( "error" ).toInt();
416 // error=0 isn't a valid error code, so 0 means it's missing from the URL
417 if ( error == 0 ) error = KIO::ERR_UNKNOWN;
418 QString errorText = mainURL.queryItem( "errText" );
420 d->m_workingURL = KURL::join( urls );
421 //kdDebug() << "Emitting fixed URL " << d->m_workingURL.prettyURL() << endl;
422 emit d->m_extension->setLocationBarURL( d->m_workingURL.prettyURL() );
423 htmlError( error, errorText, d->m_workingURL );
427 #endif // APPLE_CHANGES
429 KParts::URLArgs args( d->m_extension->urlArgs() );
432 // in case we have a) no frameset (don't test m_frames.count(), iframes get in there)
433 // b) the url is identical with the currently
434 // displayed one (except for the htmlref!) , c) the url request is not a POST
435 // operation and d) the caller did not request to reload the page we try to
436 // be smart and instead of reloading the whole document we just jump to the
437 // request html anchor
439 bool isFrameSet = false;
440 if ( d->m_doc->isHTMLDocument() ) {
441 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
442 isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET);
445 urlcmp( url.url(), m_url.url(), true, true ) &&
446 url.hasRef() && !args.doPost() && !args.reload )
448 kdDebug( 6050 ) << "KHTMLPart::openURL, jumping to anchor. m_url = " << url.url() << endl;
452 if ( !gotoAnchor( url.encodedHtmlRef()) )
453 gotoAnchor( url.htmlRef() );
455 d->m_bComplete = true;
456 d->m_doc->setParsing(false);
458 kdDebug( 6050 ) << "completed..." << endl;
463 #endif // APPLE_CHANGES
467 kdDebug( 6050 ) << "closing old URL" << endl;
472 args.metaData().insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" );
473 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" );
474 args.metaData().insert("ssl_activate_warnings", "TRUE" );
478 d->m_cachePolicy = KIO::CC_Cache;
479 else if (args.reload)
480 d->m_cachePolicy = KIO::CC_Refresh;
482 d->m_cachePolicy = KIO::CC_Verify;
484 if ( args.doPost() && (url.protocol().startsWith("http")) )
486 d->m_job = KIO::http_post( url, args.postData, false );
487 d->m_job->addMetaData("content-type", args.contentType() );
491 d->m_job = KIO::get( url, false, false );
492 d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
495 d->m_job->addMetaData(args.metaData());
497 connect( d->m_job, SIGNAL( result( KIO::Job * ) ),
498 SLOT( slotFinished( KIO::Job * ) ) );
500 connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray &)),
501 SLOT( slotData( KIO::Job*, const QByteArray &)));
504 connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KURL&) ),
505 SLOT( slotRedirection(KIO::Job*,const KURL&) ) );
507 d->m_bComplete = false;
508 d->m_bLoadEventEmitted = false;
510 // delete old status bar msg's from kjs (if it _was_ activated on last URL)
511 if( d->m_bJScriptEnabled )
513 d->m_kjsStatusBarText = QString::null;
514 d->m_kjsDefaultStatusBarText = QString::null;
517 // set the javascript flags according to the current url
519 d->m_bJScriptDebugEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled();
520 d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
521 d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
523 d->m_bJScriptDebugEnabled = d->m_settings->isJavaScriptDebugEnabled();
524 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
525 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
528 // 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
529 // data arrives) (Simon)
531 if(m_url.protocol().startsWith( "http" ) && !m_url.host().isEmpty() &&
532 m_url.path().isEmpty()) {
534 emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
536 // copy to m_workingURL after fixing m_url above
537 d->m_workingURL = m_url;
539 kdDebug( 6050 ) << "KHTMLPart::openURL now (before started) m_url = " << m_url.url() << endl;
541 connect( d->m_job, SIGNAL( speed( KIO::Job*, unsigned long ) ),
542 this, SLOT( slotJobSpeed( KIO::Job*, unsigned long ) ) );
544 connect( d->m_job, SIGNAL( percent( KIO::Job*, unsigned long ) ),
545 this, SLOT( slotJobPercent( KIO::Job*, unsigned long ) ) );
552 bool KHTMLPart::closeURL()
556 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
561 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
562 HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
564 if ( hdoc->body() && d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted ) {
565 hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false );
567 d->m_doc->updateRendering();
568 d->m_bUnloadEventEmitted = true;
572 d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
573 d->m_bLoadEventEmitted = true; // don't want that one either
574 d->m_cachePolicy = KIO::CC_Verify; // Why here?
576 KHTMLPageCache::self()->cancelFetch(this);
577 if ( d->m_doc && d->m_doc->parsing() )
579 kdDebug( 6050 ) << " was still parsing... calling end " << endl;
580 slotFinishedParsing();
581 d->m_doc->setParsing(false);
584 if ( !d->m_workingURL.isEmpty() )
586 // Aborted before starting to render
587 kdDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << m_url.prettyURL() << endl;
588 emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
591 d->m_workingURL = KURL();
593 if ( d->m_doc && d->m_doc->docLoader() )
594 khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() );
596 // tell all subframes to stop as well
597 ConstFrameIt it = d->m_frames.begin();
598 ConstFrameIt end = d->m_frames.end();
599 for (; it != end; ++it )
600 if ( !( *it ).m_part.isNull() )
601 ( *it ).m_part->closeURL();
603 d->m_bPendingChildRedirection = false;
605 // Stop any started redirections as well!! (DA)
608 // null node activated.
609 emit nodeActivated(Node());
614 DOM::HTMLDocument KHTMLPart::htmlDocument() const
616 if (d->m_doc && d->m_doc->isHTMLDocument())
617 return static_cast<HTMLDocumentImpl*>(d->m_doc);
619 return static_cast<HTMLDocumentImpl*>(0);
622 DOM::Document KHTMLPart::document() const
628 KParts::BrowserExtension *KHTMLPart::browserExtension() const
630 return d->m_extension;
633 KHTMLView *KHTMLPart::view() const
638 void KHTMLPart::setJScriptEnabled( bool enable )
640 if ( !enable && jScriptEnabled() && d->m_jscript ) {
641 d->m_jscript->clear();
643 d->m_bJScriptForce = enable;
644 d->m_bJScriptOverride = true;
647 bool KHTMLPart::jScriptEnabled() const
649 if ( d->m_bJScriptOverride )
650 return d->m_bJScriptForce;
651 return d->m_bJScriptEnabled;
654 void KHTMLPart::setMetaRefreshEnabled( bool enable )
656 d->m_metaRefreshEnabled = enable;
659 bool KHTMLPart::metaRefreshEnabled() const
661 return d->m_metaRefreshEnabled;
664 // Define this to disable dlopening kjs_html, when directly linking to it.
665 // You need to edit khtml/Makefile.am to add ./ecma/libkjs_html.la to LIBADD
666 // and to edit khtml/ecma/Makefile.am to s/kjs_html/libkjs_html/, remove libkhtml from LIBADD,
667 // remove LDFLAGS line, and replace kde_module with either lib (shared) or noinst (static)
668 //#define DIRECT_LINKAGE_TO_ECMA
670 #ifdef DIRECT_LINKAGE_TO_ECMA
671 extern "C" { KJSProxy *kjs_html_init(KHTMLPart *khtmlpart); }
674 KJSProxy *KHTMLPart::jScript()
676 if (!jScriptEnabled()){
682 #ifndef DIRECT_LINKAGE_TO_ECMA
683 KLibrary *lib = KLibLoader::self()->library("kjs_html");
685 setJScriptEnabled( false );
688 // look for plain C init function
689 void *sym = lib->symbol("kjs_html_init");
692 setJScriptEnabled( false );
695 typedef KJSProxy* (*initFunction)(KHTMLPart *);
696 initFunction initSym = (initFunction) sym;
697 d->m_jscript = (*initSym)(this);
700 d->m_jscript = kjs_html_init(this);
701 // d->m_kjs_lib remains 0L.
703 if (d->m_bJScriptDebugEnabled)
704 d->m_jscript->setDebugEnabled(true);
710 void KHTMLPart::replaceContentsWithScriptResult( const KURL &url )
712 QString script = KURL::decode_string(url.url().mid(strlen("javascript:")));
713 QVariant ret = executeScript(script);
715 if (ret.type() == QVariant::String) {
717 write(ret.asString());
722 QVariant KHTMLPart::executeScript( const QString &script, bool forceUserGesture )
724 return executeScript( DOM::Node(), script, forceUserGesture );
727 //Enable this to see all JS scripts being executed
728 //#define KJS_VERBOSE
730 QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script, bool forceUserGesture )
733 kdDebug(6070) << "KHTMLPart::executeScript n=" << n.nodeName().string().latin1() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " << script << endl;
735 KJSProxy *proxy = jScript();
737 if (!proxy || proxy->paused())
739 d->m_runningScripts++;
740 // If forceUserGesture is true, then make the script interpreter
741 // treat it as if triggered by a user gesture even if there is no
742 // current DOM event being processed.
743 QVariant ret = proxy->evaluate( forceUserGesture ? QString::null : m_url.url(), 0, script, n );
744 d->m_runningScripts--;
745 if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
747 DocumentImpl::updateDocumentsRendering();
750 kdDebug(6070) << "KHTMLPart::executeScript - done" << endl;
755 bool KHTMLPart::scheduleScript(const DOM::Node &n, const QString& script)
757 //kdDebug(6050) << "KHTMLPart::scheduleScript "<< script << endl;
759 d->scheduledScript = script;
760 d->scheduledScriptNode = n;
765 QVariant KHTMLPart::executeScheduledScript()
767 if( d->scheduledScript.isEmpty() )
770 //kdDebug(6050) << "executing delayed " << d->scheduledScript << endl;
772 QVariant ret = executeScript( d->scheduledScriptNode, d->scheduledScript );
773 d->scheduledScript = QString();
774 d->scheduledScriptNode = DOM::Node();
779 void KHTMLPart::setJavaEnabled( bool enable )
781 d->m_bJavaForce = enable;
782 d->m_bJavaOverride = true;
785 bool KHTMLPart::javaEnabled() const
788 if( d->m_bJavaOverride )
789 return d->m_bJavaForce;
790 return d->m_bJavaEnabled;
796 KJavaAppletContext *KHTMLPart::javaContext()
799 return d->m_javaContext;
805 KJavaAppletContext *KHTMLPart::createJavaContext()
808 if ( !d->m_javaContext ) {
810 d->m_javaContext = new KJavaAppletContext(d->m_dcopobject, this);
812 d->m_javaContext = new KJavaAppletContext(d->m_dcopobject);
813 connect( d->m_javaContext, SIGNAL(showStatus(const QString&)),
814 this, SIGNAL(setStatusBarText(const QString&)) );
815 connect( d->m_javaContext, SIGNAL(showDocument(const QString&, const QString&)),
816 this, SLOT(slotShowDocument(const QString&, const QString&)) );
820 return d->m_javaContext;
826 void KHTMLPart::setPluginsEnabled( bool enable )
828 d->m_bPluginsForce = enable;
829 d->m_bPluginsOverride = true;
832 bool KHTMLPart::pluginsEnabled() const
834 if ( d->m_bPluginsOverride )
835 return d->m_bPluginsForce;
836 return d->m_bPluginsEnabled;
841 void KHTMLPart::slotShowDocument( const QString &url, const QString &target )
843 // this is mostly copied from KHTMLPart::slotChildURLRequest. The better approach
844 // would be to put those functions into a single one.
845 khtml::ChildFrame *child = 0;
846 KParts::URLArgs args;
847 args.frameName = target;
849 QString frameName = args.frameName.lower();
850 if ( !frameName.isEmpty() )
852 if ( frameName == QString::fromLatin1( "_top" ) )
854 emit d->m_extension->openURLRequest( url, args );
857 else if ( frameName == QString::fromLatin1( "_blank" ) )
859 emit d->m_extension->createNewWindow( url, args );
862 else if ( frameName == QString::fromLatin1( "_parent" ) )
864 KParts::URLArgs newArgs( args );
865 newArgs.frameName = QString::null;
867 emit d->m_extension->openURLRequest( url, newArgs );
870 else if ( frameName != QString::fromLatin1( "_self" ) )
872 khtml::ChildFrame *_frame = recursiveFrameRequest( url, args );
876 emit d->m_extension->openURLRequest( url, args );
884 // TODO: handle child target correctly! currently the script are always executed fur the parent
885 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
886 executeScript( KURL::decode_string( url.right( url.length() - 11) ) );
891 requestObject( child, KURL(url), args );
892 } else if ( frameName==QString::fromLatin1("_self") ) // this is for embedded objects (via <object>) which want to replace the current document
894 KParts::URLArgs newArgs( args );
895 newArgs.frameName = QString::null;
896 emit d->m_extension->openURLRequest( KURL(url), newArgs );
900 #endif // APPLE_CHANGES
902 void KHTMLPart::slotDebugDOMTree()
904 if ( d->m_doc && d->m_doc->firstChild() )
905 qDebug("%s", d->m_doc->firstChild()->toHTML().latin1());
908 void KHTMLPart::slotDebugRenderTree()
912 d->m_doc->renderer()->printTree();
916 void KHTMLPart::setAutoloadImages( bool enable )
918 if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
922 d->m_doc->docLoader()->setAutoloadImages( enable );
925 unplugActionList( "loadImages" );
928 delete d->m_paLoadImages;
929 d->m_paLoadImages = 0;
931 else if ( !d->m_paLoadImages )
932 d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), "images_display", 0, this, SLOT( slotLoadImages() ), actionCollection(), "loadImages" );
934 if ( d->m_paLoadImages ) {
935 QPtrList<KAction> lst;
936 lst.append( d->m_paLoadImages );
937 plugActionList( "loadImages", lst );
942 bool KHTMLPart::autoloadImages() const
945 return d->m_doc->docLoader()->autoloadImages();
950 void KHTMLPart::clear()
954 d->m_bCleared = true;
956 d->m_bClearing = true;
960 ConstFrameIt it = d->m_frames.begin();
961 ConstFrameIt end = d->m_frames.end();
962 for(; it != end; ++it )
964 // Stop HTMLRun jobs for frames
966 (*it).m_run->abort();
971 QValueList<khtml::ChildFrame>::ConstIterator it = d->m_objects.begin();
972 QValueList<khtml::ChildFrame>::ConstIterator end = d->m_objects.end();
973 for(; it != end; ++it )
975 // Stop HTMLRun jobs for objects
977 (*it).m_run->abort();
983 findTextBegin(); // resets d->m_findNode and d->m_findPos
985 d->m_mousePressNode = DOM::Node();
991 // Moving past doc so that onUnload works.
993 d->m_jscript->clear();
998 // do not dereference the document before the jscript and view are cleared, as some destructors
999 // might still try to access the document.
1005 d->m_decoder->deref();
1009 ConstFrameIt it = d->m_frames.begin();
1010 ConstFrameIt end = d->m_frames.end();
1011 for(; it != end; ++it )
1016 partManager()->removePart( (*it).m_part );
1018 (*it).m_part->deref();
1022 d->m_frames.clear();
1025 ConstFrameIt it = d->m_objects.begin();
1026 ConstFrameIt end = d->m_objects.end();
1027 for(; it != end; ++it )
1032 partManager()->removePart( (*it).m_part );
1034 (*it).m_part->deref();
1038 d->m_objects.clear();
1041 delete d->m_javaContext;
1042 d->m_javaContext = 0;
1045 d->m_scheduledRedirection = noRedirectionScheduled;
1046 d->m_delayRedirect = 0;
1047 d->m_redirectURL = QString::null;
1048 d->m_redirectLockHistory = true;
1049 d->m_redirectUserGesture = false;
1050 d->m_bHTTPRefresh = false;
1051 d->m_bClearing = false;
1052 d->m_frameNameId = 1;
1053 d->m_bFirstData = true;
1055 d->m_bMousePressed = false;
1057 #ifndef QT_NO_CLIPBOARD
1058 connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
1061 d->m_totalObjectCount = 0;
1062 d->m_loadedObjects = 0;
1063 d->m_jobPercent = 0;
1065 if ( !d->m_haveEncoding )
1066 d->m_encoding = QString::null;
1068 d->m_parsetime.restart();
1072 bool KHTMLPart::openFile()
1077 DOM::HTMLDocumentImpl *KHTMLPart::docImpl() const
1079 if ( d && d->m_doc && d->m_doc->isHTMLDocument() )
1080 return static_cast<HTMLDocumentImpl*>(d->m_doc);
1084 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
1091 /*bool KHTMLPart::isSSLInUse() const
1093 return d->m_ssl_in_use;
1096 void KHTMLPart::receivedFirstData()
1098 // Leave indented one extra for easier merging.
1100 //kdDebug( 6050 ) << "begin!" << endl;
1102 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1105 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
1106 d->m_workingURL = KURL();
1108 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
1110 // When the first data arrives, the metadata has just been made available
1114 d->m_bSecurityInQuestion = false;
1115 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
1116 kdDebug(6050) << "SSL in use? " << d->m_job->queryMetaData("ssl_in_use") << endl;
1119 KHTMLPart *p = parentPart();
1120 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
1121 while (p->parentPart()) p = p->parentPart();
1123 p->d->m_paSecurity->setIcon( "halfencrypted" );
1124 p->d->m_bSecurityInQuestion = true;
1125 kdDebug(6050) << "parent setIcon half done." << endl;
1129 d->m_paSecurity->setIcon( d->m_ssl_in_use ? "encrypted" : "decrypted" );
1130 kdDebug(6050) << "setIcon " << ( d->m_ssl_in_use ? "encrypted" : "decrypted" ) << " done." << endl;
1132 // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
1134 d->m_ssl_peer_certificate = d->m_job->queryMetaData("ssl_peer_certificate");
1135 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
1136 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
1137 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
1138 d->m_ssl_cipher_desc = d->m_job->queryMetaData("ssl_cipher_desc");
1139 d->m_ssl_cipher_version = d->m_job->queryMetaData("ssl_cipher_version");
1140 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
1141 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
1142 d->m_ssl_cert_state = d->m_job->queryMetaData("ssl_cert_state");
1144 // Check for charset meta-data
1145 QString qData = d->m_job->queryMetaData("charset");
1146 if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
1147 d->m_encoding = qData;
1148 #endif // APPLE_CHANGES
1150 // Support for http-refresh
1151 qData = d->m_job->queryMetaData("http-refresh");
1152 if( !qData.isEmpty() && d->m_metaRefreshEnabled )
1154 kdDebug(6050) << "HTTP Refresh Request: " << qData << endl;
1156 int pos = qData.find( ';' );
1158 pos = qData.find( ',' );
1162 delay = qData.stripWhiteSpace().toDouble();
1164 // We want a new history item if the refresh timeout > 1 second
1165 scheduleRedirection( delay, m_url.url(), delay <= 1);
1167 scheduleRedirection( delay, m_url.url());
1172 int end_pos = qData.length();
1173 delay = qData.left(pos).stripWhiteSpace().toDouble();
1174 while ( qData[++pos] == ' ' );
1175 if ( qData.find( "url", pos, false ) == pos )
1178 while (qData[pos] == ' ' || qData[pos] == '=' )
1180 if ( qData[pos] == '"' )
1183 int index = end_pos-1;
1184 while( index > pos )
1186 if ( qData[index] == '"' )
1195 // We want a new history item if the refresh timeout > 1 second
1196 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ), delay <= 1);
1198 scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ));
1201 d->m_bHTTPRefresh = true;
1204 // Support for http last-modified
1205 d->m_lastModified = d->m_job->queryMetaData("modified");
1206 //kdDebug() << "KHTMLPart::slotData metadata modified: " << d->m_lastModified << endl;
1211 void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
1213 assert ( d->m_job == kio_job );
1215 //kdDebug( 6050 ) << "slotData: " << data.size() << endl;
1217 if ( !d->m_workingURL.isEmpty() )
1218 receivedFirstData( );
1220 KHTMLPageCache::self()->addData(d->m_cacheId, data);
1221 write( data.data(), data.size() );
1224 void KHTMLPart::slotRestoreData(const QByteArray &data )
1227 if ( !d->m_workingURL.isEmpty() )
1229 long saveCacheId = d->m_cacheId;
1230 begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
1231 d->m_cacheId = saveCacheId;
1232 d->m_workingURL = KURL();
1235 //kdDebug( 6050 ) << "slotRestoreData: " << data.size() << endl;
1236 write( data.data(), data.size() );
1238 if (data.size() == 0)
1240 //kdDebug( 6050 ) << "slotRestoreData: <<end of data>>" << endl;
1242 if (d->m_doc && d->m_doc->parsing())
1243 end(); //will emit completed()
1247 void KHTMLPart::showError( KIO::Job* job )
1249 kdDebug() << "KHTMLPart::showError d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
1250 << " d->m_bCleared=" << d->m_bCleared << endl;
1252 if (job->error() == KIO::ERR_NO_CONTENT)
1255 if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
1256 job->showErrorDialog( /*d->m_view*/ );
1259 htmlError( job->error(), job->errorText(), d->m_workingURL );
1263 // This is a protected method, placed here because of it's relevance to showError
1264 void KHTMLPart::htmlError( int errorCode, const QString& text, const KURL& reqUrl )
1266 kdDebug(6050) << "KHTMLPart::htmlError errorCode=" << errorCode << " text=" << text << endl;
1267 // make sure we're not executing any embedded JS
1268 bool bJSFO = d->m_bJScriptForce;
1269 bool bJSOO = d->m_bJScriptOverride;
1270 d->m_bJScriptForce = false;
1271 d->m_bJScriptOverride = true;
1273 QString errText = QString::fromLatin1( "<HTML><HEAD><TITLE>" );
1274 errText += i18n( "Error while loading %1" ).arg( reqUrl.htmlURL() );
1275 errText += QString::fromLatin1( "</TITLE></HEAD><BODY><P>" );
1276 errText += i18n( "An error occured while loading <B>%1</B>:" ).arg( reqUrl.htmlURL() );
1277 errText += QString::fromLatin1( "</P><P>" );
1278 QString kioErrString = KIO::buildErrorString( errorCode, text );
1280 kioErrString.replace(QRegExp("&"), QString("&"));
1281 kioErrString.replace(QRegExp("<"), QString("<"));
1282 kioErrString.replace(QRegExp(">"), QString(">"));
1284 // In case the error string has '\n' in it, replace with <BR/>
1285 kioErrString.replace( QRegExp("\n"), "<BR/>" );
1287 errText += kioErrString;
1288 errText += QString::fromLatin1( "</P></BODY></HTML>" );
1292 d->m_bJScriptForce = bJSFO;
1293 d->m_bJScriptOverride = bJSOO;
1295 // make the working url the current url, so that reload works and
1296 // emit the progress signals to advance one step in the history
1297 // (so that 'back' works)
1298 m_url = reqUrl; // same as d->m_workingURL
1299 d->m_workingURL = KURL();
1303 // following disabled until 3.1
1305 QString errorName, techName, description;
1306 QStringList causes, solutions;
1308 QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
1309 QDataStream stream(raw, IO_ReadOnly);
1311 stream >> errorName >> techName >> description >> causes >> solutions;
1313 QString url, protocol, datetime;
1314 url = reqUrl.prettyURL();
1315 protocol = reqUrl.protocol();
1316 datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
1319 QString doc = QString::fromLatin1( "<html><head><title>" );
1320 doc += i18n( "Error: " );
1322 doc += QString::fromLatin1( " - %1</title></head><body><h1>" ).arg( url );
1323 doc += i18n( "The requested operation could not be completed" );
1324 doc += QString::fromLatin1( "</h1><h2>" );
1326 doc += QString::fromLatin1( "</h2>" );
1327 if ( techName != QString::null ) {
1328 doc += QString::fromLatin1( "<h2>" );
1329 doc += i18n( "Technical Reason: " );
1331 doc += QString::fromLatin1( "</h2>" );
1333 doc += QString::fromLatin1( "<h3>" );
1334 doc += i18n( "Details of the Request:" );
1335 doc += QString::fromLatin1( "</h3><ul><li>" );
1336 doc += i18n( "URL: %1" ).arg( url );
1337 doc += QString::fromLatin1( "</li><li>" );
1338 if ( protocol != QString::null ) {
1339 // uncomment for 3.1... i18n change
1340 // doc += i18n( "Protocol: %1" ).arg( protocol ).arg( protocol );
1341 doc += QString::fromLatin1( "</li><li>" );
1343 doc += i18n( "Date and Time: %1" ).arg( datetime );
1344 doc += QString::fromLatin1( "</li><li>" );
1345 doc += i18n( "Additional Information: %1" ).arg( text );
1346 doc += QString::fromLatin1( "</li></ul><h3>" );
1347 doc += i18n( "Description:" );
1348 doc += QString::fromLatin1( "</h3><p>" );
1350 doc += QString::fromLatin1( "</p>" );
1351 if ( causes.count() ) {
1352 doc += QString::fromLatin1( "<h3>" );
1353 doc += i18n( "Possible Causes:" );
1354 doc += QString::fromLatin1( "</h3><ul><li>" );
1355 doc += causes.join( "</li><li>" );
1356 doc += QString::fromLatin1( "</li></ul>" );
1358 if ( solutions.count() ) {
1359 doc += QString::fromLatin1( "<h3>" );
1360 doc += i18n( "Possible Solutions:" );
1361 doc += QString::fromLatin1( "</h3><ul><li>" );
1362 doc += solutions.join( "</li><li>" );
1363 doc += QString::fromLatin1( "</li></ul>" );
1365 doc += QString::fromLatin1( "</body></html>" );
1373 void KHTMLPart::slotFinished( KIO::Job * job )
1377 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
1380 emit canceled( job->errorString() );
1382 // TODO: what else ?
1389 //kdDebug( 6050 ) << "slotFinished" << endl;
1391 KHTMLPageCache::self()->endData(d->m_cacheId);
1393 if ( d->m_doc && d->m_doc->docLoader()->expireDate() && m_url.protocol().lower().startsWith("http"))
1394 KIO::http_update_cache(m_url, false, d->m_doc->docLoader()->expireDate());
1396 d->m_workingURL = KURL();
1399 if (d->m_doc->parsing())
1400 end(); //will emit completed()
1403 void KHTMLPart::begin( const KURL &url, int xOffset, int yOffset )
1406 // If we aren't loading an actual URL, then we need to make sure
1407 // that we have at least an empty document. createEmptyDocument will
1408 // do that if we don't have a document already.
1409 if (d->m_workingURL.isEmpty()) {
1410 KWQ(this)->createEmptyDocument();
1416 // Only do this after clearing the part, so that JavaScript can
1417 // clean up properly if it was on for the last load.
1419 d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
1421 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
1424 d->m_bCleared = false;
1426 d->m_bComplete = false;
1427 d->m_bLoadEventEmitted = false;
1431 KHTMLFactory::vLinks()->insert( KWQ(this)->requestedURLString() );
1433 QString urlString = url.url();
1434 KHTMLFactory::vLinks()->insert( urlString );
1435 QString urlString2 = url.prettyURL();
1436 if ( urlString != urlString2 ) {
1437 KHTMLFactory::vLinks()->insert( urlString2 );
1445 KParts::URLArgs args( d->m_extension->urlArgs() );
1446 args.xOffset = xOffset;
1447 args.yOffset = yOffset;
1448 d->m_extension->setURLArgs( args );
1451 ref.setUser(QSTRING_NULL);
1452 ref.setPass(QSTRING_NULL);
1453 ref.setRef(QSTRING_NULL);
1454 d->m_referrer = ref.protocol().startsWith("http") ? ref.url() : "";
1459 // We don't need KDE chained URI handling or window caption setting
1460 if ( !m_url.isEmpty() )
1465 if ( !m_url.isEmpty() )
1467 KURL::List lst = KURL::split( m_url );
1468 if ( !lst.isEmpty() )
1469 baseurl = *lst.begin();
1471 KURL title( baseurl );
1472 title.setRef( QString::null );
1473 title.setQuery( QString::null );
1474 emit setWindowCaption( title.url() );
1477 emit setWindowCaption( i18n( "no title", "* Unknown *" ) );
1480 // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl
1481 if (args.serviceType == "text/xml" || args.serviceType == "application/xml" || args.serviceType == "application/xhtml+xml")
1482 d->m_doc = DOMImplementationImpl::instance()->createDocument( d->m_view );
1484 d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
1487 if (!d->m_doc->attached())
1488 d->m_doc->attach( );
1489 d->m_doc->setURL( m_url.url() );
1490 // We prefer m_baseURL over m_url because m_url changes when we are
1491 // about to load a new page.
1492 d->m_doc->setBaseURL( baseurl.url() );
1495 d->m_doc->setDecoder(d->m_decoder);
1498 d->m_doc->docLoader()->setShowAnimations( KHTMLFactory::defaultHTMLSettings()->showAnimations() );
1500 d->m_doc->docLoader()->setShowAnimations( d->m_settings->showAnimations() );
1504 KWQ(this)->updatePolicyBaseURL();
1508 d->m_paUseStylesheet->setItems(QStringList());
1509 d->m_paUseStylesheet->setEnabled( false );
1513 setAutoloadImages( KHTMLFactory::defaultHTMLSettings()->autoLoadImages() );
1514 QString userStyleSheet = KHTMLFactory::defaultHTMLSettings()->userStyleSheet();
1516 setAutoloadImages( d->m_settings->autoLoadImages() );
1517 QString userStyleSheet = d->m_settings->userStyleSheet();
1520 if ( !userStyleSheet.isEmpty() )
1521 setUserStyleSheet( KURL( userStyleSheet ) );
1524 KWQ(this)->restoreDocumentState();
1526 d->m_doc->setRestoreState(args.docState);
1532 d->m_view->resizeContents( 0, 0 );
1533 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
1536 emit d->m_extension->enableAction( "print", true );
1539 d->m_doc->setParsing(true);
1542 void KHTMLPart::write( const char *str, int len )
1544 if ( !d->m_decoder ) {
1545 d->m_decoder = new Decoder;
1546 if (!d->m_encoding.isNull())
1547 d->m_decoder->setEncoding(d->m_encoding.latin1(),
1548 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
1550 // Inherit the default encoding from the parent frame if there is one.
1551 const char *defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
1552 ? parentPart()->d->m_decoder->encoding() : settings()->encoding().latin1();
1553 d->m_decoder->setEncoding(defaultEncoding, Decoder::DefaultEncoding);
1557 d->m_doc->setDecoder(d->m_decoder);
1564 len = strlen( str );
1566 QString decoded = d->m_decoder->decode( str, len );
1568 if(decoded.isEmpty()) return;
1570 if(d->m_bFirstData) {
1571 // determine the parse mode
1572 d->m_doc->determineParseMode( decoded );
1573 d->m_bFirstData = false;
1575 //kdDebug(6050) << "KHTMLPart::write haveEnc = " << d->m_haveEncoding << endl;
1576 // ### this is still quite hacky, but should work a lot better than the old solution
1577 if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
1578 d->m_doc->recalcStyle( NodeImpl::Force );
1582 jScript()->appendSourceFile(m_url.url(),decoded);
1583 Tokenizer* t = d->m_doc->tokenizer();
1585 // parsing some of the page can result in running a script which
1586 // could possibly destroy the part. To avoid this, ref it temporarily.
1589 t->write( decoded, true );
1593 void KHTMLPart::write( const QString &str )
1598 if(d->m_bFirstData) {
1599 // determine the parse mode
1600 d->m_doc->setParseMode( DocumentImpl::Strict );
1601 d->m_bFirstData = false;
1604 jScript()->appendSourceFile(m_url.url(),str);
1605 Tokenizer* t = d->m_doc->tokenizer();
1607 t->write( str, true );
1610 void KHTMLPart::end()
1612 // make sure nothing's left in there...
1614 write(d->m_decoder->flush());
1616 d->m_doc->finishParsing();
1621 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
1623 if (!d->m_view) return;
1624 d->m_view->paint(p, rc, yOff, more);
1629 void KHTMLPart::stopAnimations()
1632 d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
1634 ConstFrameIt it = d->m_frames.begin();
1635 ConstFrameIt end = d->m_frames.end();
1636 for (; it != end; ++it )
1637 if ( !( *it ).m_part.isNull() && ( *it ).m_part->inherits( "KHTMLPart" ) ) {
1638 KParts::ReadOnlyPart* p = ( *it ).m_part;
1639 static_cast<KHTMLPart*>( p )->stopAnimations();
1643 void KHTMLPart::slotFinishedParsing()
1645 d->m_doc->setParsing(false);
1646 checkEmitLoadEvent();
1647 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
1650 return; // We are probably being destructed.
1651 // check if the scrollbars are really needed for the content
1652 // if not, remove them, relayout, and repaint
1654 d->m_view->restoreScrollBar();
1656 if ( !m_url.encodedHtmlRef().isEmpty() )
1657 if ( !gotoAnchor( m_url.encodedHtmlRef()) )
1658 gotoAnchor( m_url.htmlRef() );
1663 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
1666 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1667 KHTMLPart* p = this;
1670 p->d->m_totalObjectCount++;
1671 p = p->parentPart();
1672 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount )
1673 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1679 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
1682 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
1683 KHTMLPart* p = this;
1686 p->d->m_loadedObjects++;
1687 p = p->parentPart();
1688 if ( !p && d->m_loadedObjects <= d->m_totalObjectCount && d->m_jobPercent >= 100 )
1689 QTimer::singleShot( 200, op, SLOT( slotProgressUpdate() ) );
1699 void KHTMLPart::slotProgressUpdate()
1702 if ( d->m_loadedObjects < d->m_totalObjectCount )
1703 percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
1705 percent = d->m_jobPercent;
1707 if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
1708 emit d->m_extension->infoMessage( i18n( "%1 of 1 Image loaded", "%1 of %n Images loaded", d->m_totalObjectCount ).arg( d->m_loadedObjects ) );
1710 emit d->m_extension->loadingProgress( percent );
1713 void KHTMLPart::slotJobSpeed( KIO::Job* /*job*/, unsigned long speed )
1715 emit d->m_extension->speedProgress( speed );
1718 void KHTMLPart::slotJobPercent( KIO::Job* /*job*/, unsigned long percent )
1720 d->m_jobPercent = percent;
1722 if ( !parentPart() )
1723 QTimer::singleShot( 0, this, SLOT( slotProgressUpdate() ) );
1728 void KHTMLPart::checkCompleted()
1730 // kdDebug( 6050 ) << "KHTMLPart::checkCompleted() parsing: " << d->m_doc->parsing() << endl;
1731 // kdDebug( 6050 ) << " complete: " << d->m_bComplete << endl;
1734 // restore the cursor position
1735 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
1737 if (d->m_focusNodeNumber >= 0)
1738 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
1740 d->m_doc->setFocusNode(0);
1741 d->m_focusNodeRestored = true;
1745 // Any frame that hasn't completed yet ?
1746 ConstFrameIt it = d->m_frames.begin();
1747 ConstFrameIt end = d->m_frames.end();
1748 for (; it != end; ++it )
1749 if ( !(*it).m_bCompleted )
1752 // Are we still parsing - or have we done the completed stuff already ?
1753 if ( d->m_bComplete || (d->m_doc && d->m_doc->parsing()) )
1756 // Still waiting for images/scripts from the loader ?
1758 if ( d->m_doc && d->m_doc->docLoader() )
1759 requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
1765 // Now do what should be done when we are really completed.
1766 d->m_bComplete = true;
1768 checkEmitLoadEvent(); // if we didn't do it before
1775 // check that the view has not been moved by the user
1776 if ( m_url.encodedHtmlRef().isEmpty() && d->m_view->contentsY() == 0 )
1777 d->m_view->setContentsPos( d->m_extension->urlArgs().xOffset,
1778 d->m_extension->urlArgs().yOffset );
1781 d->m_view->complete();
1787 if ( d->m_scheduledRedirection != noRedirectionScheduled )
1789 // Do not start redirection for frames here! That action is
1790 // deferred until the parent emits a completed signal.
1791 if ( parentPart() == 0 )
1792 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1794 emit completed( true );
1798 if ( d->m_bPendingChildRedirection )
1799 emit completed ( true );
1805 // find the alternate stylesheets
1808 sheets = d->m_doc->availableStyleSheets();
1809 d->m_paUseStylesheet->setItems( sheets );
1810 d->m_paUseStylesheet->setEnabled( !sheets.isEmpty() );
1811 if (!sheets.isEmpty())
1813 d->m_paUseStylesheet->setCurrentItem(kMax(sheets.findIndex(d->m_sheetUsed), 0));
1814 slotUseStylesheet();
1818 emit setStatusBarText(i18n("Done."));
1822 kdDebug(6050) << "DONE: " <<d->m_parsetime.elapsed() << endl;
1826 void KHTMLPart::checkEmitLoadEvent()
1828 if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
1830 ConstFrameIt it = d->m_frames.begin();
1831 ConstFrameIt end = d->m_frames.end();
1832 for (; it != end; ++it )
1833 if ( !(*it).m_bCompleted ) // still got a frame running -> too early
1837 // All frames completed -> set their domain to the frameset's domain
1838 // This must only be done when loading the frameset initially (#22039),
1839 // not when following a link in a frame (#44162).
1842 DOMString domain = d->m_doc->domain();
1843 ConstFrameIt it = d->m_frames.begin();
1844 ConstFrameIt end = d->m_frames.end();
1845 for (; it != end; ++it )
1847 KParts::ReadOnlyPart *p = (*it).m_part;
1848 if ( p && p->inherits( "KHTMLPart" ))
1850 KHTMLPart* htmlFrame = static_cast<KHTMLPart *>(p);
1851 if (htmlFrame->d->m_doc)
1853 kdDebug() << "KHTMLPart::checkCompleted setting frame domain to " << domain.string() << endl;
1854 htmlFrame->d->m_doc->setDomain( domain );
1860 d->m_bLoadEventEmitted = true;
1861 d->m_bUnloadEventEmitted = false;
1866 const KHTMLSettings *KHTMLPart::settings() const
1868 return d->m_settings;
1871 #ifndef KDE_NO_COMPAT
1872 KURL KHTMLPart::baseURL() const
1874 if ( !d->m_doc ) return KURL();
1876 return d->m_doc->baseURL();
1879 QString KHTMLPart::baseTarget() const
1881 if ( !d->m_doc ) return QString::null;
1883 return d->m_doc->baseTarget();
1887 KURL KHTMLPart::completeURL( const QString &url )
1889 if ( !d->m_doc ) return url;
1893 return KURL(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
1896 return KURL( d->m_doc->completeURL( url ) );
1899 void KHTMLPart::scheduleRedirection( double delay, const QString &url, bool doLockHistory, bool userGesture )
1901 kdDebug(6050) << "KHTMLPart::scheduleRedirection delay=" << delay << " url=" << url << endl;
1902 if (delay < 0 || delay > INT_MAX / 1000)
1904 if ( d->m_scheduledRedirection == noRedirectionScheduled || delay < d->m_delayRedirect )
1907 // Handle a location change of a page with no document as a special case.
1908 // This may happens when a frame changes the location of another frame.
1909 d->m_scheduledRedirection = redirectionDuringLoad;
1912 d->m_scheduledRedirection = redirectionScheduled;
1913 d->m_delayRedirect = delay;
1914 d->m_redirectURL = url;
1915 d->m_redirectLockHistory = doLockHistory;
1916 d->m_redirectUserGesture = userGesture;
1918 if ( d->m_bComplete ) {
1919 d->m_redirectionTimer.stop();
1920 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1925 void KHTMLPart::scheduleHistoryNavigation( int steps )
1927 d->m_scheduledRedirection = historyNavigationScheduled;
1928 d->m_delayRedirect = 0;
1929 d->m_redirectURL = QString::null;
1930 d->m_scheduledHistoryNavigationSteps = steps;
1931 if ( d->m_bComplete ) {
1932 d->m_redirectionTimer.stop();
1933 d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1937 void KHTMLPart::cancelRedirection(bool cancelWithLoadInProgress)
1940 d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
1941 d->m_scheduledRedirection = noRedirectionScheduled;
1942 d->m_redirectionTimer.stop();
1946 void KHTMLPart::slotRedirect()
1948 if (d->m_scheduledRedirection == historyNavigationScheduled) {
1949 d->m_scheduledRedirection = noRedirectionScheduled;
1951 // Special case for go(0) from a frame -> reload only the frame
1952 // go(i!=0) from a frame navigates into the history of the frame only,
1953 // in both IE and NS (but not in Mozilla).... we can't easily do that
1955 if (d->m_scheduledHistoryNavigationSteps == 0) // add && parentPart() to get only frames, but doesn't matter
1956 openURL( url() ); /// ## need args.reload=true?
1958 if (d->m_extension) {
1959 BrowserInterface *interface = d->m_extension->browserInterface();
1961 interface->callMethod( "goHistory(int)", d->m_scheduledHistoryNavigationSteps );
1967 QString u = d->m_redirectURL;
1968 d->m_scheduledRedirection = noRedirectionScheduled;
1969 d->m_delayRedirect = 0;
1970 d->m_redirectURL = QString::null;
1971 if ( u.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
1973 QString script = KURL::decode_string( u.right( u.length() - 11 ) );
1974 //kdDebug( 6050 ) << "KHTMLPart::slotRedirect script=" << script << endl;
1975 QVariant res = executeScript( script, d->m_redirectUserGesture );
1976 if ( res.type() == QVariant::String ) {
1978 write( res.asString() );
1983 KParts::URLArgs args;
1984 if ( urlcmp( u, m_url.url(), true, false ) )
1987 args.setLockHistory( d->m_redirectLockHistory );
1988 urlSelected( u, 0, 0, "_self", args );
1991 void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url)
1993 // the slave told us that we got redirected
1994 // kdDebug( 6050 ) << "redirection by KIO to " << url.url() << endl;
1995 emit d->m_extension->setLocationBarURL( url.prettyURL() );
1996 d->m_workingURL = url;
2001 bool KHTMLPart::setEncoding( const QString &name, bool override )
2003 d->m_encoding = name;
2004 d->m_haveEncoding = override;
2006 if( !m_url.isEmpty() ) {
2011 d->m_restored = true;
2013 d->m_restored = false;
2021 QString KHTMLPart::encoding() const
2023 if(d->m_haveEncoding && !d->m_encoding.isEmpty())
2024 return d->m_encoding;
2026 if(d->m_decoder && d->m_decoder->encoding())
2027 return QString(d->m_decoder->encoding());
2029 return(settings()->encoding());
2032 void KHTMLPart::setUserStyleSheet(const KURL &url)
2034 if ( d->m_doc && d->m_doc->docLoader() )
2035 (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
2038 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
2041 d->m_doc->setUserStyleSheet( styleSheet );
2044 bool KHTMLPart::gotoAnchor( const QString &name )
2049 NodeImpl *n = d->m_doc->getElementById(name);
2051 HTMLCollectionImpl *anchors =
2052 new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
2054 n = anchors->namedItem(name, !d->m_doc->inCompatMode());
2058 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
2061 kdDebug(6050) << "KHTMLPart::gotoAnchor node '" << name << "' not found" << endl;
2065 // We need to update the layout before scrolling, otherwise we could
2066 // really mess things up if an anchor scroll comes at a bad moment.
2068 d->m_doc->updateRendering();
2069 // Only do a layout if changes have occurred that make it necessary.
2070 if ( d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() ) {
2071 d->m_view->layout();
2076 HTMLElementImpl *a = static_cast<HTMLElementImpl *>(n);
2077 a->getUpperLeftCorner(x, y);
2079 // Remove the 50 pixel slop factor; some pages expect anchors to be exactly scrolled to.
2080 // Also, call recursive version so this will expose correctly from within nested frames.
2081 d->m_view->setContentsPosRecursive(x, y);
2083 d->m_view->setContentsPos(x-50, y-50);
2089 void KHTMLPart::setStandardFont( const QString &name )
2091 d->m_settings->setStdFontName(name);
2094 void KHTMLPart::setFixedFont( const QString &name )
2096 d->m_settings->setFixedFontName(name);
2101 void KHTMLPart::setURLCursor( const QCursor &c )
2103 d->m_linkCursor = c;
2108 QCursor KHTMLPart::urlCursor() const
2111 // Don't load the link cursor until it's actually used.
2112 // Also, we don't need setURLCursor.
2113 // This speeds up startup time.
2114 return KCursor::handCursor();
2116 return d->m_linkCursor;
2120 bool KHTMLPart::onlyLocalReferences() const
2122 return d->m_onlyLocalReferences;
2125 void KHTMLPart::setOnlyLocalReferences(bool enable)
2127 d->m_onlyLocalReferences = enable;
2130 void KHTMLPart::setEditMode(TristateFlag flag)
2132 d->m_inEditMode = flag;
2135 TristateFlag KHTMLPart::editMode() const
2137 if (d->m_inEditMode != FlagNone)
2138 return d->m_inEditMode == FlagEnabled ? FlagEnabled : FlagDisabled;
2140 KHTMLPart *part = parentPart();
2142 if (part->d->m_inEditMode != FlagNone)
2143 return part->d->m_inEditMode == FlagEnabled ? FlagEnabled : FlagDisabled;
2144 part = part->parentPart();
2149 bool KHTMLPart::inEditMode() const
2151 return editMode() == FlagEnabled;
2154 void KHTMLPart::findTextBegin(NodeImpl *startNode, int startPos)
2156 d->m_findPos = startPos;
2157 d->m_findNode = startNode;
2160 bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensitive, bool isRegExp )
2165 if(!d->m_findNode) {
2166 if (d->m_doc->isHTMLDocument())
2167 d->m_findNode = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
2169 d->m_findNode = d->m_doc;
2172 if ( !d->m_findNode )
2174 kdDebug() << "KHTMLPart::findTextNext no findNode -> return false" << endl;
2177 if ( d->m_findNode->id() == ID_FRAMESET )
2179 kdDebug() << "KHTMLPart::findTextNext FRAMESET -> return false" << endl;
2185 if( (d->m_findNode->nodeType() == Node::TEXT_NODE || d->m_findNode->nodeType() == Node::CDATA_SECTION_NODE) && d->m_findNode->renderer() )
2187 DOMString nodeText = d->m_findNode->nodeValue();
2188 DOMStringImpl *t = nodeText.implementation();
2189 QConstString s(t->s, t->l);
2194 QRegExp matcher( str );
2195 matcher.setCaseSensitive( caseSensitive );
2196 d->m_findPos = matcher.search(s.string(), d->m_findPos+1);
2197 if ( d->m_findPos != -1 )
2198 matchLen = matcher.matchedLength();
2201 d->m_findPos = s.string().find(str, d->m_findPos+1, caseSensitive);
2202 matchLen = str.length();
2206 d->m_findPos = s.string().find(str, d->m_findPos+1, caseSensitive);
2208 if (d->m_findPos == -1) {
2209 // search from end of node
2210 d->m_findPos = s.string().findRev(str, -1, caseSensitive);
2211 } else if (d->m_findPos != 0) {
2212 d->m_findPos = s.string().findRev(str, d->m_findPos-1, caseSensitive);
2214 // already at start of this node, on to the next node
2218 matchLen = str.length();
2221 if(d->m_findPos != -1)
2225 static_cast<khtml::RenderText *>(d->m_findNode->renderer())
2226 ->posOfChar(d->m_findPos, x, y);
2227 d->m_view->setContentsPos(x-50, y-50);
2229 Selection s = selection();
2230 s.moveTo(d->m_findNode, d->m_findPos, d->m_findNode, d->m_findPos + matchLen);
2241 next = d->m_findNode->firstChild();
2243 if(!next) next = d->m_findNode->nextSibling();
2244 while(d->m_findNode && !next) {
2245 d->m_findNode = d->m_findNode->parentNode();
2246 if( d->m_findNode ) {
2247 next = d->m_findNode->nextSibling();
2253 next = d->m_findNode->lastChild();
2255 if (!next ) next = d->m_findNode->previousSibling();
2256 while ( d->m_findNode && !next )
2258 d->m_findNode = d->m_findNode->parentNode();
2261 next = d->m_findNode->previousSibling();
2266 d->m_findNode = next;
2267 if(!d->m_findNode) return false;
2271 QString KHTMLPart::text(const DOM::Range &r) const
2273 // FIXME: This whole function should use the render tree and not the DOM tree, since elements could
2274 // be hidden using CSS, or additional generated content could be added. For now, we just make sure
2275 // text objects walk their renderers' InlineTextBox objects, so that we at least get the whitespace
2276 // stripped out properly and obey CSS visibility for text runs.
2281 bool hasNewLine = true;
2282 bool addedSpace = true;
2283 bool needSpace = false;
2285 DOM::Node startNode = r.startContainer();
2286 DOM::Node endNode = r.endContainer();
2287 int startOffset = r.startOffset();
2288 int endOffset = r.endOffset();
2289 if (!startNode.isNull() && startNode.nodeType() == Node::ELEMENT_NODE) {
2290 if (startOffset >= 0 && startOffset < (int)startNode.childNodes().length()) {
2291 startNode = startNode.childNodes().item(r.startOffset());
2295 if (!endNode.isNull() && endNode.nodeType() == Node::ELEMENT_NODE) {
2296 if (endOffset > 0 && endOffset <= (int)endNode.childNodes().length()) {
2297 endNode = endNode.childNodes().item(endOffset - 1);
2302 DOM::Node n = startNode;
2303 while(!n.isNull()) {
2304 if(n.nodeType() == DOM::Node::TEXT_NODE) {
2310 QString str = n.nodeValue().string();
2311 int start = (n == startNode) ? startOffset : -1;
2312 int end = (n == endNode) ? endOffset : -1;
2313 RenderObject* renderer = n.handle()->renderer();
2314 if (renderer && renderer->isText()) {
2315 if (renderer->style()->whiteSpace() == khtml::PRE) {
2316 if (needSpace && !addedSpace)
2318 int runStart = (start == -1) ? 0 : start;
2319 int runEnd = (end == -1) ? str.length() : end;
2320 text += str.mid(runStart, runEnd-runStart);
2322 addedSpace = str[runEnd-1].direction() == QChar::DirWS;
2325 RenderText* textObj = static_cast<RenderText*>(n.handle()->renderer());
2326 if (!textObj->firstTextBox() && str.length() > 0) {
2327 // We have no runs, but we do have a length. This means we must be
2328 // whitespace that collapsed away at the end of a line.
2332 for (InlineTextBox* box = textObj->firstTextBox(); box; box = box->nextTextBox()) {
2333 int runStart = (start == -1) ? box->m_start : start;
2334 int runEnd = (end == -1) ? box->m_start + box->m_len : end;
2335 runEnd = QMIN(runEnd, box->m_start + box->m_len);
2336 if (runStart >= box->m_start &&
2337 runStart < box->m_start + box->m_len) {
2338 if (box == textObj->firstTextBox() && box->m_start == runStart && runStart > 0)
2339 needSpace = true; // collapsed space at the start
2340 if (needSpace && !addedSpace)
2342 QString runText = str.mid(runStart, runEnd - runStart);
2343 runText.replace('\n', ' ');
2345 int nextRunStart = box->nextTextBox() ? box->nextTextBox()->m_start : str.length(); // collapsed space between runs or at the end
2346 needSpace = nextRunStart > runEnd; // collapsed space between runs or at the end
2347 addedSpace = str[runEnd-1].direction() == QChar::DirWS;
2350 if (end != -1 && runEnd >= end)
2358 // This is our simple HTML -> ASCII transformation:
2359 unsigned short id = n.elementId();
2397 if(n == endNode) break;
2398 DOM::Node next = n.firstChild();
2399 if(next.isNull()) next = n.nextSibling();
2400 while( next.isNull() && !n.parentNode().isNull() ) {
2402 if(n == endNode) break;
2403 next = n.nextSibling();
2404 unsigned short id = n.elementId();
2432 // An extra newline is needed at the start, not the end, of these types of tags,
2433 // so don't add another here.
2442 int end = text.length();
2444 // Strip leading LFs
2445 while ((start < end) && (text[start] == '\n'))
2448 // Strip excessive trailing LFs
2449 while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n'))
2452 return text.mid(start, end-start);
2455 QString KHTMLPart::selectedText() const
2457 return text(selection().toRange());
2460 bool KHTMLPart::hasSelection() const
2462 return !d->m_selection.isEmpty();
2465 const Selection &KHTMLPart::selection() const
2467 return d->m_selection;
2470 void KHTMLPart::setSelection(const Selection &s)
2472 if (d->m_selection != s) {
2473 clearCaretRectIfNeeded();
2474 setFocusNodeIfNeeded(s);
2476 notifySelectionChanged();
2480 void KHTMLPart::takeSelectionFrom(const EditCommand &cmd, bool useEndingSelection)
2483 if (useEndingSelection)
2484 s = cmd.endingSelection();
2486 s = cmd.startingSelection();
2488 if (d->m_selection != s) {
2489 clearCaretRectIfNeeded();
2490 setFocusNodeIfNeeded(s);
2492 notifySelectionChanged(false);
2496 void KHTMLPart::clearSelection()
2498 clearCaretRectIfNeeded();
2499 setFocusNodeIfNeeded(d->m_selection);
2500 d->m_selection = Selection();
2501 notifySelectionChanged();
2504 void KHTMLPart::invalidateSelection()
2506 clearCaretRectIfNeeded();
2507 setFocusNodeIfNeeded(d->m_selection);
2508 d->m_selection.setNeedsLayout();
2509 notifySelectionChanged(false);
2512 void KHTMLPart::setSelectionVisible(bool flag)
2514 if (d->m_caretVisible == flag)
2517 clearCaretRectIfNeeded();
2518 setFocusNodeIfNeeded(d->m_selection);
2519 d->m_caretVisible = flag;
2520 notifySelectionChanged();
2523 void KHTMLPart::slotClearSelection()
2525 clearCaretRectIfNeeded();
2526 bool hadSelection = hasSelection();
2527 d->m_selection.clear();
2529 notifySelectionChanged();
2532 void KHTMLPart::clearCaretRectIfNeeded()
2534 if (d->m_caretPaint) {
2535 d->m_caretPaint = false;
2536 d->m_selection.needsCaretRepaint();
2540 void KHTMLPart::setFocusNodeIfNeeded(const Selection &s)
2542 if (!xmlDocImpl() || s.state() == Selection::NONE)
2545 NodeImpl *n = s.startNode();
2546 NodeImpl *target = n->isContentEditable() ? n : 0;
2548 while (n != s.endNode()) {
2549 if (n->isContentEditable()) {
2553 n = n->traverseNextNode();
2556 assert(target == 0 || target->isContentEditable());
2559 for ( ; target && !target->isFocusable(); target = target->parentNode()); // loop
2560 if (target && target->isMouseFocusable())
2561 xmlDocImpl()->setFocusNode(target);
2562 else if (!target || !target->focused())
2563 xmlDocImpl()->setFocusNode(0);
2567 void KHTMLPart::notifySelectionChanged(bool endTyping)
2569 // kill any caret blink timer now running
2570 if (d->m_caretBlinkTimer >= 0) {
2571 killTimer(d->m_caretBlinkTimer);
2572 d->m_caretBlinkTimer = -1;
2575 // see if a new caret blink timer needs to be started
2576 if (d->m_caretVisible && d->m_caretBlinks &&
2577 d->m_selection.state() == Selection::CARET && d->m_selection.startNode()->isContentEditable()) {
2578 d->m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
2579 d->m_caretPaint = true;
2580 d->m_selection.needsCaretRepaint();
2584 d->m_doc->updateSelection();
2587 TypingCommand::closeTyping(lastEditCommand());
2589 // Always clear the x position used for vertical arrow navigation.
2590 // It will be restored by the vertical arrow navigation code if necessary.
2591 d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
2593 emitSelectionChanged();
2596 void KHTMLPart::setXPosForVerticalArrowNavigation(int x)
2598 d->m_xPosForVerticalArrowNavigation = x;
2601 int KHTMLPart::xPosForVerticalArrowNavigation() const
2603 return d->m_xPosForVerticalArrowNavigation;
2606 void KHTMLPart::timerEvent(QTimerEvent *e)
2608 if (e->timerId() == d->m_caretBlinkTimer &&
2609 d->m_caretVisible &&
2611 d->m_selection.state() == Selection::CARET) {
2612 d->m_caretPaint = !d->m_caretPaint;
2613 d->m_selection.needsCaretRepaint();
2617 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
2619 if (d->m_caretPaint)
2620 d->m_selection.paintCaret(p, rect);
2625 void KHTMLPart::overURL( const QString &url, const QString &target, bool shiftPressed )
2627 if ( !d->m_kjsStatusBarText.isEmpty() && !shiftPressed ) {
2629 emit setStatusBarText( d->m_kjsStatusBarText );
2630 d->m_kjsStatusBarText = QString::null;
2636 if ( url.isEmpty() )
2638 emit setStatusBarText(completeURL(url).htmlURL());
2642 if (url.find( QString::fromLatin1( "javascript:" ),0, false ) != -1 )
2644 emit setStatusBarText( KURL::decode_string( url.mid( url.find( "javascript:", 0, false ) ) ) );
2648 KURL u = completeURL(url);
2650 // special case for <a href="">
2651 if ( url.isEmpty() )
2652 u.setFileName( url );
2656 KMimeType::Ptr typ = KMimeType::findByURL( u );
2659 com = typ->comment( u, false );
2661 if ( u.isMalformed() )
2663 emit setStatusBarText(u.htmlURL());
2667 if ( u.isLocalFile() )
2669 // TODO : use KIO::stat() and create a KFileItem out of its result,
2670 // to use KFileItem::statusBarText()
2671 QCString path = QFile::encodeName( u.path() );
2674 bool ok = !stat( path.data(), &buff );
2677 if (ok) ok = !lstat( path.data(), &lbuff );
2679 QString text = u.htmlURL();
2680 QString text2 = text;
2682 if (ok && S_ISLNK( lbuff.st_mode ) )
2686 tmp = i18n( "Symbolic Link");
2688 tmp = i18n("%1 (Link)").arg(com);
2689 char buff_two[1024];
2691 int n = readlink ( path.data(), buff_two, 1022);
2696 emit setStatusBarText(text2);
2705 else if ( ok && S_ISREG( buff.st_mode ) )
2707 if (buff.st_size < 1024)
2708 text = i18n("%2 (%1 bytes)").arg((long) buff.st_size).arg(text2); // always put the URL last, in case it contains '%'
2711 float d = (float) buff.st_size/1024.0;
2712 text = i18n("%1 (%2 K)").arg(text2).arg(KGlobal::locale()->formatNumber(d, 2)); // was %.2f
2717 else if ( ok && S_ISDIR( buff.st_mode ) )
2727 emit setStatusBarText(text);
2732 if (target == QString::fromLatin1("_blank"))
2734 extra = i18n(" (In new window)");
2736 else if (!target.isEmpty() &&
2737 (target != QString::fromLatin1("_top")) &&
2738 (target != QString::fromLatin1("_self")) &&
2739 (target != QString::fromLatin1("_parent")))
2741 extra = i18n(" (In other frame)");
2744 if (u.protocol() == QString::fromLatin1("mailto")) {
2745 QString mailtoMsg/* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
2746 mailtoMsg += i18n("Email to: ") + KURL::decode_string(u.path());
2747 QStringList queries = QStringList::split('&', u.query().mid(1));
2748 for (QStringList::Iterator it = queries.begin(); it != queries.end(); ++it)
2749 if ((*it).startsWith(QString::fromLatin1("subject=")))
2750 mailtoMsg += i18n(" - Subject: ") + KURL::decode_string((*it).mid(8));
2751 else if ((*it).startsWith(QString::fromLatin1("cc=")))
2752 mailtoMsg += i18n(" - CC: ") + KURL::decode_string((*it).mid(3));
2753 else if ((*it).startsWith(QString::fromLatin1("bcc=")))
2754 mailtoMsg += i18n(" - BCC: ") + KURL::decode_string((*it).mid(4));
2755 mailtoMsg.replace(QRegExp("&"), QString("&"));
2756 mailtoMsg.replace(QRegExp("<"), QString("<"));
2757 mailtoMsg.replace(QRegExp(">"), QString(">"));
2758 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), "");
2759 emit setStatusBarText(mailtoMsg);
2762 // Is this check neccessary at all? (Frerich)
2764 else if (u.protocol() == QString::fromLatin1("http")) {
2765 DOM::Node hrefNode = nodeUnderMouse().parentNode();
2766 while (hrefNode.nodeName().string() != QString::fromLatin1("A") && !hrefNode.isNull())
2767 hrefNode = hrefNode.parentNode();
2769 if (!hrefNode.isNull()) {
2770 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
2771 if (!hreflangNode.isNull()) {
2772 QString countryCode = hreflangNode.nodeValue().string().lower();
2773 // Map the language code to an appropriate country code.
2774 if (countryCode == QString::fromLatin1("en"))
2775 countryCode = QString::fromLatin1("gb");
2776 QString flagImg = QString::fromLatin1("<img src=%1>").arg(
2777 locate("locale", QString::fromLatin1("l10n/")
2779 + QString::fromLatin1("/flag.png")));
2780 emit setStatusBarText(flagImg + u.prettyURL() + extra);
2785 emit setStatusBarText(u.htmlURL() + extra);
2789 #endif // APPLE_CHANGES
2791 void KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target,
2792 KParts::URLArgs args )
2794 bool hasTarget = false;
2796 QString target = _target;
2797 if ( target.isEmpty() && d->m_doc )
2798 target = d->m_doc->baseTarget();
2799 if ( !target.isEmpty() )
2802 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
2804 executeScript( KURL::decode_string( url.right( url.length() - 11) ), true );
2808 KURL cURL = completeURL(url);
2810 // special case for <a href="">
2811 if ( url.isEmpty() )
2812 cURL.setFileName( url );
2815 if ( !cURL.isValid() )
2816 // ### ERROR HANDLING
2819 //kdDebug( 6000 ) << "urlSelected: complete URL:" << cURL.url() << " target = " << target << endl;
2822 if ( button == LeftButton && ( state & ShiftButton ) )
2824 KIO::MetaData metaData;
2825 metaData["referrer"] = d->m_referrer;
2826 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As..." ), cURL, metaData );
2830 if (!checkLinkSecurity(cURL,
2831 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?" ),
2836 args.frameName = target;
2838 if ( d->m_bHTTPRefresh )
2840 d->m_bHTTPRefresh = false;
2841 args.metaData()["cache"] = "refresh";
2845 args.metaData().insert("main_frame_request",
2846 parentPart() == 0 ? "TRUE":"FALSE");
2847 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
2848 args.metaData().insert("ssl_activate_warnings", "TRUE");
2852 args.metaData()["referrer"] = d->m_referrer;
2853 KWQ(this)->urlSelected(cURL, button, state, args);
2857 // unknown frame names should open in a new window.
2858 khtml::ChildFrame *frame = recursiveFrameRequest( cURL, args, false );
2861 args.metaData()["referrer"] = d->m_referrer;
2862 requestObject( frame, cURL, args );
2867 if ( !d->m_bComplete && !hasTarget )
2870 if (!d->m_referrer.isEmpty())
2871 args.metaData()["referrer"] = d->m_referrer;
2873 if ( button == MidButton && (state & ShiftButton) )
2875 KParts::WindowArgs winArgs;
2876 winArgs.lowerWindow = true;
2877 KParts::ReadOnlyPart *newPart = 0;
2878 emit d->m_extension->createNewWindow( cURL, args, winArgs, newPart );
2881 emit d->m_extension->openURLRequest( cURL, args );
2882 #endif // APPLE_CHANGES
2887 void KHTMLPart::slotViewDocumentSource()
2890 if (!(url.isLocalFile()) && KHTMLPageCache::self()->isValid(d->m_cacheId))
2892 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2893 if (sourceFile.status() == 0)
2895 KHTMLPageCache::self()->saveData(d->m_cacheId, sourceFile.dataStream());
2897 url.setPath(sourceFile.name());
2901 // emit d->m_extension->openURLRequest( m_url, KParts::URLArgs( false, 0, 0, QString::fromLatin1( "text/plain" ) ) );
2902 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2905 void KHTMLPart::slotViewFrameSource()
2907 KParts::ReadOnlyPart *frame = currentFrame();
2911 KURL url = frame->url();
2912 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
2914 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
2916 if (KHTMLPageCache::self()->isValid(cacheId))
2918 KTempFile sourceFile(QString::null, QString::fromLatin1(".html"));
2919 if (sourceFile.status() == 0)
2921 KHTMLPageCache::self()->saveData(cacheId, sourceFile.dataStream());
2923 url.setPath(sourceFile.name());
2928 (void) KRun::runURL( url, QString::fromLatin1("text/plain") );
2931 KURL KHTMLPart::backgroundURL() const
2933 // ### what about XML documents? get from CSS?
2934 if (!d->m_doc || !d->m_doc->isHTMLDocument())
2937 QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
2939 return KURL( m_url, relURL );
2942 void KHTMLPart::slotSaveBackground()
2944 KIO::MetaData metaData;
2945 metaData["referrer"] = d->m_referrer;
2946 KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save background image as"), backgroundURL(), metaData );
2949 void KHTMLPart::slotSaveDocument()
2951 KURL srcURL( m_url );
2953 if ( srcURL.fileName(false).isEmpty() )
2954 srcURL.setFileName( "index.html" );
2956 KIO::MetaData metaData;
2958 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files"), d->m_cacheId );
2961 void KHTMLPart::slotSecurity()
2963 // kdDebug( 6050 ) << "Meta Data:" << endl
2964 // << d->m_ssl_peer_cert_subject
2966 // << d->m_ssl_peer_cert_issuer
2968 // << d->m_ssl_cipher
2970 // << d->m_ssl_cipher_desc
2972 // << d->m_ssl_cipher_version
2974 // << d->m_ssl_good_from
2976 // << d->m_ssl_good_until
2978 // << d->m_ssl_cert_state
2981 KSSLInfoDlg *kid = new KSSLInfoDlg(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
2983 if (d->m_bSecurityInQuestion)
2984 kid->setSecurityInQuestion(true);
2986 if (d->m_ssl_in_use) {
2987 KSSLCertificate *x = KSSLCertificate::fromString(d->m_ssl_peer_certificate.local8Bit());
2989 // Set the chain back onto the certificate
2990 QStringList cl = QStringList::split(QString("\n"), d->m_ssl_peer_chain);
2991 QPtrList<KSSLCertificate> ncl;
2993 ncl.setAutoDelete(true);
2994 for (QStringList::Iterator it = cl.begin(); it != cl.end(); ++it) {
2995 KSSLCertificate *y = KSSLCertificate::fromString((*it).local8Bit());
2996 if (y) ncl.append(y);
2999 if (ncl.count() > 0)
3000 x->chain().setChain(ncl);
3006 d->m_ssl_cipher_desc,
3007 d->m_ssl_cipher_version,
3008 d->m_ssl_cipher_used_bits.toInt(),
3009 d->m_ssl_cipher_bits.toInt(),
3010 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt()
3018 void KHTMLPart::slotSaveFrame()
3020 if ( !d->m_activeFrame )
3021 return; // should never be the case, but one never knows :-)
3023 KURL srcURL( static_cast<KParts::ReadOnlyPart *>( d->m_activeFrame )->url() );
3025 if ( srcURL.fileName(false).isEmpty() )
3026 srcURL.setFileName( "index.html" );
3028 KIO::MetaData metaData;
3029 // Referrer unknown?
3030 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, i18n("*.html *.htm|HTML files") );
3033 void KHTMLPart::slotSetEncoding()
3035 // first Item is always auto
3036 if(d->m_paSetEncoding->currentItem() == 0)
3037 setEncoding(QString::null, false);
3039 // strip of the language to get the raw encoding again.
3040 QString enc = KGlobal::charsets()->encodingForName(d->m_paSetEncoding->currentText());
3041 setEncoding(enc, true);
3045 void KHTMLPart::slotUseStylesheet()
3047 if (d->m_doc && d->m_paUseStylesheet->currentText() != d->m_sheetUsed) {
3048 d->m_sheetUsed = d->m_paUseStylesheet->currentText();
3049 d->m_doc->updateStyleSelector();
3053 void KHTMLPart::updateActions()
3055 bool frames = false;
3057 QValueList<khtml::ChildFrame>::ConstIterator it = d->m_frames.begin();
3058 QValueList<khtml::ChildFrame>::ConstIterator end = d->m_frames.end();
3059 for (; it != end; ++it )
3060 if ( (*it).m_type == khtml::ChildFrame::Frame )
3066 d->m_paViewFrame->setEnabled( frames );
3067 d->m_paSaveFrame->setEnabled( frames );
3070 d->m_paFind->setText( i18n( "&Find in Frame..." ) );
3072 d->m_paFind->setText( i18n( "&Find..." ) );
3074 KParts::Part *frame = 0;
3077 frame = currentFrame();
3079 bool enableFindAndSelectAll = true;
3082 enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
3084 d->m_paFind->setEnabled( enableFindAndSelectAll );
3085 d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
3087 bool enablePrintFrame = false;
3091 QObject *ext = KParts::BrowserExtension::childObject( frame );
3093 enablePrintFrame = ext->metaObject()->slotNames().contains( "print()" );
3096 d->m_paPrintFrame->setEnabled( enablePrintFrame );
3101 if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
3102 bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
3104 d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
3109 bool KHTMLPart::requestFrame( khtml::RenderPart *frame, const QString &url, const QString &frameName,
3110 const QStringList ¶ms, bool isIFrame )
3112 // kdDebug( 6050 ) << "childRequest( ..., " << url << ", " << frameName << " )" << endl;
3113 FrameIt it = d->m_frames.find( frameName );
3114 if ( it == d->m_frames.end() )
3116 khtml::ChildFrame child;
3117 // kdDebug( 6050 ) << "inserting new frame into frame map " << frameName << endl;
3118 child.m_name = frameName;
3119 it = d->m_frames.append( child );
3122 (*it).m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
3123 (*it).m_frame = frame;
3124 (*it).m_params = params;
3126 // Support for <frame src="javascript:string">
3127 if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
3129 if (!processObjectRequest(&(*it), "about:blank", "text/html" ))
3132 KHTMLPart *newPart = static_cast<KHTMLPart *>(&*(*it).m_part);
3133 newPart->replaceContentsWithScriptResult( url );
3138 return requestObject( &(*it), completeURL( url ));
3141 QString KHTMLPart::requestFrameName()
3144 return KWQ(this)->generateFrameName();
3146 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
3150 bool KHTMLPart::requestObject( khtml::RenderPart *frame, const QString &url, const QString &serviceType,
3151 const QStringList ¶ms )
3153 khtml::ChildFrame child;
3154 QValueList<khtml::ChildFrame>::Iterator it = d->m_objects.append( child );
3155 (*it).m_frame = frame;
3156 (*it).m_type = khtml::ChildFrame::Object;
3157 (*it).m_params = params;
3161 completedURL = completeURL(url);
3163 KParts::URLArgs args;
3164 args.serviceType = serviceType;
3165 return requestObject( &(*it), completedURL, args );
3168 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KURL &url, const KParts::URLArgs &_args )
3171 if (!checkLinkSecurity(url))
3174 if ( child->m_bPreloaded )
3176 // kdDebug(6005) << "KHTMLPart::requestObject preload" << endl;
3177 if ( child->m_frame && child->m_part && child->m_part->widget() )
3178 child->m_frame->setWidget( child->m_part->widget() );
3180 child->m_bPreloaded = false;
3184 KParts::URLArgs args( _args );
3188 child->m_run->abort();
3191 if ( child->m_part && !args.reload && urlcmp( child->m_part->url().url(), url.url(), true, true ) )
3192 args.serviceType = child->m_serviceType;
3194 child->m_args = args;
3195 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3196 child->m_serviceName = QString::null;
3197 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
3198 child->m_args.metaData()["referrer"] = d->m_referrer;
3201 child->m_args.metaData().insert("main_frame_request",
3202 parentPart() == 0 ? "TRUE":"FALSE");
3203 child->m_args.metaData().insert("ssl_was_in_use",
3204 d->m_ssl_in_use ? "TRUE":"FALSE");
3205 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
3208 // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
3209 if ((url.isEmpty() || url.url() == "about:blank") && args.serviceType.isEmpty())
3210 args.serviceType = QString::fromLatin1( "text/html" );
3213 return processObjectRequest( child, url, args.serviceType );
3215 if ( args.serviceType.isEmpty() ) {
3216 child->m_run = new KHTMLRun( this, child, url, child->m_args,
3217 child->m_type != khtml::ChildFrame::Frame );
3220 return processObjectRequest( child, url, args.serviceType );
3225 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KURL &_url, const QString &mimetype )
3227 //kdDebug( 6050 ) << "KHTMLPart::processObjectRequest trying to create part for " << mimetype << endl;
3229 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
3230 // by an emitting frame part (emit openURLRequest( blahurl, ... ) . A few lines below we delete the part
3231 // though -> the reference becomes invalid -> crash is likely
3234 // khtmlrun called us this way to indicate a loading error
3235 if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
3237 checkEmitLoadEvent();
3238 child->m_bCompleted = true;
3242 if (child->m_bNotify)
3244 child->m_bNotify = false;
3245 if ( !child->m_args.lockHistory() )
3246 emit d->m_extension->openURLNotify();
3250 if ( child->m_part )
3252 KHTMLPart *part = dynamic_cast<KHTMLPart *>(&*child->m_part);
3258 KParts::ReadOnlyPart *part = KWQ(this)->createPart(*child, url, mimetype);
3260 if ( !child->m_services.contains( mimetype ) )
3262 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 );
3267 if ( child->m_frame )
3268 if (child->m_frame->partLoadingErrorNotify( child, url, mimetype ))
3269 return true; // we succeeded after all (a fallback was used)
3271 checkEmitLoadEvent();
3276 if ( child->m_part )
3279 partManager()->removePart( (KParts::ReadOnlyPart *)child->m_part );
3281 child->m_part->deref();
3284 child->m_serviceType = mimetype;
3285 if ( child->m_frame && part->widget() )
3286 child->m_frame->setWidget( part->widget() );
3289 if ( child->m_type != khtml::ChildFrame::Object )
3290 partManager()->addPart( part, false );
3292 // kdDebug(6005) << "AH! NO FRAME!!!!!" << endl;
3295 child->m_part = part;
3296 assert( ((void*) child->m_part) != 0);
3298 if ( child->m_type != khtml::ChildFrame::Object )
3300 connect( part, SIGNAL( started( KIO::Job *) ),
3301 this, SLOT( slotChildStarted( KIO::Job *) ) );
3302 connect( part, SIGNAL( completed() ),
3303 this, SLOT( slotChildCompleted() ) );
3304 connect( part, SIGNAL( completed(bool) ),
3305 this, SLOT( slotChildCompleted(bool) ) );
3306 connect( part, SIGNAL( setStatusBarText( const QString & ) ),
3307 this, SIGNAL( setStatusBarText( const QString & ) ) );
3308 connect( this, SIGNAL( completed() ),
3309 part, SLOT( slotParentCompleted() ) );
3310 connect( this, SIGNAL( completed(bool) ),
3311 part, SLOT( slotParentCompleted() ) );
3317 child->m_extension = KParts::BrowserExtension::childObject( part );
3319 if ( child->m_extension )
3321 connect( child->m_extension, SIGNAL( openURLNotify() ),
3322 d->m_extension, SIGNAL( openURLNotify() ) );
3324 connect( child->m_extension, SIGNAL( openURLRequestDelayed( const KURL &, const KParts::URLArgs & ) ),
3325 this, SLOT( slotChildURLRequest( const KURL &, const KParts::URLArgs & ) ) );
3327 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ),
3328 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ) );
3329 connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs &, const KParts::WindowArgs &, KParts::ReadOnlyPart *& ) ),
3330 d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & , const KParts::WindowArgs &, KParts::ReadOnlyPart *&) ) );
3332 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ),
3333 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ) );
3334 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ),
3335 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ) );
3336 connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ),
3337 d->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ) );
3338 connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ),
3339 d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ) );
3341 connect( child->m_extension, SIGNAL( infoMessage( const QString & ) ),
3342 d->m_extension, SIGNAL( infoMessage( const QString & ) ) );
3344 child->m_extension->setBrowserInterface( d->m_extension->browserInterface() );
3349 checkEmitLoadEvent();
3350 // Some JS code in the load event may have destroyed the part
3351 // In that case, abort
3352 if ( !child->m_part )
3355 if ( child->m_bPreloaded )
3357 if ( child->m_frame && child->m_part )
3358 child->m_frame->setWidget( child->m_part->widget() );
3360 child->m_bPreloaded = false;
3364 child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
3366 // make sure the part has a way to find out about the mimetype.
3367 // we actually set it in child->m_args in requestObject already,
3368 // but it's useless if we had to use a KHTMLRun instance, as the
3369 // point the run object is to find out exactly the mimetype.
3370 child->m_args.serviceType = mimetype;
3372 child->m_bCompleted = false;
3373 if ( child->m_extension )
3374 child->m_extension->setURLArgs( child->m_args );
3377 // In these cases, the synchronous load would have finished
3378 // before we could connect the signals, so make sure to send the
3379 // completed() signal for the child by hand:
3380 if (url.isEmpty() || url.url() == "about:blank") {
3381 ReadOnlyPart *readOnlyPart = child->m_part;
3382 KHTMLPart *part = dynamic_cast<KHTMLPart *>(readOnlyPart);
3388 if(url.protocol() == "javascript" || url.url() == "about:blank") {
3389 if (!child->m_part->inherits("KHTMLPart"))
3392 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(child->m_part));
3395 if (d->m_doc && p->d->m_doc)
3396 p->d->m_doc->setBaseURL(d->m_doc->baseURL());
3397 if (!url.url().startsWith("about:")) {
3398 p->write(url.path());
3405 else if ( !url.isEmpty() )
3407 //kdDebug( 6050 ) << "opening " << url.url() << " in frame " << child->m_part << endl;
3408 return child->m_part->openURL( url );
3417 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget, const char *widgetName,
3418 QObject *parent, const char *name, const QString &mimetype,
3419 QString &serviceName, QStringList &serviceTypes,
3420 const QStringList ¶ms )
3423 if ( !serviceName.isEmpty() )
3424 constr.append( QString::fromLatin1( "Name == '%1'" ).arg( serviceName ) );
3426 KTrader::OfferList offers = KTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr, QString::null );
3428 if ( offers.isEmpty() )
3431 KService::Ptr service = *offers.begin();
3433 KLibFactory *factory = KLibLoader::self()->factory( QFile::encodeName(service->library()) );
3438 KParts::ReadOnlyPart *res = 0L;
3440 const char *className = "KParts::ReadOnlyPart";
3441 if ( service->serviceTypes().contains( "Browser/View" ) )
3442 className = "Browser/View";
3444 if ( factory->inherits( "KParts::Factory" ) )
3445 res = static_cast<KParts::ReadOnlyPart *>(static_cast<KParts::Factory *>( factory )->createPart( parentWidget, widgetName, parent, name, className, params ));
3447 res = static_cast<KParts::ReadOnlyPart *>(factory->create( parentWidget, widgetName, className ));
3452 serviceTypes = service->serviceTypes();
3453 serviceName = service->name();
3458 KParts::PartManager *KHTMLPart::partManager()
3460 if ( !d->m_manager )
3462 d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this, "khtml part manager" );
3463 d->m_manager->setAllowNestedParts( true );
3464 connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
3465 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
3466 connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ),
3467 this, SLOT( slotPartRemoved( KParts::Part * ) ) );
3470 return d->m_manager;
3475 void KHTMLPart::submitFormAgain()
3477 if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
3478 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 );
3480 delete d->m_submitForm;
3481 d->m_submitForm = 0;
3482 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
3485 void KHTMLPart::submitForm( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
3487 kdDebug(6000) << this << ": KHTMLPart::submitForm target=" << _target << " url=" << url << endl;
3488 KURL u = completeURL( url );
3492 // ### ERROR HANDLING!
3497 // Form security checks
3500 /* This is separate for a reason. It has to be _before_ all script, etc,
3501 * AND I don't want to break anything that uses checkLinkSecurity() in
3505 // This causes crashes... needs to be fixed.
3506 if (!d->m_submitForm && u.protocol() != "https" && u.protocol() != "mailto") {
3507 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
3508 int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
3509 "\nA third party may be able to intercept and view this information."
3510 "\nAre you sure you wish to continue?"),
3512 if (rc == KMessageBox::Cancel)
3514 } else { // Going from nonSSL -> nonSSL
3515 KSSLSettings kss(true);
3516 if (kss.warnOnUnencrypted()) {
3517 int rc = KMessageBox::warningContinueCancel(NULL,
3518 i18n("Warning: Your data is about to be transmitted across the network unencrypted."
3519 "\nAre you sure you wish to continue?"),
3522 "WarnOnUnencryptedForm");
3523 // Move this setting into KSSL instead
3524 KConfig *config = kapp->config();
3525 QString grpNotifMsgs = QString::fromLatin1("Notification Messages");
3526 KConfigGroupSaver saver( config, grpNotifMsgs );
3528 if (!config->readBoolEntry("WarnOnUnencryptedForm", true)) {
3529 config->deleteEntry("WarnOnUnencryptedForm");
3531 kss.setWarnOnUnencrypted(false);
3534 if (rc == KMessageBox::Cancel)
3540 if (!d->m_submitForm && u.protocol() == "mailto") {
3541 int rc = KMessageBox::warningContinueCancel(NULL,
3542 i18n("This site is attempting to submit form data via email."),
3545 "WarnTriedEmailSubmit");
3547 if (rc == KMessageBox::Cancel) {
3552 // End form security checks
3554 #endif // APPLE_CHANGES
3556 QString urlstring = u.url();
3558 if ( urlstring.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
3559 urlstring = KURL::decode_string(urlstring);
3560 d->m_executingJavaScriptFormAction = true;
3561 executeScript( urlstring.right( urlstring.length() - 11) );
3562 d->m_executingJavaScriptFormAction = false;
3567 if (!checkLinkSecurity(u,
3568 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?" ),
3573 KParts::URLArgs args;
3575 if (!d->m_referrer.isEmpty())
3576 args.metaData()["referrer"] = d->m_referrer;
3579 args.metaData().insert("main_frame_request",
3580 parentPart() == 0 ? "TRUE":"FALSE");
3581 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
3582 args.metaData().insert("ssl_activate_warnings", "TRUE");
3584 args.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
3586 // Handle mailto: forms
3587 if (u.protocol() == "mailto") {
3588 // 1) Check for attach= and strip it
3589 QString q = u.query().mid(1);
3590 QStringList nvps = QStringList::split("&", q);
3591 bool triedToAttach = false;
3593 for (QStringList::Iterator nvp = nvps.begin(); nvp != nvps.end(); ++nvp) {
3594 QStringList pair = QStringList::split("=", *nvp);
3595 if (pair.count() >= 2) {
3596 if (pair.first().lower() == "attach") {
3597 nvp = nvps.remove(nvp);
3598 triedToAttach = true;
3605 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");
3610 if (contentType.lower() == "multipart/form-data") {
3611 // FIXME: is this correct? I suspect not
3612 bodyEnc = KURL::encode_string(QString::fromLatin1(formData.data(),
3614 } else if (contentType.lower() == "text/plain") {
3615 // Convention seems to be to decode, and s/&/\n/
3616 QString tmpbody = QString::fromLatin1(formData.data(),
3618 tmpbody.replace(QRegExp("[&]"), "\n");
3619 tmpbody.replace(QRegExp("[+]"), " ");
3620 tmpbody = KURL::decode_string(tmpbody); // Decode the rest of it
3621 bodyEnc = KURL::encode_string(tmpbody); // Recode for the URL
3623 bodyEnc = KURL::encode_string(QString::fromLatin1(formData.data(),
3627 nvps.append(QString("body=%1").arg(bodyEnc));
3632 if ( strcmp( action, "get" ) == 0 ) {
3633 if (u.protocol() != "mailto")
3634 u.setQuery( QString::fromLatin1( formData.data(), formData.size() ) );
3635 args.setDoPost( false );
3638 args.postData = formData;
3639 args.setDoPost( true );
3641 // construct some user headers if necessary
3642 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
3643 args.setContentType( "Content-Type: application/x-www-form-urlencoded" );
3644 else // contentType must be "multipart/form-data"
3645 args.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
3648 if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
3649 if( d->m_submitForm ) {
3650 kdDebug(6000) << "KHTMLPart::submitForm ABORTING!" << endl;
3653 d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
3654 d->m_submitForm->submitAction = action;
3655 d->m_submitForm->submitUrl = url;
3656 d->m_submitForm->submitFormData = formData;
3657 d->m_submitForm->target = _target;
3658 d->m_submitForm->submitContentType = contentType;
3659 d->m_submitForm->submitBoundary = boundary;
3660 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));