summaryrefslogtreecommitdiffstats
path: root/khtml/khtml_part.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'khtml/khtml_part.cpp')
-rw-r--r--khtml/khtml_part.cpp7471
1 files changed, 7471 insertions, 0 deletions
diff --git a/khtml/khtml_part.cpp b/khtml/khtml_part.cpp
new file mode 100644
index 000000000..d5f776078
--- /dev/null
+++ b/khtml/khtml_part.cpp
@@ -0,0 +1,7471 @@
+// -*- c-basic-offset: 2 -*-
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ * 1999 Lars Knoll <knoll@kde.org>
+ * 1999 Antti Koivisto <koivisto@kde.org>
+ * 2000 Simon Hausmann <hausmann@kde.org>
+ * 2000 Stefan Schimanski <1Stein@gmx.de>
+ * 2001-2003 George Staikos <staikos@kde.org>
+ * 2001-2003 Dirk Mueller <mueller@kde.org>
+ * 2000-2005 David Faure <faure@kde.org>
+ * 2002 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+//#define SPEED_DEBUG
+#include "khtml_part.h"
+
+#include "khtml_pagecache.h"
+
+#include "dom/dom_string.h"
+#include "dom/dom_element.h"
+#include "dom/dom_exception.h"
+#include "html/html_documentimpl.h"
+#include "html/html_baseimpl.h"
+#include "html/html_objectimpl.h"
+#include "html/html_miscimpl.h"
+#include "html/html_imageimpl.h"
+#include "html/html_objectimpl.h"
+#include "rendering/render_text.h"
+#include "rendering/render_frames.h"
+#include "rendering/render_layer.h"
+#include "misc/htmlhashes.h"
+#include "misc/loader.h"
+#include "xml/dom2_eventsimpl.h"
+#include "xml/dom2_rangeimpl.h"
+#include "xml/xml_tokenizer.h"
+#include "css/cssstyleselector.h"
+#include "css/csshelper.h"
+using namespace DOM;
+
+#include "khtmlview.h"
+#include <kparts/partmanager.h>
+#include "ecma/kjs_proxy.h"
+#include "ecma/kjs_window.h"
+#include "khtml_settings.h"
+#include "kjserrordlg.h"
+
+#include <kjs/function.h>
+#include <kjs/interpreter.h>
+
+#include "htmlpageinfo.h"
+
+#include <sys/types.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include <config.h>
+
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <kstandarddirs.h>
+#include <kstringhandler.h>
+#include <kio/job.h>
+#include <kio/global.h>
+#include <kio/netaccess.h>
+#include <kprotocolmanager.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kcharsets.h>
+#include <kmessagebox.h>
+#include <kstdaction.h>
+#include <kfiledialog.h>
+#include <ktrader.h>
+#include <kdatastream.h>
+#include <ktempfile.h>
+#include <kglobalsettings.h>
+#include <kurldrag.h>
+#include <kapplication.h>
+#include <kparts/browserinterface.h>
+#if !defined(QT_NO_DRAGANDDROP)
+#include <kmultipledrag.h>
+#endif
+#include "../kutils/kfinddialog.h"
+#include "../kutils/kfind.h"
+
+#include <ksslcertchain.h>
+#include <ksslinfodlg.h>
+
+#include <kfileitem.h>
+#include <kurifilter.h>
+#include <kstatusbar.h>
+#include <kurllabel.h>
+
+#include <qclipboard.h>
+#include <qfile.h>
+#include <qtooltip.h>
+#include <qmetaobject.h>
+#include <private/qucomextra_p.h>
+
+#include "khtmlpart_p.h"
+#include "kpassivepopup.h"
+#include "kpopupmenu.h"
+#include "rendering/render_form.h"
+#include <kwin.h>
+
+#define HINT_UTF8 106
+
+namespace khtml {
+ class PartStyleSheetLoader : public CachedObjectClient
+ {
+ public:
+ PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
+ {
+ m_part = part;
+ m_cachedSheet = dl->requestStyleSheet(url, QString::null, "text/css",
+ true /* "user sheet" */);
+ if (m_cachedSheet)
+ m_cachedSheet->ref( this );
+ }
+ virtual ~PartStyleSheetLoader()
+ {
+ if ( m_cachedSheet ) m_cachedSheet->deref(this);
+ }
+ virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet, const DOM::DOMString &)
+ {
+ if ( m_part )
+ m_part->setUserStyleSheet( sheet.string() );
+
+ delete this;
+ }
+ virtual void error( int, const QString& ) {
+ delete this;
+ }
+ QGuardedPtr<KHTMLPart> m_part;
+ khtml::CachedCSSStyleSheet *m_cachedSheet;
+ };
+}
+
+void khtml::ChildFrame::liveConnectEvent(const unsigned long, const QString & event, const KParts::LiveConnectExtension::ArgList & args)
+{
+ if (!m_part || !m_frame || !m_liveconnect)
+ // hmmm
+ return;
+
+ QString script;
+ script.sprintf("%s(", event.latin1());
+
+ KParts::LiveConnectExtension::ArgList::const_iterator i = args.begin();
+ const KParts::LiveConnectExtension::ArgList::const_iterator argsBegin = i;
+ const KParts::LiveConnectExtension::ArgList::const_iterator argsEnd = args.end();
+
+ for ( ; i != argsEnd; ++i) {
+ if (i != argsBegin)
+ script += ",";
+ if ((*i).first == KParts::LiveConnectExtension::TypeString) {
+ script += "\"";
+ script += QString((*i).second).replace('\\', "\\\\").replace('"', "\\\"");
+ script += "\"";
+ } else
+ script += (*i).second;
+ }
+ script += ")";
+ kdDebug(6050) << "khtml::ChildFrame::liveConnectEvent " << script << endl;
+
+ KHTMLPart * part = ::qt_cast<KHTMLPart *>(m_part->parent());
+ if (!part)
+ return;
+ if (!m_jscript)
+ part->framejScript(m_part);
+ if (m_jscript) {
+ // we have a jscript => a part in an iframe
+ KJS::Completion cmp;
+ m_jscript->evaluate(QString::null, 1, script, 0L, &cmp);
+ } else
+ part->executeScript(m_frame->element(), script);
+}
+
+KHTMLFrameList::Iterator KHTMLFrameList::find( const QString &name )
+{
+ Iterator it = begin();
+ const Iterator e = end();
+
+ for (; it!=e; ++it )
+ if ( (*it)->m_name==name )
+ break;
+
+ return it;
+}
+
+KHTMLPart::KHTMLPart( QWidget *parentWidget, const char *widgetname, QObject *parent, const char *name, GUIProfile prof )
+: KParts::ReadOnlyPart( parent, name )
+{
+ d = 0;
+ KHTMLFactory::registerPart( this );
+ setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
+ // TODO KDE4 - don't load plugins yet
+ //setInstance( KHTMLFactory::instance(), false );
+ init( new KHTMLView( this, parentWidget, widgetname ), prof );
+}
+
+KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, const char *name, GUIProfile prof )
+: KParts::ReadOnlyPart( parent, name )
+{
+ d = 0;
+ KHTMLFactory::registerPart( this );
+ setInstance( KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
+ // TODO KDE4 - don't load plugins yet
+ //setInstance( KHTMLFactory::instance(), false );
+ assert( view );
+ init( view, prof );
+}
+
+void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
+{
+ if ( prof == DefaultGUI )
+ setXMLFile( "khtml.rc" );
+ else if ( prof == BrowserViewGUI )
+ setXMLFile( "khtml_browser.rc" );
+
+ d = new KHTMLPartPrivate(parent());
+
+ d->m_view = view;
+ setWidget( d->m_view );
+
+ d->m_guiProfile = prof;
+ d->m_extension = new KHTMLPartBrowserExtension( this, "KHTMLBrowserExtension" );
+ d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
+ d->m_statusBarExtension = new KParts::StatusBarExtension( this );
+ d->m_statusBarIconLabel = 0L;
+ d->m_statusBarPopupLabel = 0L;
+ d->m_openableSuppressedPopups = 0;
+
+ d->m_bSecurityInQuestion = false;
+ d->m_paLoadImages = 0;
+ d->m_paDebugScript = 0;
+ d->m_bMousePressed = false;
+ d->m_bRightMousePressed = false;
+ d->m_bCleared = false;
+ d->m_paViewDocument = new KAction( i18n( "View Do&cument Source" ), CTRL + Key_U, this, SLOT( slotViewDocumentSource() ), actionCollection(), "viewDocumentSource" );
+ d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), 0, this, SLOT( slotViewFrameSource() ), actionCollection(), "viewFrameSource" );
+ d->m_paViewInfo = new KAction( i18n( "View Document Information" ), CTRL+Key_I, this, SLOT( slotViewPageInfo() ), actionCollection(), "viewPageInfo" );
+ d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), 0, this, SLOT( slotSaveBackground() ), actionCollection(), "saveBackground" );
+ d->m_paSaveDocument = KStdAction::saveAs( this, SLOT( slotSaveDocument() ), actionCollection(), "saveDocument" );
+ if ( parentPart() )
+ d->m_paSaveDocument->setShortcut( KShortcut() ); // avoid clashes
+ d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), 0, this, SLOT( slotSaveFrame() ), actionCollection(), "saveFrame" );
+ d->m_paSecurity = new KAction( i18n( "Security..." ), "decrypted", 0, this, SLOT( slotSecurity() ), actionCollection(), "security" );
+ d->m_paSecurity->setWhatsThis( i18n( "Security Settings<p>"
+ "Shows the certificate of the displayed page. Only "
+ "pages that have been transmitted using a secure, encrypted connection have a "
+ "certificate.<p> "
+ "Hint: If the image shows a closed lock, the page has been transmitted over a "
+ "secure connection.") );
+ d->m_paDebugRenderTree = new KAction( i18n( "Print Rendering Tree to STDOUT" ), ALT + CTRL + SHIFT + Key_A, this, SLOT( slotDebugRenderTree() ), actionCollection(), "debugRenderTree" );
+ d->m_paDebugDOMTree = new KAction( i18n( "Print DOM Tree to STDOUT" ), ALT + CTRL + SHIFT + Key_D, this, SLOT( slotDebugDOMTree() ), actionCollection(), "debugDOMTree" );
+ d->m_paStopAnimations = new KAction( i18n( "Stop Animated Images" ), 0, this, SLOT( slotStopAnimations() ), actionCollection(), "stopAnimations" );
+
+ d->m_paSetEncoding = new KActionMenu( i18n( "Set &Encoding" ), "charset", actionCollection(), "setEncoding" );
+ d->m_paSetEncoding->setDelayed( false );
+
+ d->m_automaticDetection = new KPopupMenu( 0L );
+
+ d->m_automaticDetection->insertItem( i18n( "Semi-Automatic" ), 0 );
+ d->m_automaticDetection->insertItem( i18n( "Arabic" ), 1 );
+ d->m_automaticDetection->insertItem( i18n( "Baltic" ), 2 );
+ d->m_automaticDetection->insertItem( i18n( "Central European" ), 3 );
+ //d->m_automaticDetection->insertItem( i18n( "Chinese" ), 4 );
+ d->m_automaticDetection->insertItem( i18n( "Greek" ), 5 );
+ d->m_automaticDetection->insertItem( i18n( "Hebrew" ), 6 );
+ d->m_automaticDetection->insertItem( i18n( "Japanese" ), 7 );
+ //d->m_automaticDetection->insertItem( i18n( "Korean" ), 8 );
+ d->m_automaticDetection->insertItem( i18n( "Russian" ), 9 );
+ //d->m_automaticDetection->insertItem( i18n( "Thai" ), 10 );
+ d->m_automaticDetection->insertItem( i18n( "Turkish" ), 11 );
+ d->m_automaticDetection->insertItem( i18n( "Ukrainian" ), 12 );
+ //d->m_automaticDetection->insertItem( i18n( "Unicode" ), 13 );
+ d->m_automaticDetection->insertItem( i18n( "Western European" ), 14 );
+
+ connect( d->m_automaticDetection, SIGNAL( activated( int ) ), this, SLOT( slotAutomaticDetectionLanguage( int ) ) );
+
+ d->m_paSetEncoding->popupMenu()->insertItem( i18n( "Automatic Detection" ), d->m_automaticDetection, 0 );
+
+ d->m_paSetEncoding->insert( new KActionSeparator( actionCollection() ) );
+
+
+ d->m_manualDetection = new KSelectAction( i18n( "short for Manual Detection", "Manual" ), 0, this, SLOT( slotSetEncoding() ), actionCollection(), "manualDetection" );
+ QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames();
+ d->m_manualDetection->setItems( encodings );
+ d->m_manualDetection->setCurrentItem( -1 );
+ d->m_paSetEncoding->insert( d->m_manualDetection );
+
+
+ KConfig *config = KGlobal::config();
+ if ( config->hasGroup( "HTML Settings" ) ) {
+ config->setGroup( "HTML Settings" );
+ khtml::Decoder::AutoDetectLanguage language;
+ QCString name = QTextCodec::codecForLocale()->name();
+ name = name.lower();
+
+ if ( name == "cp1256" || name == "iso-8859-6" ) {
+ language = khtml::Decoder::Arabic;
+ }
+ else if ( name == "cp1257" || name == "iso-8859-13" || name == "iso-8859-4" ) {
+ language = khtml::Decoder::Baltic;
+ }
+ else if ( name == "cp1250" || name == "ibm852" || name == "iso-8859-2" || name == "iso-8859-3" ) {
+ language = khtml::Decoder::CentralEuropean;
+ }
+ else if ( name == "cp1251" || name == "koi8-r" || name == "iso-8859-5" ) {
+ language = khtml::Decoder::Russian;
+ }
+ else if ( name == "koi8-u" ) {
+ language = khtml::Decoder::Ukrainian;
+ }
+ else if ( name == "cp1253" || name == "iso-8859-7" ) {
+ language = khtml::Decoder::Greek;
+ }
+ else if ( name == "cp1255" || name == "iso-8859-8" || name == "iso-8859-8-i" ) {
+ language = khtml::Decoder::Hebrew;
+ }
+ else if ( name == "jis7" || name == "eucjp" || name == "sjis" ) {
+ language = khtml::Decoder::Japanese;
+ }
+ else if ( name == "cp1254" || name == "iso-8859-9" ) {
+ language = khtml::Decoder::Turkish;
+ }
+ else if ( name == "cp1252" || name == "iso-8859-1" || name == "iso-8859-15" ) {
+ language = khtml::Decoder::WesternEuropean;
+ }
+ else
+ language = khtml::Decoder::SemiautomaticDetection;
+
+ int _id = config->readNumEntry( "AutomaticDetectionLanguage", language );
+ d->m_automaticDetection->setItemChecked( _id, true );
+ d->m_paSetEncoding->popupMenu()->setItemChecked( 0, true );
+
+ d->m_autoDetectLanguage = static_cast< khtml::Decoder::AutoDetectLanguage >( _id );
+ }
+
+
+ d->m_paUseStylesheet = new KSelectAction( i18n( "Use S&tylesheet"), 0, this, SLOT( slotUseStylesheet() ), actionCollection(), "useStylesheet" );
+
+ if ( prof == BrowserViewGUI ) {
+ d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, i18n(
+ "Enlarge Font" ), "viewmag+", "CTRL++;CTRL+=", this,
+ SLOT( slotIncZoomFast() ), actionCollection(), "incFontSizes" );
+ d->m_paIncZoomFactor->setWhatsThis( i18n( "Enlarge Font<p>"
+ "Make the font in this window bigger. "
+ "Click and hold down the mouse button for a menu with all available font sizes." ) );
+ d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, i18n(
+ "Shrink Font" ), "viewmag-", CTRL + Key_Minus, this,
+ SLOT( slotDecZoomFast() ), actionCollection(), "decFontSizes" );
+ d->m_paDecZoomFactor->setWhatsThis( i18n( "Shrink Font<p>"
+ "Make the font in this window smaller. "
+ "Click and hold down the mouse button for a menu with all available font sizes." ) );
+ }
+
+ d->m_paFind = KStdAction::find( this, SLOT( slotFind() ), actionCollection(), "find" );
+ d->m_paFind->setWhatsThis( i18n( "Find text<p>"
+ "Shows a dialog that allows you to find text on the displayed page." ) );
+
+ d->m_paFindNext = KStdAction::findNext( this, SLOT( slotFindNext() ), actionCollection(), "findNext" );
+ d->m_paFindNext->setWhatsThis( i18n( "Find next<p>"
+ "Find the next occurrence of the text that you "
+ "have found using the <b>Find Text</b> function" ) );
+
+ d->m_paFindPrev = KStdAction::findPrev( this, SLOT( slotFindPrev() ), actionCollection(), "findPrevious" );
+ d->m_paFindPrev->setWhatsThis( i18n( "Find previous<p>"
+ "Find the previous occurrence of the text that you "
+ "have found using the <b>Find Text</b> function" ) );
+
+ d->m_paFindAheadText = new KAction( i18n("Find Text as You Type"), KShortcut( '/' ), this, SLOT( slotFindAheadText()),
+ actionCollection(), "findAheadText");
+ d->m_paFindAheadLinks = new KAction( i18n("Find Links as You Type"), KShortcut( '\'' ), this, SLOT( slotFindAheadLink()),
+ actionCollection(), "findAheadLink");
+ d->m_paFindAheadText->setEnabled( false );
+ d->m_paFindAheadLinks->setEnabled( false );
+
+ if ( parentPart() )
+ {
+ d->m_paFind->setShortcut( KShortcut() ); // avoid clashes
+ d->m_paFindNext->setShortcut( KShortcut() ); // avoid clashes
+ d->m_paFindPrev->setShortcut( KShortcut() ); // avoid clashes
+ d->m_paFindAheadText->setShortcut( KShortcut());
+ d->m_paFindAheadLinks->setShortcut( KShortcut());
+ }
+
+ d->m_paPrintFrame = new KAction( i18n( "Print Frame..." ), "frameprint", 0, this, SLOT( slotPrintFrame() ), actionCollection(), "printFrame" );
+ d->m_paPrintFrame->setWhatsThis( i18n( "Print Frame<p>"
+ "Some pages have several frames. To print only a single frame, click "
+ "on it and then use this function." ) );
+
+ d->m_paSelectAll = KStdAction::selectAll( this, SLOT( slotSelectAll() ), actionCollection(), "selectAll" );
+ if ( parentPart() )
+ d->m_paSelectAll->setShortcut( KShortcut() ); // avoid clashes
+
+ d->m_paToggleCaretMode = new KToggleAction(i18n("Toggle Caret Mode"),
+ Key_F7, this, SLOT(slotToggleCaretMode()),
+ actionCollection(), "caretMode");
+ d->m_paToggleCaretMode->setChecked(isCaretMode());
+ if (parentPart())
+ d->m_paToggleCaretMode->setShortcut(KShortcut()); // avoid clashes
+
+ // set the default java(script) flags according to the current host.
+ d->m_bOpenMiddleClick = d->m_settings->isOpenMiddleClickEnabled();
+ d->m_bBackRightClick = d->m_settings->isBackRightClickEnabled();
+ d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
+ setDebugScript( d->m_settings->isJavaScriptDebugEnabled() );
+ d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
+ d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
+
+ // Set the meta-refresh flag...
+ d->m_metaRefreshEnabled = d->m_settings->isAutoDelayedActionsEnabled ();
+
+ connect( view, SIGNAL( zoomView( int ) ), SLOT( slotZoomView( int ) ) );
+
+ connect( this, SIGNAL( completed() ),
+ this, SLOT( updateActions() ) );
+ connect( this, SIGNAL( completed( bool ) ),
+ this, SLOT( updateActions() ) );
+ connect( this, SIGNAL( started( KIO::Job * ) ),
+ this, SLOT( updateActions() ) );
+
+ d->m_popupMenuXML = KXMLGUIFactory::readConfigFile( locate( "data", "khtml/khtml_popupmenu.rc", KHTMLFactory::instance() ) );
+
+ connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
+ this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
+ connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
+ this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
+ connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
+ this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
+
+ connect ( &d->m_progressUpdateTimer, SIGNAL( timeout() ), this, SLOT( slotProgressUpdate() ) );
+
+ findTextBegin(); //reset find variables
+
+ connect( &d->m_redirectionTimer, SIGNAL( timeout() ),
+ this, SLOT( slotRedirect() ) );
+
+ d->m_dcopobject = new KHTMLPartIface(this);
+
+ // TODO KDE4 - load plugins now (see also the constructors)
+ //if ( prof == BrowserViewGUI && !parentPart() )
+ // loadPlugins( partObject(), this, instance() );
+
+ // "khtml" catalog does not exist, our translations are in kdelibs.
+ // removing this catalog from KGlobal::locale() prevents problems
+ // with changing the language in applications at runtime -Thomas Reitelbach
+ KGlobal::locale()->removeCatalogue("khtml");
+}
+
+KHTMLPart::~KHTMLPart()
+{
+ //kdDebug(6050) << "KHTMLPart::~KHTMLPart " << this << endl;
+
+ KConfig *config = KGlobal::config();
+ config->setGroup( "HTML Settings" );
+ config->writeEntry( "AutomaticDetectionLanguage", d->m_autoDetectLanguage );
+
+ delete d->m_automaticDetection;
+ delete d->m_manualDetection;
+
+ slotWalletClosed();
+ if (!parentPart()) { // only delete it if the top khtml_part closes
+ removeJSErrorExtension();
+ delete d->m_statusBarPopupLabel;
+ }
+
+ d->m_find = 0; // deleted by its parent, the view.
+
+ if ( d->m_manager )
+ {
+ d->m_manager->setActivePart( 0 );
+ // We specify "this" as parent qobject for d->manager, so no need to delete it.
+ }
+
+ stopAutoScroll();
+ d->m_redirectionTimer.stop();
+
+ if (!d->m_bComplete)
+ closeURL();
+
+ disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
+ this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
+ disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
+ this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
+ disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
+ this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
+
+ clear();
+
+ if ( d->m_view )
+ {
+ d->m_view->hide();
+ d->m_view->viewport()->hide();
+ d->m_view->m_part = 0;
+ }
+
+ // Have to delete this here since we forward declare it in khtmlpart_p and
+ // at least some compilers won't call the destructor in this case.
+ delete d->m_jsedlg;
+ d->m_jsedlg = 0;
+
+ if (!parentPart()) // only delete d->m_frame if the top khtml_part closes
+ delete d->m_frame;
+ delete d; d = 0;
+ KHTMLFactory::deregisterPart( this );
+}
+
+bool KHTMLPart::restoreURL( const KURL &url )
+{
+ kdDebug( 6050 ) << "KHTMLPart::restoreURL " << url.url() << endl;
+
+ d->m_redirectionTimer.stop();
+
+ /*
+ * That's not a good idea as it will call closeURL() on all
+ * child frames, preventing them from further loading. This
+ * method gets called from restoreState() in case of a full frameset
+ * restoral, and restoreState() calls closeURL() before restoring
+ * anyway.
+ kdDebug( 6050 ) << "closing old URL" << endl;
+ closeURL();
+ */
+
+ d->m_bComplete = false;
+ d->m_bLoadEventEmitted = false;
+ d->m_workingURL = url;
+
+ // set the java(script) flags according to the current host.
+ d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
+ setDebugScript( KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
+ d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
+ d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
+
+ m_url = url;
+
+ d->m_restoreScrollPosition = true;
+ disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
+ connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
+
+ KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &)));
+
+ emit started( 0L );
+
+ return true;
+}
+
+
+bool KHTMLPart::openURL( const KURL &url )
+{
+ kdDebug( 6050 ) << "KHTMLPart(" << this << ")::openURL " << url.url() << endl;
+
+ d->m_redirectionTimer.stop();
+
+ // check to see if this is an "error://" URL. This is caused when an error
+ // occurs before this part was loaded (e.g. KonqRun), and is passed to
+ // khtmlpart so that it can display the error.
+ if ( url.protocol() == "error" && url.hasSubURL() ) {
+ closeURL();
+
+ if( d->m_bJScriptEnabled )
+ d->m_statusBarText[BarOverrideText] = d->m_statusBarText[BarDefaultText] = QString::null;
+
+ /**
+ * The format of the error url is that two variables are passed in the query:
+ * error = int kio error code, errText = QString error text from kio
+ * and the URL where the error happened is passed as a sub URL.
+ */
+ KURL::List urls = KURL::split( url );
+ //kdDebug(6050) << "Handling error URL. URL count:" << urls.count() << endl;
+
+ if ( urls.count() > 1 ) {
+ KURL mainURL = urls.first();
+ int error = mainURL.queryItem( "error" ).toInt();
+ // error=0 isn't a valid error code, so 0 means it's missing from the URL
+ if ( error == 0 ) error = KIO::ERR_UNKNOWN;
+ QString errorText = mainURL.queryItem( "errText", HINT_UTF8 );
+ urls.pop_front();
+ d->m_workingURL = KURL::join( urls );
+ //kdDebug(6050) << "Emitting fixed URL " << d->m_workingURL.prettyURL() << endl;
+ emit d->m_extension->setLocationBarURL( d->m_workingURL.prettyURL() );
+ htmlError( error, errorText, d->m_workingURL );
+ return true;
+ }
+ }
+
+ if (!parentPart()) { // only do it for toplevel part
+ QString host = url.isLocalFile() ? "localhost" : url.host();
+ QString userAgent = KProtocolManager::userAgentForHost(host);
+ if (userAgent != KProtocolManager::userAgentForHost(QString::null)) {
+ if (!d->m_statusBarUALabel) {
+ d->m_statusBarUALabel = new KURLLabel(d->m_statusBarExtension->statusBar());
+ d->m_statusBarUALabel->setFixedHeight(instance()->iconLoader()->currentSize(KIcon::Small));
+ d->m_statusBarUALabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ d->m_statusBarUALabel->setUseCursor(false);
+ d->m_statusBarExtension->addStatusBarItem(d->m_statusBarUALabel, 0, false);
+ d->m_statusBarUALabel->setPixmap(SmallIcon("agent", instance()));
+ } else {
+ QToolTip::remove(d->m_statusBarUALabel);
+ }
+ QToolTip::add(d->m_statusBarUALabel, i18n("The fake user-agent '%1' is in use.").arg(userAgent));
+ } else if (d->m_statusBarUALabel) {
+ d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarUALabel);
+ delete d->m_statusBarUALabel;
+ d->m_statusBarUALabel = 0L;
+ }
+ }
+
+ KParts::URLArgs args( d->m_extension->urlArgs() );
+
+ // in case
+ // a) we have no frameset (don't test m_frames.count(), iframes get in there)
+ // b) the url is identical with the currently displayed one (except for the htmlref!)
+ // c) the url request is not a POST operation and
+ // d) the caller did not request to reload the page
+ // e) there was no HTTP redirection meanwhile (testcase: webmin's software/tree.cgi)
+ // => we don't reload the whole document and
+ // we just jump to the requested html anchor
+ bool isFrameSet = false;
+ if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
+ HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
+ isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET);
+ }
+
+ if ( url.hasRef() && !isFrameSet )
+ {
+ bool noReloadForced = !args.reload && !args.redirectedRequest() && !args.doPost();
+ if (noReloadForced && urlcmp( url.url(), m_url.url(), true, true ))
+ {
+ kdDebug( 6050 ) << "KHTMLPart::openURL, jumping to anchor. m_url = " << url.url() << endl;
+ m_url = url;
+ emit started( 0L );
+
+ if ( !gotoAnchor( url.encodedHtmlRef()) )
+ gotoAnchor( url.htmlRef() );
+
+ d->m_bComplete = true;
+ if (d->m_doc)
+ d->m_doc->setParsing(false);
+
+ kdDebug( 6050 ) << "completed..." << endl;
+ emit completed();
+ return true;
+ }
+ }
+
+ // Save offset of viewport when page is reloaded to be compliant
+ // to every other capable browser out there.
+ if (args.reload) {
+ args.xOffset = d->m_view->contentsX();
+ args.yOffset = d->m_view->contentsY();
+ d->m_extension->setURLArgs(args);
+ }
+
+ if (!d->m_restored)
+ closeURL();
+
+ d->m_restoreScrollPosition = d->m_restored;
+ disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
+ connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
+
+ // 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
+ // data arrives) (Simon)
+ m_url = url;
+ if(m_url.protocol().startsWith( "http" ) && !m_url.host().isEmpty() &&
+ m_url.path().isEmpty()) {
+ m_url.setPath("/");
+ emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
+ }
+ // copy to m_workingURL after fixing m_url above
+ d->m_workingURL = m_url;
+
+ args.metaData().insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" );
+ args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
+ args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
+ args.metaData().insert("PropagateHttpHeader", "true");
+ args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" );
+ args.metaData().insert("ssl_activate_warnings", "TRUE" );
+ args.metaData().insert("cross-domain", toplevelURL().url());
+
+ if (d->m_restored)
+ {
+ args.metaData().insert("referrer", d->m_pageReferrer);
+ d->m_cachePolicy = KIO::CC_Cache;
+ }
+ else if (args.reload)
+ d->m_cachePolicy = KIO::CC_Reload;
+ else
+ d->m_cachePolicy = KProtocolManager::cacheControl();
+
+ if ( args.doPost() && (m_url.protocol().startsWith("http")) )
+ {
+ d->m_job = KIO::http_post( m_url, args.postData, false );
+ d->m_job->addMetaData("content-type", args.contentType() );
+ }
+ else
+ {
+ d->m_job = KIO::get( m_url, false, false );
+ d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
+ }
+
+ if (widget())
+ d->m_job->setWindow(widget()->topLevelWidget());
+ d->m_job->addMetaData(args.metaData());
+
+ connect( d->m_job, SIGNAL( result( KIO::Job* ) ),
+ SLOT( slotFinished( KIO::Job* ) ) );
+ connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
+ SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
+ connect ( d->m_job, SIGNAL( infoMessage( KIO::Job*, const QString& ) ),
+ SLOT( slotInfoMessage(KIO::Job*, const QString& ) ) );
+ connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KURL& ) ),
+ SLOT( slotRedirection(KIO::Job*, const KURL&) ) );
+
+ d->m_bComplete = false;
+ d->m_bLoadEventEmitted = false;
+
+ // delete old status bar msg's from kjs (if it _was_ activated on last URL)
+ if( d->m_bJScriptEnabled )
+ d->m_statusBarText[BarOverrideText] = d->m_statusBarText[BarDefaultText] = QString::null;
+
+ // set the javascript flags according to the current url
+ d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
+ setDebugScript( KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
+ d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
+ d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
+
+
+ connect( d->m_job, SIGNAL( speed( KIO::Job*, unsigned long ) ),
+ this, SLOT( slotJobSpeed( KIO::Job*, unsigned long ) ) );
+
+ connect( d->m_job, SIGNAL( percent( KIO::Job*, unsigned long ) ),
+ this, SLOT( slotJobPercent( KIO::Job*, unsigned long ) ) );
+
+ connect( d->m_job, SIGNAL( result( KIO::Job* ) ),
+ this, SLOT( slotJobDone( KIO::Job* ) ) );
+
+ d->m_jobspeed = 0;
+
+ // If this was an explicit reload and the user style sheet should be used,
+ // do a stat to see whether the stylesheet was changed in the meanwhile.
+ if ( args.reload && !settings()->userStyleSheet().isEmpty() ) {
+ KURL url( settings()->userStyleSheet() );
+ KIO::StatJob *job = KIO::stat( url, false /* don't show progress */ );
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ this, SLOT( slotUserSheetStatDone( KIO::Job * ) ) );
+ }
+ emit started( 0L );
+
+ return true;
+}
+
+bool KHTMLPart::closeURL()
+{
+ if ( d->m_job )
+ {
+ KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
+ d->m_job->kill();
+ d->m_job = 0;
+ }
+
+ if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
+ HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
+
+ if ( hdoc->body() && d->m_bLoadEventEmitted ) {
+ hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false );
+ if ( d->m_doc )
+ d->m_doc->updateRendering();
+ d->m_bLoadEventEmitted = false;
+ }
+ }
+
+ d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
+ d->m_bLoadEventEmitted = true; // don't want that one either
+ d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
+
+ disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
+
+ KHTMLPageCache::self()->cancelFetch(this);
+ if ( d->m_doc && d->m_doc->parsing() )
+ {
+ kdDebug( 6050 ) << " was still parsing... calling end " << endl;
+ slotFinishedParsing();
+ d->m_doc->setParsing(false);
+ }
+
+ if ( !d->m_workingURL.isEmpty() )
+ {
+ // Aborted before starting to render
+ kdDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << m_url.prettyURL() << endl;
+ emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
+ }
+
+ d->m_workingURL = KURL();
+
+ if ( d->m_doc && d->m_doc->docLoader() )
+ khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() );
+
+ // tell all subframes to stop as well
+ {
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ {
+ if ( (*it)->m_run )
+ (*it)->m_run->abort();
+ if ( !( *it )->m_part.isNull() )
+ ( *it )->m_part->closeURL();
+ }
+ }
+ // tell all objects to stop as well
+ {
+ ConstFrameIt it = d->m_objects.begin();
+ const ConstFrameIt end = d->m_objects.end();
+ for (; it != end; ++it)
+ {
+ if ( !( *it )->m_part.isNull() )
+ ( *it )->m_part->closeURL();
+ }
+ }
+ // Stop any started redirections as well!! (DA)
+ if ( d && d->m_redirectionTimer.isActive() )
+ d->m_redirectionTimer.stop();
+
+ // null node activated.
+ emit nodeActivated(Node());
+
+ // make sure before clear() runs, we pop out of a dialog's message loop
+ if ( d->m_view )
+ d->m_view->closeChildDialogs();
+
+ return true;
+}
+
+DOM::HTMLDocument KHTMLPart::htmlDocument() const
+{
+ if (d->m_doc && d->m_doc->isHTMLDocument())
+ return static_cast<HTMLDocumentImpl*>(d->m_doc);
+ else
+ return static_cast<HTMLDocumentImpl*>(0);
+}
+
+DOM::Document KHTMLPart::document() const
+{
+ return d->m_doc;
+}
+
+QString KHTMLPart::documentSource() const
+{
+ QString sourceStr;
+ if ( !( m_url.isLocalFile() ) && KHTMLPageCache::self()->isComplete( d->m_cacheId ) )
+ {
+ QByteArray sourceArray;
+ QDataStream dataStream( sourceArray, IO_WriteOnly );
+ KHTMLPageCache::self()->saveData( d->m_cacheId, &dataStream );
+ QTextStream stream( sourceArray, IO_ReadOnly );
+ stream.setCodec( QTextCodec::codecForName( encoding().latin1() ) );
+ sourceStr = stream.read();
+ } else
+ {
+ QString tmpFile;
+ if( KIO::NetAccess::download( m_url, tmpFile, NULL ) )
+ {
+ QFile f( tmpFile );
+ if ( f.open( IO_ReadOnly ) )
+ {
+ QTextStream stream( &f );
+ stream.setCodec( QTextCodec::codecForName( encoding().latin1() ) );
+ sourceStr = stream.read();
+ f.close();
+ }
+ KIO::NetAccess::removeTempFile( tmpFile );
+ }
+ }
+
+ return sourceStr;
+}
+
+
+KParts::BrowserExtension *KHTMLPart::browserExtension() const
+{
+ return d->m_extension;
+}
+
+KParts::BrowserHostExtension *KHTMLPart::browserHostExtension() const
+{
+ return d->m_hostExtension;
+}
+
+KHTMLView *KHTMLPart::view() const
+{
+ return d->m_view;
+}
+
+void KHTMLPart::setStatusMessagesEnabled( bool enable )
+{
+ d->m_statusMessagesEnabled = enable;
+}
+
+KJS::Interpreter *KHTMLPart::jScriptInterpreter()
+{
+ KJSProxy *proxy = jScript();
+ if (!proxy || proxy->paused())
+ return 0;
+
+ return proxy->interpreter();
+}
+
+bool KHTMLPart::statusMessagesEnabled() const
+{
+ return d->m_statusMessagesEnabled;
+}
+
+void KHTMLPart::setJScriptEnabled( bool enable )
+{
+ if ( !enable && jScriptEnabled() && d->m_frame && d->m_frame->m_jscript ) {
+ d->m_frame->m_jscript->clear();
+ }
+ d->m_bJScriptForce = enable;
+ d->m_bJScriptOverride = true;
+}
+
+bool KHTMLPart::jScriptEnabled() const
+{
+ if(onlyLocalReferences()) return false;
+
+ if ( d->m_bJScriptOverride )
+ return d->m_bJScriptForce;
+ return d->m_bJScriptEnabled;
+}
+
+void KHTMLPart::setMetaRefreshEnabled( bool enable )
+{
+ d->m_metaRefreshEnabled = enable;
+}
+
+bool KHTMLPart::metaRefreshEnabled() const
+{
+ return d->m_metaRefreshEnabled;
+}
+
+// Define this to disable dlopening kjs_html, when directly linking to it.
+// You need to edit khtml/Makefile.am to add ./ecma/libkjs_html.la to LIBADD
+// and to edit khtml/ecma/Makefile.am to s/kjs_html/libkjs_html/, remove libkhtml from LIBADD,
+// remove LDFLAGS line, and replace kde_module with either lib (shared) or noinst (static)
+// Also, change the order of "ecma" and "." in khtml's SUBDIRS line.
+// OK - that's the default now, use the opposite of the above instructions to go back
+// to "dlopening it" - but it breaks exception catching in kjs_binding.cpp
+#define DIRECT_LINKAGE_TO_ECMA
+
+#ifdef DIRECT_LINKAGE_TO_ECMA
+extern "C" { KJSProxy *kjs_html_init(khtml::ChildFrame * childframe); }
+#endif
+
+static bool createJScript(khtml::ChildFrame *frame)
+{
+#ifndef DIRECT_LINKAGE_TO_ECMA
+ KLibrary *lib = KLibLoader::self()->library("kjs_html");
+ if ( !lib ) {
+ setJScriptEnabled( false );
+ return false;
+ }
+ // look for plain C init function
+ void *sym = lib->symbol("kjs_html_init");
+ if ( !sym ) {
+ lib->unload();
+ setJScriptEnabled( false );
+ return false;
+ }
+ typedef KJSProxy* (*initFunction)(khtml::ChildFrame *);
+ initFunction initSym = (initFunction) sym;
+ frame->m_jscript = (*initSym)(d->m_frame);
+ frame->m_kjs_lib = lib;
+#else
+ frame->m_jscript = kjs_html_init(frame);
+ // frame->m_kjs_lib remains 0L.
+#endif
+ return true;
+}
+
+KJSProxy *KHTMLPart::jScript()
+{
+ if (!jScriptEnabled()) return 0;
+
+ if ( !d->m_frame ) {
+ KHTMLPart * p = parentPart();
+ if (!p) {
+ d->m_frame = new khtml::ChildFrame;
+ d->m_frame->m_part = this;
+ } else {
+ ConstFrameIt it = p->d->m_frames.begin();
+ const ConstFrameIt end = p->d->m_frames.end();
+ for (; it != end; ++it)
+ if ((*it)->m_part.operator->() == this) {
+ d->m_frame = *it;
+ break;
+ }
+ }
+ if ( !d->m_frame )
+ return 0;
+ }
+ if ( !d->m_frame->m_jscript )
+ if (!createJScript(d->m_frame))
+ return 0;
+ if (d->m_bJScriptDebugEnabled)
+ d->m_frame->m_jscript->setDebugEnabled(true);
+
+ return d->m_frame->m_jscript;
+}
+
+QVariant KHTMLPart::crossFrameExecuteScript(const QString& target, const QString& script)
+{
+ KHTMLPart* destpart = this;
+
+ QString trg = target.lower();
+
+ if (target == "_top") {
+ while (destpart->parentPart())
+ destpart = destpart->parentPart();
+ }
+ else if (target == "_parent") {
+ if (parentPart())
+ destpart = parentPart();
+ }
+ else if (target == "_self" || target == "_blank") {
+ // we always allow these
+ }
+ else {
+ destpart = findFrame(target);
+ if (!destpart)
+ destpart = this;
+ }
+
+ // easy way out?
+ if (destpart == this)
+ return executeScript(DOM::Node(), script);
+
+ // now compare the domains
+ if (destpart->checkFrameAccess(this))
+ return destpart->executeScript(DOM::Node(), script);
+
+ // eww, something went wrong. better execute it in our frame
+ return executeScript(DOM::Node(), script);
+}
+
+//Enable this to see all JS scripts being executed
+//#define KJS_VERBOSE
+
+KJSErrorDlg *KHTMLPart::jsErrorExtension() {
+ if (!d->m_settings->jsErrorsEnabled()) {
+ return 0L;
+ }
+
+ if (parentPart()) {
+ return parentPart()->jsErrorExtension();
+ }
+
+ if (!d->m_statusBarJSErrorLabel) {
+ d->m_statusBarJSErrorLabel = new KURLLabel(d->m_statusBarExtension->statusBar());
+ d->m_statusBarJSErrorLabel->setFixedHeight(instance()->iconLoader()->currentSize(KIcon::Small));
+ d->m_statusBarJSErrorLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ d->m_statusBarJSErrorLabel->setUseCursor(false);
+ d->m_statusBarExtension->addStatusBarItem(d->m_statusBarJSErrorLabel, 0, false);
+ QToolTip::add(d->m_statusBarJSErrorLabel, i18n("This web page contains coding errors."));
+ d->m_statusBarJSErrorLabel->setPixmap(SmallIcon("bug", instance()));
+ connect(d->m_statusBarJSErrorLabel, SIGNAL(leftClickedURL()), SLOT(launchJSErrorDialog()));
+ connect(d->m_statusBarJSErrorLabel, SIGNAL(rightClickedURL()), SLOT(jsErrorDialogContextMenu()));
+ }
+ if (!d->m_jsedlg) {
+ d->m_jsedlg = new KJSErrorDlg;
+ d->m_jsedlg->setURL(m_url.prettyURL());
+ if (KGlobalSettings::showIconsOnPushButtons()) {
+ d->m_jsedlg->_clear->setIconSet(SmallIconSet("locationbar_erase"));
+ d->m_jsedlg->_close->setIconSet(SmallIconSet("fileclose"));
+ }
+ }
+ return d->m_jsedlg;
+}
+
+void KHTMLPart::removeJSErrorExtension() {
+ if (parentPart()) {
+ parentPart()->removeJSErrorExtension();
+ return;
+ }
+ if (d->m_statusBarJSErrorLabel != 0) {
+ d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarJSErrorLabel );
+ delete d->m_statusBarJSErrorLabel;
+ d->m_statusBarJSErrorLabel = 0;
+ }
+ delete d->m_jsedlg;
+ d->m_jsedlg = 0;
+}
+
+void KHTMLPart::disableJSErrorExtension() {
+ removeJSErrorExtension();
+ // These two lines are really kind of hacky, and it sucks to do this inside
+ // KHTML but I don't know of anything that's reasonably easy as an alternative
+ // right now. It makes me wonder if there should be a more clean way to
+ // contact all running "KHTML" instance as opposed to Konqueror instances too.
+ d->m_settings->setJSErrorsEnabled(false);
+ DCOPClient::mainClient()->send("konqueror*", "KonquerorIface", "reparseConfiguration()", QByteArray());
+}
+
+void KHTMLPart::jsErrorDialogContextMenu() {
+ KPopupMenu *m = new KPopupMenu(0L);
+ m->insertItem(i18n("&Hide Errors"), this, SLOT(removeJSErrorExtension()));
+ m->insertItem(i18n("&Disable Error Reporting"), this, SLOT(disableJSErrorExtension()));
+ m->popup(QCursor::pos());
+}
+
+void KHTMLPart::launchJSErrorDialog() {
+ KJSErrorDlg *dlg = jsErrorExtension();
+ if (dlg) {
+ dlg->show();
+ dlg->raise();
+ }
+}
+
+void KHTMLPart::launchJSConfigDialog() {
+ QStringList args;
+ args << "khtml_java_js";
+ KApplication::kdeinitExec( "kcmshell", args );
+}
+
+QVariant KHTMLPart::executeScript(const QString& filename, int baseLine, const DOM::Node& n, const QString& script)
+{
+#ifdef KJS_VERBOSE
+ // The script is now printed by KJS's Parser::parse
+ kdDebug(6070) << "executeScript: caller='" << name() << "' filename=" << filename << " baseLine=" << baseLine /*<< " script=" << script*/ << endl;
+#endif
+ KJSProxy *proxy = jScript();
+
+ if (!proxy || proxy->paused())
+ return QVariant();
+
+ KJS::Completion comp;
+
+ QVariant ret = proxy->evaluate(filename, baseLine, script, n, &comp);
+
+ /*
+ * Error handling
+ */
+ if (comp.complType() == KJS::Throw && !comp.value().isNull()) {
+ KJSErrorDlg *dlg = jsErrorExtension();
+ if (dlg) {
+ KJS::UString msg = comp.value().toString(proxy->interpreter()->globalExec());
+ dlg->addError(i18n("<b>Error</b>: %1: %2").arg(filename, msg.qstring()));
+ }
+ }
+
+ // Handle immediate redirects now (e.g. location='foo')
+ if ( !d->m_redirectURL.isEmpty() && d->m_delayRedirect == -1 )
+ {
+ kdDebug(6070) << "executeScript done, handling immediate redirection NOW" << endl;
+ // Must abort tokenizer, no further script must execute.
+ khtml::Tokenizer* t = d->m_doc->tokenizer();
+ if(t)
+ t->abort();
+ d->m_redirectionTimer.start( 0, true );
+ }
+
+ return ret;
+}
+
+QVariant KHTMLPart::executeScript( const QString &script )
+{
+ return executeScript( DOM::Node(), script );
+}
+
+QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script )
+{
+#ifdef KJS_VERBOSE
+ kdDebug(6070) << "KHTMLPart::executeScript caller='" << name() << "' node=" << n.nodeName().string().latin1() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " /* << script */ << endl;
+#endif
+ KJSProxy *proxy = jScript();
+
+ if (!proxy || proxy->paused())
+ return QVariant();
+ ++(d->m_runningScripts);
+ KJS::Completion comp;
+ const QVariant ret = proxy->evaluate( QString::null, 1, script, n, &comp );
+ --(d->m_runningScripts);
+
+ /*
+ * Error handling
+ */
+ if (comp.complType() == KJS::Throw && !comp.value().isNull()) {
+ KJSErrorDlg *dlg = jsErrorExtension();
+ if (dlg) {
+ KJS::UString msg = comp.value().toString(proxy->interpreter()->globalExec());
+ dlg->addError(i18n("<b>Error</b>: node %1: %2").arg(n.nodeName().string()).arg(msg.qstring()));
+ }
+ }
+
+ if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
+ submitFormAgain();
+
+#ifdef KJS_VERBOSE
+ kdDebug(6070) << "KHTMLPart::executeScript - done" << endl;
+#endif
+ return ret;
+}
+
+bool KHTMLPart::scheduleScript(const DOM::Node &n, const QString& script)
+{
+ //kdDebug(6050) << "KHTMLPart::scheduleScript "<< script << endl;
+
+ d->scheduledScript = script;
+ d->scheduledScriptNode = n;
+
+ return true;
+}
+
+QVariant KHTMLPart::executeScheduledScript()
+{
+ if( d->scheduledScript.isEmpty() )
+ return QVariant();
+
+ //kdDebug(6050) << "executing delayed " << d->scheduledScript << endl;
+
+ QVariant ret = executeScript( d->scheduledScriptNode, d->scheduledScript );
+ d->scheduledScript = QString();
+ d->scheduledScriptNode = DOM::Node();
+
+ return ret;
+}
+
+void KHTMLPart::setJavaEnabled( bool enable )
+{
+ d->m_bJavaForce = enable;
+ d->m_bJavaOverride = true;
+}
+
+bool KHTMLPart::javaEnabled() const
+{
+ if (onlyLocalReferences()) return false;
+
+#ifndef Q_WS_QWS
+ if( d->m_bJavaOverride )
+ return d->m_bJavaForce;
+ return d->m_bJavaEnabled;
+#else
+ return false;
+#endif
+}
+
+KJavaAppletContext *KHTMLPart::javaContext()
+{
+ return 0;
+}
+
+KJavaAppletContext *KHTMLPart::createJavaContext()
+{
+ return 0;
+}
+
+void KHTMLPart::setPluginsEnabled( bool enable )
+{
+ d->m_bPluginsForce = enable;
+ d->m_bPluginsOverride = true;
+}
+
+bool KHTMLPart::pluginsEnabled() const
+{
+ if (onlyLocalReferences()) return false;
+
+ if ( d->m_bPluginsOverride )
+ return d->m_bPluginsForce;
+ return d->m_bPluginsEnabled;
+}
+
+static int s_DOMTreeIndentLevel = 0;
+
+void KHTMLPart::slotDebugDOMTree()
+{
+ if ( d->m_doc && d->m_doc->firstChild() )
+ qDebug("%s", d->m_doc->firstChild()->toString().string().latin1());
+
+ // Now print the contents of the frames that contain HTML
+
+ const int indentLevel = s_DOMTreeIndentLevel++;
+
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
+ KParts::ReadOnlyPart* const p = ( *it )->m_part;
+ kdDebug(6050) << QString().leftJustify(s_DOMTreeIndentLevel*4,' ') << "FRAME " << p->name() << " " << endl;
+ static_cast<KHTMLPart*>( p )->slotDebugDOMTree();
+ }
+ s_DOMTreeIndentLevel = indentLevel;
+}
+
+void KHTMLPart::slotDebugScript()
+{
+ if (jScript())
+ jScript()->showDebugWindow();
+}
+
+void KHTMLPart::slotDebugRenderTree()
+{
+#ifndef NDEBUG
+ if ( d->m_doc ) {
+ d->m_doc->renderer()->printTree();
+ // dump out the contents of the rendering & DOM trees
+// QString dumps;
+// QTextStream outputStream(dumps,IO_WriteOnly);
+// d->m_doc->renderer()->layer()->dump( outputStream );
+// kdDebug() << "dump output:" << "\n" + dumps;
+ }
+#endif
+}
+
+void KHTMLPart::slotStopAnimations()
+{
+ stopAnimations();
+}
+
+void KHTMLPart::setAutoloadImages( bool enable )
+{
+ if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
+ return;
+
+ if ( d->m_doc )
+ d->m_doc->docLoader()->setAutoloadImages( enable );
+
+ unplugActionList( "loadImages" );
+
+ if ( enable ) {
+ delete d->m_paLoadImages;
+ d->m_paLoadImages = 0;
+ }
+ else if ( !d->m_paLoadImages )
+ d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), "images_display", 0, this, SLOT( slotLoadImages() ), actionCollection(), "loadImages" );
+
+ if ( d->m_paLoadImages ) {
+ QPtrList<KAction> lst;
+ lst.append( d->m_paLoadImages );
+ plugActionList( "loadImages", lst );
+ }
+}
+
+bool KHTMLPart::autoloadImages() const
+{
+ if ( d->m_doc )
+ return d->m_doc->docLoader()->autoloadImages();
+
+ return true;
+}
+
+void KHTMLPart::clear()
+{
+ if ( d->m_bCleared )
+ return;
+
+ d->m_bCleared = true;
+
+ d->m_bClearing = true;
+
+ {
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for(; it != end; ++it )
+ {
+ // Stop HTMLRun jobs for frames
+ if ( (*it)->m_run )
+ (*it)->m_run->abort();
+ }
+ }
+
+ {
+ ConstFrameIt it = d->m_objects.begin();
+ const ConstFrameIt end = d->m_objects.end();
+ for(; it != end; ++it )
+ {
+ // Stop HTMLRun jobs for objects
+ if ( (*it)->m_run )
+ (*it)->m_run->abort();
+ }
+ }
+
+
+ findTextBegin(); // resets d->m_findNode and d->m_findPos
+ d->m_mousePressNode = DOM::Node();
+
+
+ if ( d->m_doc )
+ {
+ if (d->m_doc->attached()) //the view may have detached it already
+ d->m_doc->detach();
+ }
+
+ // Moving past doc so that onUnload works.
+ if ( d->m_frame && d->m_frame->m_jscript )
+ d->m_frame->m_jscript->clear();
+
+ // stopping marquees
+ if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->layer())
+ d->m_doc->renderer()->layer()->suspendMarquees();
+
+ if ( d->m_view )
+ d->m_view->clear();
+
+ // do not dereference the document before the jscript and view are cleared, as some destructors
+ // might still try to access the document.
+ if ( d->m_doc ) {
+ d->m_doc->deref();
+ }
+ d->m_doc = 0;
+
+ delete d->m_decoder;
+ d->m_decoder = 0;
+
+ // We don't want to change between parts if we are going to delete all of them anyway
+ disconnect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ),
+ this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
+
+ if (d->m_frames.count())
+ {
+ KHTMLFrameList frames = d->m_frames;
+ d->m_frames.clear();
+ ConstFrameIt it = frames.begin();
+ const ConstFrameIt end = frames.end();
+ for(; it != end; ++it )
+ {
+ if ( (*it)->m_part )
+ {
+ partManager()->removePart( (*it)->m_part );
+ delete (KParts::ReadOnlyPart *)(*it)->m_part;
+ }
+ delete *it;
+ }
+ }
+ d->m_suppressedPopupOriginParts.clear();
+
+ if (d->m_objects.count())
+ {
+ KHTMLFrameList objects = d->m_objects;
+ d->m_objects.clear();
+ ConstFrameIt oi = objects.begin();
+ const ConstFrameIt oiEnd = objects.end();
+
+ for (; oi != oiEnd; ++oi )
+ delete *oi;
+ }
+
+ // Listen to part changes again
+ connect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ),
+ this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
+
+ d->m_delayRedirect = 0;
+ d->m_redirectURL = QString::null;
+ d->m_redirectionTimer.stop();
+ d->m_redirectLockHistory = true;
+ d->m_bClearing = false;
+ d->m_frameNameId = 1;
+ d->m_bFirstData = true;
+
+ d->m_bMousePressed = false;
+
+ d->m_selectionStart = DOM::Node();
+ d->m_selectionEnd = DOM::Node();
+ d->m_startOffset = 0;
+ d->m_endOffset = 0;
+#ifndef QT_NO_CLIPBOARD
+ connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
+#endif
+
+ d->m_jobPercent = 0;
+
+ if ( !d->m_haveEncoding )
+ d->m_encoding = QString::null;
+#ifdef SPEED_DEBUG
+ d->m_parsetime.restart();
+#endif
+}
+
+bool KHTMLPart::openFile()
+{
+ return true;
+}
+
+DOM::HTMLDocumentImpl *KHTMLPart::docImpl() const
+{
+ if ( d && d->m_doc && d->m_doc->isHTMLDocument() )
+ return static_cast<HTMLDocumentImpl*>(d->m_doc);
+ return 0;
+}
+
+DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
+{
+ if ( d )
+ return d->m_doc;
+ return 0;
+}
+
+void KHTMLPart::slotInfoMessage(KIO::Job* kio_job, const QString& msg)
+{
+ assert(d->m_job == kio_job);
+
+ if (!parentPart())
+ setStatusBarText(msg, BarDefaultText);
+}
+
+void KHTMLPart::setPageSecurity( PageSecurity sec )
+{
+ emit d->m_extension->setPageSecurity( sec );
+ if ( sec != NotCrypted && !d->m_statusBarIconLabel && !parentPart() ) {
+ d->m_statusBarIconLabel = new KURLLabel( d->m_statusBarExtension->statusBar() );
+ d->m_statusBarIconLabel->setFixedHeight( instance()->iconLoader()->currentSize(KIcon::Small) );
+ d->m_statusBarIconLabel->setSizePolicy(QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ));
+ d->m_statusBarIconLabel->setUseCursor( false );
+ d->m_statusBarExtension->addStatusBarItem( d->m_statusBarIconLabel, 0, false );
+ connect( d->m_statusBarIconLabel, SIGNAL( leftClickedURL() ), SLOT( slotSecurity() ) );
+ } else if (d->m_statusBarIconLabel) {
+ QToolTip::remove(d->m_statusBarIconLabel);
+ }
+
+ if (d->m_statusBarIconLabel) {
+ if (d->m_ssl_in_use)
+ QToolTip::add(d->m_statusBarIconLabel,
+ i18n("Session is secured with %1 bit %2.").arg(d->m_ssl_cipher_used_bits).arg(d->m_ssl_cipher));
+ else QToolTip::add(d->m_statusBarIconLabel, i18n("Session is not secured."));
+ }
+
+ QString iconName;
+ switch (sec) {
+ case NotCrypted:
+ iconName = "decrypted";
+ if ( d->m_statusBarIconLabel ) {
+ d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarIconLabel );
+ delete d->m_statusBarIconLabel;
+ d->m_statusBarIconLabel = 0L;
+ }
+ break;
+ case Encrypted:
+ iconName = "encrypted";
+ break;
+ case Mixed:
+ iconName = "halfencrypted";
+ break;
+ }
+ d->m_paSecurity->setIcon( iconName );
+ if ( d->m_statusBarIconLabel )
+ d->m_statusBarIconLabel->setPixmap( SmallIcon( iconName, instance() ) );
+}
+
+void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
+{
+ assert ( d->m_job == kio_job );
+
+ //kdDebug( 6050 ) << "slotData: " << data.size() << endl;
+ // The first data ?
+ if ( !d->m_workingURL.isEmpty() )
+ {
+ //kdDebug( 6050 ) << "begin!" << endl;
+
+ // We must suspend KIO while we're inside begin() because it can cause
+ // crashes if a window (such as kjsdebugger) goes back into the event loop,
+ // more data arrives, and begin() gets called again (re-entered).
+ d->m_job->suspend();
+ begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
+ d->m_job->resume();
+
+ if (d->m_cachePolicy == KIO::CC_Refresh)
+ d->m_doc->docLoader()->setCachePolicy(KIO::CC_Verify);
+ else
+ d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
+
+ d->m_workingURL = KURL();
+
+ d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
+
+ // When the first data arrives, the metadata has just been made available
+ d->m_httpHeaders = d->m_job->queryMetaData("HTTP-Headers");
+ time_t cacheCreationDate = d->m_job->queryMetaData("cache-creation-date").toLong();
+ d->m_doc->docLoader()->setCacheCreationDate(cacheCreationDate);
+
+ d->m_pageServices = d->m_job->queryMetaData("PageServices");
+ d->m_pageReferrer = d->m_job->queryMetaData("referrer");
+ d->m_bSecurityInQuestion = false;
+ d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
+
+ {
+ KHTMLPart *p = parentPart();
+ if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
+ while (p->parentPart()) p = p->parentPart();
+
+ p->setPageSecurity( Mixed );
+ p->d->m_bSecurityInQuestion = true;
+ }
+ }
+
+ setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
+
+ // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
+ d->m_ssl_parent_ip = d->m_job->queryMetaData("ssl_parent_ip");
+ d->m_ssl_parent_cert = d->m_job->queryMetaData("ssl_parent_cert");
+ d->m_ssl_peer_certificate = d->m_job->queryMetaData("ssl_peer_certificate");
+ d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
+ d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
+ d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
+ d->m_ssl_cipher_desc = d->m_job->queryMetaData("ssl_cipher_desc");
+ d->m_ssl_cipher_version = d->m_job->queryMetaData("ssl_cipher_version");
+ d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
+ d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
+ d->m_ssl_cert_state = d->m_job->queryMetaData("ssl_cert_state");
+
+ if (d->m_statusBarIconLabel) {
+ QToolTip::remove(d->m_statusBarIconLabel);
+ if (d->m_ssl_in_use) {
+ QToolTip::add(d->m_statusBarIconLabel, i18n("Session is secured with %1 bit %2.").arg(d->m_ssl_cipher_used_bits).arg(d->m_ssl_cipher));
+ } else {
+ QToolTip::add(d->m_statusBarIconLabel, i18n("Session is not secured."));
+ }
+ }
+
+ // Check for charset meta-data
+ QString qData = d->m_job->queryMetaData("charset");
+ if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
+ d->m_encoding = qData;
+
+
+ // Support for http-refresh
+ qData = d->m_job->queryMetaData("http-refresh");
+ if( !qData.isEmpty())
+ d->m_doc->processHttpEquiv("refresh", qData);
+
+ // DISABLED: Support Content-Location per section 14.14 of RFC 2616.
+ // See BR# 51185,BR# 82747
+ /*
+ QString baseURL = d->m_job->queryMetaData ("content-location");
+ if (!baseURL.isEmpty())
+ d->m_doc->setBaseURL(KURL( d->m_doc->completeURL(baseURL) ));
+ */
+
+ // Support for Content-Language
+ QString language = d->m_job->queryMetaData("content-language");
+ if (!language.isEmpty())
+ d->m_doc->setContentLanguage(language);
+
+ if ( !m_url.isLocalFile() ) {
+ // Support for http last-modified
+ d->m_lastModified = d->m_job->queryMetaData("modified");
+ } else
+ d->m_lastModified = QString::null; // done on-demand by lastModified()
+ }
+
+ KHTMLPageCache::self()->addData(d->m_cacheId, data);
+ write( data.data(), data.size() );
+ if (d->m_frame && d->m_frame->m_jscript)
+ d->m_frame->m_jscript->dataReceived();
+}
+
+void KHTMLPart::slotRestoreData(const QByteArray &data )
+{
+ // The first data ?
+ if ( !d->m_workingURL.isEmpty() )
+ {
+ long saveCacheId = d->m_cacheId;
+ QString savePageReferrer = d->m_pageReferrer;
+ QString saveEncoding = d->m_encoding;
+ begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
+ d->m_encoding = saveEncoding;
+ d->m_pageReferrer = savePageReferrer;
+ d->m_cacheId = saveCacheId;
+ d->m_workingURL = KURL();
+ }
+
+ //kdDebug( 6050 ) << "slotRestoreData: " << data.size() << endl;
+ write( data.data(), data.size() );
+
+ if (data.size() == 0)
+ {
+ //kdDebug( 6050 ) << "slotRestoreData: <<end of data>>" << endl;
+ // End of data.
+ if (d->m_doc && d->m_doc->parsing())
+ end(); //will emit completed()
+ }
+}
+
+void KHTMLPart::showError( KIO::Job* job )
+{
+ kdDebug(6050) << "KHTMLPart::showError d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
+ << " d->m_bCleared=" << d->m_bCleared << endl;
+
+ if (job->error() == KIO::ERR_NO_CONTENT)
+ return;
+
+ if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
+ job->showErrorDialog( /*d->m_view*/ );
+ else
+ {
+ htmlError( job->error(), job->errorText(), d->m_workingURL );
+ }
+}
+
+// This is a protected method, placed here because of it's relevance to showError
+void KHTMLPart::htmlError( int errorCode, const QString& text, const KURL& reqUrl )
+{
+ kdDebug(6050) << "KHTMLPart::htmlError errorCode=" << errorCode << " text=" << text << endl;
+ // make sure we're not executing any embedded JS
+ bool bJSFO = d->m_bJScriptForce;
+ bool bJSOO = d->m_bJScriptOverride;
+ d->m_bJScriptForce = false;
+ d->m_bJScriptOverride = true;
+ begin();
+ QString errText = QString::fromLatin1( "<HTML dir=%1><HEAD><TITLE>" )
+ .arg(QApplication::reverseLayout() ? "rtl" : "ltr");
+ errText += i18n( "Error while loading %1" ).arg( reqUrl.htmlURL() );
+ errText += QString::fromLatin1( "</TITLE></HEAD><BODY><P>" );
+ errText += i18n( "An error occurred while loading <B>%1</B>:" ).arg( reqUrl.htmlURL() );
+ errText += QString::fromLatin1( "</P>" );
+ errText += QStyleSheet::convertFromPlainText( KIO::buildErrorString( errorCode, text ) );
+ errText += QString::fromLatin1( "</BODY></HTML>" );
+ write(errText);
+ end();
+
+ d->m_bJScriptForce = bJSFO;
+ d->m_bJScriptOverride = bJSOO;
+
+ // make the working url the current url, so that reload works and
+ // emit the progress signals to advance one step in the history
+ // (so that 'back' works)
+ m_url = reqUrl; // same as d->m_workingURL
+ d->m_workingURL = KURL();
+ emit started( 0 );
+ emit completed();
+ return;
+ // following disabled until 3.1
+
+ QString errorName, techName, description;
+ QStringList causes, solutions;
+
+ QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
+ QDataStream stream(raw, IO_ReadOnly);
+
+ stream >> errorName >> techName >> description >> causes >> solutions;
+
+ QString url, protocol, datetime;
+ url = reqUrl.prettyURL();
+ protocol = reqUrl.protocol();
+ datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
+ false );
+
+ QString doc = QString::fromLatin1( "<html><head><title>" );
+ doc += i18n( "Error: " );
+ doc += errorName;
+ doc += QString::fromLatin1( " - %1</title></head><body><h1>" ).arg( url );
+ doc += i18n( "The requested operation could not be completed" );
+ doc += QString::fromLatin1( "</h1><h2>" );
+ doc += errorName;
+ doc += QString::fromLatin1( "</h2>" );
+ if ( !techName.isNull() ) {
+ doc += QString::fromLatin1( "<h2>" );
+ doc += i18n( "Technical Reason: " );
+ doc += techName;
+ doc += QString::fromLatin1( "</h2>" );
+ }
+ doc += QString::fromLatin1( "<h3>" );
+ doc += i18n( "Details of the Request:" );
+ doc += QString::fromLatin1( "</h3><ul><li>" );
+ doc += i18n( "URL: %1" ).arg( url );
+ doc += QString::fromLatin1( "</li><li>" );
+ if ( !protocol.isNull() ) {
+ // uncomment for 3.1... i18n change
+ // doc += i18n( "Protocol: %1" ).arg( protocol ).arg( protocol );
+ doc += QString::fromLatin1( "</li><li>" );
+ }
+ doc += i18n( "Date and Time: %1" ).arg( datetime );
+ doc += QString::fromLatin1( "</li><li>" );
+ doc += i18n( "Additional Information: %1" ).arg( text );
+ doc += QString::fromLatin1( "</li></ul><h3>" );
+ doc += i18n( "Description:" );
+ doc += QString::fromLatin1( "</h3><p>" );
+ doc += description;
+ doc += QString::fromLatin1( "</p>" );
+ if ( causes.count() ) {
+ doc += QString::fromLatin1( "<h3>" );
+ doc += i18n( "Possible Causes:" );
+ doc += QString::fromLatin1( "</h3><ul><li>" );
+ doc += causes.join( "</li><li>" );
+ doc += QString::fromLatin1( "</li></ul>" );
+ }
+ if ( solutions.count() ) {
+ doc += QString::fromLatin1( "<h3>" );
+ doc += i18n( "Possible Solutions:" );
+ doc += QString::fromLatin1( "</h3><ul><li>" );
+ doc += solutions.join( "</li><li>" );
+ doc += QString::fromLatin1( "</li></ul>" );
+ }
+ doc += QString::fromLatin1( "</body></html>" );
+
+ write( doc );
+ end();
+}
+
+void KHTMLPart::slotFinished( KIO::Job * job )
+{
+ d->m_job = 0L;
+ d->m_jobspeed = 0L;
+
+ if (job->error())
+ {
+ KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
+
+ // The following catches errors that occur as a result of HTTP
+ // to FTP redirections where the FTP URL is a directory. Since
+ // KIO cannot change a redirection request from GET to LISTDIR,
+ // we have to take care of it here once we know for sure it is
+ // a directory...
+ if (job->error() == KIO::ERR_IS_DIRECTORY)
+ {
+ KParts::URLArgs args;
+ emit d->m_extension->openURLRequest( d->m_workingURL, args );
+ }
+ else
+ {
+ emit canceled( job->errorString() );
+ // TODO: what else ?
+ checkCompleted();
+ showError( job );
+ }
+
+ return;
+ }
+ KIO::TransferJob *tjob = ::qt_cast<KIO::TransferJob*>(job);
+ if (tjob && tjob->isErrorPage()) {
+ khtml::RenderPart *renderPart = d->m_frame ? static_cast<khtml::RenderPart *>(d->m_frame->m_frame) : 0;
+ if (renderPart) {
+ HTMLObjectElementImpl* elt = static_cast<HTMLObjectElementImpl *>(renderPart->element());
+ if (!elt)
+ return;
+ elt->renderAlternative();
+ checkCompleted();
+ }
+ if (d->m_bComplete) return;
+ }
+
+ //kdDebug( 6050 ) << "slotFinished" << endl;
+
+ KHTMLPageCache::self()->endData(d->m_cacheId);
+ if (d->m_frame && d->m_frame->m_jscript)
+ d->m_frame->m_jscript->dataReceived();
+
+ if ( d->m_doc && d->m_doc->docLoader()->expireDate() && m_url.protocol().lower().startsWith("http"))
+ KIO::http_update_cache(m_url, false, d->m_doc->docLoader()->expireDate());
+
+ d->m_workingURL = KURL();
+
+ if ( d->m_doc && d->m_doc->parsing())
+ end(); //will emit completed()
+}
+
+void KHTMLPart::begin( const KURL &url, int xOffset, int yOffset )
+{
+ // No need to show this for a new page until an error is triggered
+ if (!parentPart()) {
+ removeJSErrorExtension();
+ setSuppressedPopupIndicator( false );
+ d->m_openableSuppressedPopups = 0;
+ for ( QValueListIterator<QGuardedPtr<KHTMLPart> > i = d->m_suppressedPopupOriginParts.begin();
+ i != d->m_suppressedPopupOriginParts.end(); ++i ) {
+
+ if (KHTMLPart* part = *i) {
+ KJS::Window *w = KJS::Window::retrieveWindow( part );
+ if (w)
+ w->forgetSuppressedWindows();
+ }
+ }
+ }
+
+ clear();
+ d->m_bCleared = false;
+ d->m_cacheId = 0;
+ d->m_bComplete = false;
+ d->m_bLoadEventEmitted = false;
+
+ if(url.isValid()) {
+ QString urlString = url.url();
+ KHTMLFactory::vLinks()->insert( urlString );
+ QString urlString2 = url.prettyURL();
+ if ( urlString != urlString2 ) {
+ KHTMLFactory::vLinks()->insert( urlString2 );
+ }
+ }
+
+
+ // ###
+ //stopParser();
+
+ KParts::URLArgs args( d->m_extension->urlArgs() );
+ args.xOffset = xOffset;
+ args.yOffset = yOffset;
+ d->m_extension->setURLArgs( args );
+
+ d->m_pageReferrer = QString::null;
+
+ KURL ref(url);
+ d->m_referrer = ref.protocol().startsWith("http") ? ref.url() : "";
+
+ m_url = url;
+
+ bool servedAsXHTML = args.serviceType == "application/xhtml+xml";
+ bool servedAsXML = KMimeType::mimeType(args.serviceType)->is( "text/xml" );
+ // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl
+ if ( servedAsXML && !servedAsXHTML ) { // any XML derivative, except XHTML
+ d->m_doc = DOMImplementationImpl::instance()->createDocument( d->m_view );
+ } else {
+ d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
+ // HTML or XHTML? (#86446)
+ static_cast<HTMLDocumentImpl *>(d->m_doc)->setHTMLRequested( !servedAsXHTML );
+ }
+#ifndef KHTML_NO_CARET
+// d->m_view->initCaret();
+#endif
+
+ d->m_doc->ref();
+ d->m_doc->setURL( m_url.url() );
+ if (!d->m_doc->attached())
+ d->m_doc->attach( );
+ d->m_doc->setBaseURL( KURL() );
+ d->m_doc->docLoader()->setShowAnimations( KHTMLFactory::defaultHTMLSettings()->showAnimations() );
+ emit docCreated();
+
+ d->m_paUseStylesheet->setItems(QStringList());
+ d->m_paUseStylesheet->setEnabled( false );
+
+ setAutoloadImages( KHTMLFactory::defaultHTMLSettings()->autoLoadImages() );
+ QString userStyleSheet = KHTMLFactory::defaultHTMLSettings()->userStyleSheet();
+ if ( !userStyleSheet.isEmpty() )
+ setUserStyleSheet( KURL( userStyleSheet ) );
+
+ d->m_doc->setRestoreState(args.docState);
+ d->m_doc->open();
+ connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
+
+ emit d->m_extension->enableAction( "print", true );
+
+ d->m_doc->setParsing(true);
+}
+
+void KHTMLPart::write( const char *str, int len )
+{
+ if ( !d->m_decoder )
+ d->m_decoder = createDecoder();
+
+ if ( len == -1 )
+ len = strlen( str );
+
+ if ( len == 0 )
+ return;
+
+ QString decoded = d->m_decoder->decode( str, len );
+
+ if(decoded.isEmpty()) return;
+
+ if(d->m_bFirstData) {
+ // determine the parse mode
+ d->m_doc->determineParseMode( decoded );
+ d->m_bFirstData = false;
+
+ //kdDebug(6050) << "KHTMLPart::write haveEnc = " << d->m_haveEncoding << endl;
+ // ### this is still quite hacky, but should work a lot better than the old solution
+ if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
+ d->m_doc->setDecoderCodec(d->m_decoder->codec());
+ d->m_doc->recalcStyle( NodeImpl::Force );
+ }
+
+ khtml::Tokenizer* t = d->m_doc->tokenizer();
+ if(t)
+ t->write( decoded, true );
+}
+
+void KHTMLPart::write( const QString &str )
+{
+ if ( str.isNull() )
+ return;
+
+ if(d->m_bFirstData) {
+ // determine the parse mode
+ d->m_doc->setParseMode( DocumentImpl::Strict );
+ d->m_bFirstData = false;
+ }
+ khtml::Tokenizer* t = d->m_doc->tokenizer();
+ if(t)
+ t->write( str, true );
+}
+
+void KHTMLPart::end()
+{
+ if (d->m_doc) {
+ if (d->m_decoder) {
+ QString decoded = d->m_decoder->flush();
+ if (d->m_bFirstData) {
+ d->m_bFirstData = false;
+ d->m_doc->determineParseMode(decoded);
+ }
+ write(decoded);
+ }
+ d->m_doc->finishParsing();
+ }
+}
+
+bool KHTMLPart::doOpenStream( const QString& mimeType )
+{
+ KMimeType::Ptr mime = KMimeType::mimeType(mimeType);
+ if ( mime->is( "text/html" ) || mime->is( "text/xml" ) )
+ {
+ begin( url() );
+ return true;
+ }
+ return false;
+}
+
+bool KHTMLPart::doWriteStream( const QByteArray& data )
+{
+ write( data.data(), data.size() );
+ return true;
+}
+
+bool KHTMLPart::doCloseStream()
+{
+ end();
+ return true;
+}
+
+
+void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
+{
+ if (!d->m_view) return;
+ d->m_view->paint(p, rc, yOff, more);
+}
+
+void KHTMLPart::stopAnimations()
+{
+ if ( d->m_doc )
+ d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
+
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ if ( !(*it)->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
+ KParts::ReadOnlyPart* const p = ( *it )->m_part;
+ static_cast<KHTMLPart*>( p )->stopAnimations();
+ }
+}
+
+void KHTMLPart::resetFromScript()
+{
+ closeURL();
+ d->m_bComplete = false;
+ d->m_bLoadEventEmitted = false;
+ disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
+ connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
+ d->m_doc->setParsing(true);
+
+ emit started( 0L );
+}
+
+void KHTMLPart::slotFinishedParsing()
+{
+ d->m_doc->setParsing(false);
+ checkEmitLoadEvent();
+ disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
+
+ if (!d->m_view)
+ return; // We are probably being destructed.
+
+ checkCompleted();
+}
+
+void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
+{
+ if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
+ KHTMLPart* p = this;
+ while ( p ) {
+ KHTMLPart* const op = p;
+ ++(p->d->m_totalObjectCount);
+ p = p->parentPart();
+ if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount
+ && !op->d->m_progressUpdateTimer.isActive())
+ op->d->m_progressUpdateTimer.start( 200, true );
+ }
+ }
+}
+
+void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
+{
+ if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
+ KHTMLPart* p = this;
+ while ( p ) {
+ KHTMLPart* const op = p;
+ ++(p->d->m_loadedObjects);
+ p = p->parentPart();
+ if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount && op->d->m_jobPercent <= 100
+ && !op->d->m_progressUpdateTimer.isActive())
+ op->d->m_progressUpdateTimer.start( 200, true );
+ }
+ }
+
+ checkCompleted();
+}
+
+void KHTMLPart::slotProgressUpdate()
+{
+ int percent;
+ if ( d->m_loadedObjects < d->m_totalObjectCount )
+ percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
+ else
+ percent = d->m_jobPercent;
+
+ if( d->m_bComplete )
+ percent = 100;
+
+ if (d->m_statusMessagesEnabled) {
+ if( d->m_bComplete )
+ emit d->m_extension->infoMessage( i18n( "Page loaded." ));
+ else if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
+ emit d->m_extension->infoMessage( i18n( "%n Image of %1 loaded.", "%n Images of %1 loaded.", d->m_loadedObjects).arg(d->m_totalObjectCount) );
+ }
+
+ emit d->m_extension->loadingProgress( percent );
+}
+
+void KHTMLPart::slotJobSpeed( KIO::Job* /*job*/, unsigned long speed )
+{
+ d->m_jobspeed = speed;
+ if (!parentPart())
+ setStatusBarText(jsStatusBarText(), BarOverrideText);
+}
+
+void KHTMLPart::slotJobPercent( KIO::Job* /*job*/, unsigned long percent )
+{
+ d->m_jobPercent = percent;
+
+ if ( !parentPart() )
+ d->m_progressUpdateTimer.start( 0, true );
+}
+
+void KHTMLPart::slotJobDone( KIO::Job* /*job*/ )
+{
+ d->m_jobPercent = 100;
+
+ if ( !parentPart() )
+ d->m_progressUpdateTimer.start( 0, true );
+}
+
+void KHTMLPart::slotUserSheetStatDone( KIO::Job *_job )
+{
+ using namespace KIO;
+
+ if ( _job->error() ) {
+ showError( _job );
+ return;
+ }
+
+ const UDSEntry entry = dynamic_cast<KIO::StatJob *>( _job )->statResult();
+ UDSEntry::ConstIterator it = entry.begin();
+ const UDSEntry::ConstIterator end = entry.end();
+ for ( ; it != end; ++it ) {
+ if ( ( *it ).m_uds == UDS_MODIFICATION_TIME ) {
+ break;
+ }
+ }
+
+ // If the filesystem supports modification times, only reload the
+ // user-defined stylesheet if necessary - otherwise always reload.
+ if ( it != end ) {
+ const time_t lastModified = static_cast<time_t>( ( *it ).m_long );
+ if ( d->m_userStyleSheetLastModified >= lastModified ) {
+ return;
+ }
+ d->m_userStyleSheetLastModified = lastModified;
+ }
+
+ setUserStyleSheet( KURL( settings()->userStyleSheet() ) );
+}
+
+void KHTMLPart::checkCompleted()
+{
+// kdDebug( 6050 ) << "KHTMLPart::checkCompleted() " << this << " " << name() << endl;
+// kdDebug( 6050 ) << " parsing: " << (d->m_doc && d->m_doc->parsing()) << endl;
+// kdDebug( 6050 ) << " complete: " << d->m_bComplete << endl;
+
+ // restore the cursor position
+ if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
+ {
+ if (d->m_focusNodeNumber >= 0)
+ d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
+
+ d->m_focusNodeRestored = true;
+ }
+
+ bool bPendingChildRedirection = false;
+ // Any frame that hasn't completed yet ?
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it ) {
+ if ( !(*it)->m_bCompleted )
+ {
+ //kdDebug( 6050 ) << this << " is waiting for " << (*it)->m_part << endl;
+ return;
+ }
+ // Check for frames with pending redirections
+ if ( (*it)->m_bPendingRedirection )
+ bPendingChildRedirection = true;
+ }
+
+ // Any object that hasn't completed yet ?
+ {
+ ConstFrameIt oi = d->m_objects.begin();
+ const ConstFrameIt oiEnd = d->m_objects.end();
+
+ for (; oi != oiEnd; ++oi )
+ if ( !(*oi)->m_bCompleted )
+ return;
+ }
+ // Are we still parsing - or have we done the completed stuff already ?
+ if ( d->m_bComplete || (d->m_doc && d->m_doc->parsing()) )
+ return;
+
+ // Still waiting for images/scripts from the loader ?
+ int requests = 0;
+ if ( d->m_doc && d->m_doc->docLoader() )
+ requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
+
+ if ( requests > 0 )
+ {
+ //kdDebug(6050) << "still waiting for images/scripts from the loader - requests:" << requests << endl;
+ return;
+ }
+
+ // OK, completed.
+ // Now do what should be done when we are really completed.
+ d->m_bComplete = true;
+ d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
+ d->m_totalObjectCount = 0;
+ d->m_loadedObjects = 0;
+
+ KHTMLPart* p = this;
+ while ( p ) {
+ KHTMLPart* op = p;
+ p = p->parentPart();
+ if ( !p && !op->d->m_progressUpdateTimer.isActive())
+ op->d->m_progressUpdateTimer.start( 0, true );
+ }
+
+ checkEmitLoadEvent(); // if we didn't do it before
+
+ bool pendingAction = false;
+
+ if ( !d->m_redirectURL.isEmpty() )
+ {
+ // DA: Do not start redirection for frames here! That action is
+ // deferred until the parent emits a completed signal.
+ if ( parentPart() == 0 ) {
+ //kdDebug(6050) << this << " starting redirection timer" << endl;
+ d->m_redirectionTimer.start( 1000 * d->m_delayRedirect, true );
+ } else {
+ //kdDebug(6050) << this << " not toplevel -> not starting redirection timer. Waiting for slotParentCompleted." << endl;
+ }
+
+ pendingAction = true;
+ }
+ else if ( bPendingChildRedirection )
+ {
+ pendingAction = true;
+ }
+
+ // the view will emit completed on our behalf,
+ // either now or at next repaint if one is pending
+
+ //kdDebug(6050) << this << " asks the view to emit completed. pendingAction=" << pendingAction << endl;
+ d->m_view->complete( pendingAction );
+
+ // find the alternate stylesheets
+ QStringList sheets;
+ if (d->m_doc)
+ sheets = d->m_doc->availableStyleSheets();
+ sheets.prepend( i18n( "Automatic Detection" ) );
+ d->m_paUseStylesheet->setItems( sheets );
+
+ d->m_paUseStylesheet->setEnabled( sheets.count() > 2);
+ if (sheets.count() > 2)
+ {
+ d->m_paUseStylesheet->setCurrentItem(kMax(sheets.findIndex(d->m_sheetUsed), 0));
+ slotUseStylesheet();
+ }
+
+ setJSDefaultStatusBarText(QString::null);
+
+#ifdef SPEED_DEBUG
+ kdDebug(6050) << "DONE: " <<d->m_parsetime.elapsed() << endl;
+#endif
+}
+
+void KHTMLPart::checkEmitLoadEvent()
+{
+ if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
+
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ if ( !(*it)->m_bCompleted ) // still got a frame running -> too early
+ return;
+
+ ConstFrameIt oi = d->m_objects.begin();
+ const ConstFrameIt oiEnd = d->m_objects.end();
+
+ for (; oi != oiEnd; ++oi )
+ if ( !(*oi)->m_bCompleted ) // still got a object running -> too early
+ return;
+
+ // Still waiting for images/scripts from the loader ?
+ // (onload must happen afterwards, #45607)
+ // ## This makes this method very similar to checkCompleted. A brave soul should try merging them.
+ int requests = 0;
+ if ( d->m_doc && d->m_doc->docLoader() )
+ requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
+
+ if ( requests > 0 )
+ return;
+
+ d->m_bLoadEventEmitted = true;
+ if (d->m_doc)
+ d->m_doc->close();
+}
+
+const KHTMLSettings *KHTMLPart::settings() const
+{
+ return d->m_settings;
+}
+
+#ifndef KDE_NO_COMPAT
+KURL KHTMLPart::baseURL() const
+{
+ if ( !d->m_doc ) return KURL();
+
+ return d->m_doc->baseURL();
+}
+
+QString KHTMLPart::baseTarget() const
+{
+ if ( !d->m_doc ) return QString::null;
+
+ return d->m_doc->baseTarget();
+}
+#endif
+
+KURL KHTMLPart::completeURL( const QString &url )
+{
+ if ( !d->m_doc ) return KURL( url );
+
+ if (d->m_decoder)
+ return KURL(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
+
+ return KURL( d->m_doc->completeURL( url ) );
+}
+
+// Called by ecma/kjs_window in case of redirections from Javascript,
+// and by xml/dom_docimpl.cpp in case of http-equiv meta refresh.
+void KHTMLPart::scheduleRedirection( int delay, const QString &url, bool doLockHistory )
+{
+ kdDebug(6050) << "KHTMLPart::scheduleRedirection delay=" << delay << " url=" << url << endl;
+ kdDebug(6050) << "current redirectURL=" << d->m_redirectURL << " with delay " << d->m_delayRedirect << endl;
+ if( delay < 24*60*60 &&
+ ( d->m_redirectURL.isEmpty() || delay <= d->m_delayRedirect) ) {
+ d->m_delayRedirect = delay;
+ d->m_redirectURL = url;
+ d->m_redirectLockHistory = doLockHistory;
+ kdDebug(6050) << " d->m_bComplete=" << d->m_bComplete << endl;
+ if ( d->m_bComplete ) {
+ d->m_redirectionTimer.stop();
+ d->m_redirectionTimer.start( kMax(0, 1000 * d->m_delayRedirect), true );
+ }
+ }
+}
+
+void KHTMLPart::slotRedirect()
+{
+ kdDebug(6050) << this << " slotRedirect()" << endl;
+ QString u = d->m_redirectURL;
+ d->m_delayRedirect = 0;
+ d->m_redirectURL = QString::null;
+
+ // SYNC check with ecma/kjs_window.cpp::goURL !
+ if ( u.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
+ {
+ QString script = KURL::decode_string( u.right( u.length() - 11 ) );
+ kdDebug( 6050 ) << "KHTMLPart::slotRedirect script=" << script << endl;
+ QVariant res = executeScript( DOM::Node(), script );
+ if ( res.type() == QVariant::String ) {
+ begin( url() );
+ write( res.asString() );
+ end();
+ }
+ emit completed();
+ return;
+ }
+ KParts::URLArgs args;
+ KURL cUrl( m_url );
+ KURL url( u );
+
+ // handle windows opened by JS
+ if ( openedByJS() && d->m_opener )
+ cUrl = d->m_opener->url();
+
+ if (!kapp || !kapp->authorizeURLAction("redirect", cUrl, url))
+ {
+ kdWarning(6050) << "KHTMLPart::scheduleRedirection: Redirection from " << cUrl << " to " << url << " REJECTED!" << endl;
+ emit completed();
+ return;
+ }
+
+ if ( urlcmp( u, m_url.url(), true, true ) )
+ {
+ args.metaData().insert("referrer", d->m_pageReferrer);
+ }
+
+ // For javascript and META-tag based redirections:
+ // - We don't take cross-domain-ness in consideration if we are the
+ // toplevel frame because the new URL may be in a different domain as the current URL
+ // but that's ok.
+ // - If we are not the toplevel frame then we check against the toplevelURL()
+ if (parentPart())
+ args.metaData().insert("cross-domain", toplevelURL().url());
+
+ args.setLockHistory( d->m_redirectLockHistory );
+ // _self: make sure we don't use any <base target=>'s
+
+ d->m_urlSelectedOpenedURL = true; // In case overriden, default to success
+ urlSelected( u, 0, 0, "_self", args );
+
+ if ( !d->m_urlSelectedOpenedURL ) // urlSelected didn't open a url, so emit completed ourselves
+ emit completed();
+}
+
+void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url)
+{
+ // the slave told us that we got redirected
+ //kdDebug( 6050 ) << "redirection by KIO to " << url.url() << endl;
+ emit d->m_extension->setLocationBarURL( url.prettyURL() );
+ d->m_workingURL = url;
+}
+
+bool KHTMLPart::setEncoding( const QString &name, bool override )
+{
+ d->m_encoding = name;
+ d->m_haveEncoding = override;
+
+ if( !m_url.isEmpty() ) {
+ // reload document
+ closeURL();
+ KURL url = m_url;
+ m_url = 0;
+ d->m_restored = true;
+ openURL(url);
+ d->m_restored = false;
+ }
+
+ return true;
+}
+
+QString KHTMLPart::encoding() const
+{
+ if(d->m_haveEncoding && !d->m_encoding.isEmpty())
+ return d->m_encoding;
+
+ if(d->m_decoder && d->m_decoder->encoding())
+ return QString(d->m_decoder->encoding());
+
+ return defaultEncoding();
+}
+
+QString KHTMLPart::defaultEncoding() const
+{
+ QString encoding = settings()->encoding();
+ if ( !encoding.isEmpty() )
+ return encoding;
+ // HTTP requires the default encoding to be latin1, when neither
+ // the user nor the page requested a particular encoding.
+ if ( url().protocol().startsWith( "http" ) )
+ return "iso-8859-1";
+ else
+ return KGlobal::locale()->encoding();
+}
+
+void KHTMLPart::setUserStyleSheet(const KURL &url)
+{
+ if ( d->m_doc && d->m_doc->docLoader() )
+ (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
+}
+
+void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
+{
+ if ( d->m_doc )
+ d->m_doc->setUserStyleSheet( styleSheet );
+}
+
+bool KHTMLPart::gotoAnchor( const QString &name )
+{
+ if (!d->m_doc)
+ return false;
+
+ HTMLCollectionImpl *anchors =
+ new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
+ anchors->ref();
+ NodeImpl *n = anchors->namedItem(name);
+ anchors->deref();
+
+ if(!n) {
+ n = d->m_doc->getElementById( name );
+ }
+
+ d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
+
+ // Implement the rule that "" and "top" both mean top of page as in other browsers.
+ bool quirkyName = !n && !d->m_doc->inStrictMode() && (name.isEmpty() || name.lower() == "top");
+
+ if (quirkyName) {
+ d->m_view->setContentsPos(0, 0);
+ return true;
+ } else if (!n) {
+ kdDebug(6050) << "KHTMLPart::gotoAnchor node '" << name << "' not found" << endl;
+ return false;
+ }
+
+ int x = 0, y = 0;
+ int gox, dummy;
+ HTMLElementImpl *a = static_cast<HTMLElementImpl *>(n);
+
+ a->getUpperLeftCorner(x, y);
+ if (x <= d->m_view->contentsX())
+ gox = x - 10;
+ else {
+ gox = d->m_view->contentsX();
+ if ( x + 10 > d->m_view->contentsX()+d->m_view->visibleWidth()) {
+ a->getLowerRightCorner(x, dummy);
+ gox = x - d->m_view->visibleWidth() + 10;
+ }
+ }
+
+ d->m_view->setContentsPos(gox, y);
+
+ return true;
+}
+
+bool KHTMLPart::nextAnchor()
+{
+ if (!d->m_doc)
+ return false;
+ d->m_view->focusNextPrevNode ( true );
+
+ return true;
+}
+
+bool KHTMLPart::prevAnchor()
+{
+ if (!d->m_doc)
+ return false;
+ d->m_view->focusNextPrevNode ( false );
+
+ return true;
+}
+
+void KHTMLPart::setStandardFont( const QString &name )
+{
+ d->m_settings->setStdFontName(name);
+}
+
+void KHTMLPart::setFixedFont( const QString &name )
+{
+ d->m_settings->setFixedFontName(name);
+}
+
+void KHTMLPart::setURLCursor( const QCursor &c )
+{
+ d->m_linkCursor = c;
+}
+
+QCursor KHTMLPart::urlCursor() const
+{
+ return d->m_linkCursor;
+}
+
+bool KHTMLPart::onlyLocalReferences() const
+{
+ return d->m_onlyLocalReferences;
+}
+
+void KHTMLPart::setOnlyLocalReferences(bool enable)
+{
+ d->m_onlyLocalReferences = enable;
+}
+
+void KHTMLPartPrivate::setFlagRecursively(
+ bool KHTMLPartPrivate::*flag, bool value)
+{
+ // first set it on the current one
+ this->*flag = value;
+
+ // descend into child frames recursively
+ {
+ QValueList<khtml::ChildFrame*>::Iterator it = m_frames.begin();
+ const QValueList<khtml::ChildFrame*>::Iterator itEnd = m_frames.end();
+ for (; it != itEnd; ++it) {
+ KHTMLPart* const part = static_cast<KHTMLPart *>((KParts::ReadOnlyPart *)(*it)->m_part);
+ if (part->inherits("KHTMLPart"))
+ part->d->setFlagRecursively(flag, value);
+ }/*next it*/
+ }
+ // do the same again for objects
+ {
+ QValueList<khtml::ChildFrame*>::Iterator it = m_objects.begin();
+ const QValueList<khtml::ChildFrame*>::Iterator itEnd = m_objects.end();
+ for (; it != itEnd; ++it) {
+ KHTMLPart* const part = static_cast<KHTMLPart *>((KParts::ReadOnlyPart *)(*it)->m_part);
+ if (part->inherits("KHTMLPart"))
+ part->d->setFlagRecursively(flag, value);
+ }/*next it*/
+ }
+}
+
+void KHTMLPart::setCaretMode(bool enable)
+{
+#ifndef KHTML_NO_CARET
+ kdDebug(6200) << "setCaretMode(" << enable << ")" << endl;
+ if (isCaretMode() == enable) return;
+ d->setFlagRecursively(&KHTMLPartPrivate::m_caretMode, enable);
+ // FIXME: this won't work on frames as expected
+ if (!isEditable()) {
+ if (enable) {
+ view()->initCaret(true);
+ view()->ensureCaretVisible();
+ } else
+ view()->caretOff();
+ }/*end if*/
+#endif // KHTML_NO_CARET
+}
+
+bool KHTMLPart::isCaretMode() const
+{
+ return d->m_caretMode;
+}
+
+void KHTMLPart::setEditable(bool enable)
+{
+#ifndef KHTML_NO_CARET
+ if (isEditable() == enable) return;
+ d->setFlagRecursively(&KHTMLPartPrivate::m_designMode, enable);
+ // FIXME: this won't work on frames as expected
+ if (!isCaretMode()) {
+ if (enable) {
+ view()->initCaret(true);
+ view()->ensureCaretVisible();
+ } else
+ view()->caretOff();
+ }/*end if*/
+#endif // KHTML_NO_CARET
+}
+
+bool KHTMLPart::isEditable() const
+{
+ return d->m_designMode;
+}
+
+void KHTMLPart::setCaretPosition(DOM::Node node, long offset, bool extendSelection)
+{
+#ifndef KHTML_NO_CARET
+#if 0
+ kdDebug(6200) << k_funcinfo << "node: " << node.handle() << " nodeName: "
+ << node.nodeName().string() << " offset: " << offset
+ << " extendSelection " << extendSelection << endl;
+#endif
+ if (view()->moveCaretTo(node.handle(), offset, !extendSelection))
+ emitSelectionChanged();
+ view()->ensureCaretVisible();
+#endif // KHTML_NO_CARET
+}
+
+KHTMLPart::CaretDisplayPolicy KHTMLPart::caretDisplayPolicyNonFocused() const
+{
+#ifndef KHTML_NO_CARET
+ return (CaretDisplayPolicy)view()->caretDisplayPolicyNonFocused();
+#else // KHTML_NO_CARET
+ return CaretInvisible;
+#endif // KHTML_NO_CARET
+}
+
+void KHTMLPart::setCaretDisplayPolicyNonFocused(CaretDisplayPolicy policy)
+{
+#ifndef KHTML_NO_CARET
+ view()->setCaretDisplayPolicyNonFocused(policy);
+#endif // KHTML_NO_CARET
+}
+
+void KHTMLPart::setCaretVisible(bool show)
+{
+#ifndef KHTML_NO_CARET
+ if (show) {
+
+ NodeImpl *caretNode = xmlDocImpl()->focusNode();
+ if (isCaretMode() || isEditable()
+ || (caretNode && caretNode->contentEditable())) {
+ view()->caretOn();
+ }/*end if*/
+
+ } else {
+
+ view()->caretOff();
+
+ }/*end if*/
+#endif // KHTML_NO_CARET
+}
+
+void KHTMLPart::findTextBegin()
+{
+ d->m_findPos = -1;
+ d->m_findNode = 0;
+ d->m_findPosEnd = -1;
+ d->m_findNodeEnd= 0;
+ d->m_findPosStart = -1;
+ d->m_findNodeStart = 0;
+ d->m_findNodePrevious = 0;
+ delete d->m_find;
+ d->m_find = 0L;
+}
+
+bool KHTMLPart::initFindNode( bool selection, bool reverse, bool fromCursor )
+{
+ if ( !d->m_doc )
+ return false;
+
+ DOM::NodeImpl* firstNode = 0L;
+ if (d->m_doc->isHTMLDocument())
+ firstNode = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
+ else
+ firstNode = d->m_doc;
+
+ if ( !firstNode )
+ {
+ //kdDebug(6050) << k_funcinfo << "no first node (body or doc) -> return false" << endl;
+ return false;
+ }
+ if ( firstNode->id() == ID_FRAMESET )
+ {
+ //kdDebug(6050) << k_funcinfo << "FRAMESET -> return false" << endl;
+ return false;
+ }
+
+ if ( selection && hasSelection() )
+ {
+ //kdDebug(6050) << k_funcinfo << "using selection" << endl;
+ if ( !fromCursor )
+ {
+ d->m_findNode = reverse ? d->m_selectionEnd.handle() : d->m_selectionStart.handle();
+ d->m_findPos = reverse ? d->m_endOffset : d->m_startOffset;
+ }
+ d->m_findNodeEnd = reverse ? d->m_selectionStart.handle() : d->m_selectionEnd.handle();
+ d->m_findPosEnd = reverse ? d->m_startOffset : d->m_endOffset;
+ d->m_findNodeStart = !reverse ? d->m_selectionStart.handle() : d->m_selectionEnd.handle();
+ d->m_findPosStart = !reverse ? d->m_startOffset : d->m_endOffset;
+ d->m_findNodePrevious = d->m_findNodeStart;
+ }
+ else // whole document
+ {
+ //kdDebug(6050) << k_funcinfo << "whole doc" << endl;
+ if ( !fromCursor )
+ {
+ d->m_findNode = firstNode;
+ d->m_findPos = reverse ? -1 : 0;
+ }
+ d->m_findNodeEnd = reverse ? firstNode : 0;
+ d->m_findPosEnd = reverse ? 0 : -1;
+ d->m_findNodeStart = !reverse ? firstNode : 0;
+ d->m_findPosStart = !reverse ? 0 : -1;
+ d->m_findNodePrevious = d->m_findNodeStart;
+ if ( reverse )
+ {
+ // Need to find out the really last object, to start from it
+ khtml::RenderObject* obj = d->m_findNode ? d->m_findNode->renderer() : 0;
+ if ( obj )
+ {
+ // find the last object in the render tree
+ while ( obj->lastChild() )
+ {
+ obj = obj->lastChild();
+ }
+ // now get the last object with a NodeImpl associated
+ while ( !obj->element() && obj->objectAbove() )
+ {
+ obj = obj->objectAbove();
+ }
+ d->m_findNode = obj->element();
+ }
+ }
+ }
+ return true;
+}
+
+// Old method (its API limits the available features - remove in KDE-4)
+bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensitive, bool isRegExp )
+{
+ if ( !initFindNode( false, !forward, d->m_findNode ) )
+ return false;
+ while(1)
+ {
+ if( (d->m_findNode->nodeType() == Node::TEXT_NODE || d->m_findNode->nodeType() == Node::CDATA_SECTION_NODE) && d->m_findNode->renderer() )
+ {
+ DOMString nodeText = d->m_findNode->nodeValue();
+ DOMStringImpl *t = nodeText.implementation();
+ QConstString s(t->s, t->l);
+
+ int matchLen = 0;
+ if ( isRegExp ) {
+ QRegExp matcher( str );
+ matcher.setCaseSensitive( caseSensitive );
+ d->m_findPos = matcher.search(s.string(), d->m_findPos+1);
+ if ( d->m_findPos != -1 )
+ matchLen = matcher.matchedLength();
+ }
+ else {
+ d->m_findPos = s.string().find(str, d->m_findPos+1, caseSensitive);
+ matchLen = str.length();
+ }
+
+ if(d->m_findPos != -1)
+ {
+ int x = 0, y = 0;
+ if(static_cast<khtml::RenderText *>(d->m_findNode->renderer())
+ ->posOfChar(d->m_findPos, x, y))
+ d->m_view->setContentsPos(x-50, y-50);
+
+ d->m_selectionStart = d->m_findNode;
+ d->m_startOffset = d->m_findPos;
+ d->m_selectionEnd = d->m_findNode;
+ d->m_endOffset = d->m_findPos + matchLen;
+ d->m_startBeforeEnd = true;
+
+ d->m_doc->setSelection( d->m_selectionStart.handle(), d->m_startOffset,
+ d->m_selectionEnd.handle(), d->m_endOffset );
+ emitSelectionChanged();
+ return true;
+ }
+ }
+ d->m_findPos = -1;
+
+ NodeImpl *next;
+
+ if ( forward )
+ {
+ next = d->m_findNode->firstChild();
+
+ if(!next) next = d->m_findNode->nextSibling();
+ while(d->m_findNode && !next) {
+ d->m_findNode = d->m_findNode->parentNode();
+ if( d->m_findNode ) {
+ next = d->m_findNode->nextSibling();
+ }
+ }
+ }
+ else
+ {
+ next = d->m_findNode->lastChild();
+
+ if (!next ) next = d->m_findNode->previousSibling();
+ while ( d->m_findNode && !next )
+ {
+ d->m_findNode = d->m_findNode->parentNode();
+ if( d->m_findNode )
+ {
+ next = d->m_findNode->previousSibling();
+ }
+ }
+ }
+
+ d->m_findNode = next;
+ if(!d->m_findNode) return false;
+ }
+}
+
+
+void KHTMLPart::slotFind()
+{
+ KParts::ReadOnlyPart *part = currentFrame();
+ if (!part)
+ return;
+ if (!part->inherits("KHTMLPart") )
+ {
+ kdError(6000) << "slotFind: part is a " << part->className() << ", can't do a search into it" << endl;
+ return;
+ }
+ static_cast<KHTMLPart *>( part )->findText();
+}
+
+void KHTMLPart::slotFindNext()
+{
+ KParts::ReadOnlyPart *part = currentFrame();
+ if (!part)
+ return;
+ if (!part->inherits("KHTMLPart") )
+ {
+ kdError(6000) << "slotFindNext: part is a " << part->className() << ", can't do a search into it" << endl;
+ return;
+ }
+ static_cast<KHTMLPart *>( part )->findTextNext();
+}
+
+void KHTMLPart::slotFindPrev()
+{
+ KParts::ReadOnlyPart *part = currentFrame();
+ if (!part)
+ return;
+ if (!part->inherits("KHTMLPart") )
+ {
+ kdError(6000) << "slotFindNext: part is a " << part->className() << ", can't do a search into it" << endl;
+ return;
+ }
+ static_cast<KHTMLPart *>( part )->findTextNext( true ); // reverse
+}
+
+void KHTMLPart::slotFindDone()
+{
+ // ### remove me
+}
+
+void KHTMLPart::slotFindAheadText()
+{
+#ifndef KHTML_NO_TYPE_AHEAD_FIND
+ KParts::ReadOnlyPart *part = currentFrame();
+ if (!part)
+ return;
+ if (!part->inherits("KHTMLPart") )
+ {
+ kdError(6000) << "slotFindNext: part is a " << part->className() << ", can't do a search into it" << endl;
+ return;
+ }
+ static_cast<KHTMLPart *>( part )->view()->startFindAhead( false );
+#endif // KHTML_NO_TYPE_AHEAD_FIND
+}
+
+void KHTMLPart::slotFindAheadLink()
+{
+#ifndef KHTML_NO_TYPE_AHEAD_FIND
+ KParts::ReadOnlyPart *part = currentFrame();
+ if (!part)
+ return;
+ if (!part->inherits("KHTMLPart") )
+ {
+ kdError(6000) << "slotFindNext: part is a " << part->className() << ", can't do a search into it" << endl;
+ return;
+ }
+ static_cast<KHTMLPart *>( part )->view()->startFindAhead( true );
+#endif // KHTML_NO_TYPE_AHEAD_FIND
+}
+
+void KHTMLPart::enableFindAheadActions( bool enable )
+{
+ // only the topmost one has shortcuts
+ KHTMLPart* p = this;
+ while( p->parentPart())
+ p = p->parentPart();
+ p->d->m_paFindAheadText->setEnabled( enable );
+ p->d->m_paFindAheadLinks->setEnabled( enable );
+}
+
+void KHTMLPart::slotFindDialogDestroyed()
+{
+ d->m_lastFindState.options = d->m_findDialog->options();
+ d->m_lastFindState.history = d->m_findDialog->findHistory();
+ d->m_findDialog->deleteLater();
+ d->m_findDialog = 0L;
+}
+
+void KHTMLPart::findText()
+{
+ // First do some init to make sure we can search in this frame
+ if ( !d->m_doc )
+ return;
+
+ // Raise if already opened
+ if ( d->m_findDialog )
+ {
+ KWin::activateWindow( d->m_findDialog->winId() );
+ return;
+ }
+
+ // The lineedit of the dialog would make khtml lose its selection, otherwise
+#ifndef QT_NO_CLIPBOARD
+ disconnect( kapp->clipboard(), SIGNAL(selectionChanged()), this, SLOT(slotClearSelection()) );
+#endif
+
+ // Now show the dialog in which the user can choose options.
+ d->m_findDialog = new KFindDialog( false /*non-modal*/, widget(), "khtmlfind" );
+ d->m_findDialog->setHasSelection( hasSelection() );
+ d->m_findDialog->setHasCursor( d->m_findNode != 0 );
+ if ( d->m_findNode ) // has a cursor -> default to 'FromCursor'
+ d->m_lastFindState.options |= KFindDialog::FromCursor;
+
+ // TODO? optionsDialog.setPattern( d->m_lastFindState.text );
+ d->m_findDialog->setFindHistory( d->m_lastFindState.history );
+ d->m_findDialog->setOptions( d->m_lastFindState.options );
+
+ d->m_lastFindState.options = -1; // force update in findTextNext
+ d->m_lastFindState.last_dir = -1;
+
+ d->m_findDialog->show();
+ connect( d->m_findDialog, SIGNAL(okClicked()), this, SLOT(slotFindNext()) );
+ connect( d->m_findDialog, SIGNAL(finished()), this, SLOT(slotFindDialogDestroyed()) );
+
+ findText( d->m_findDialog->pattern(), 0 /*options*/, widget(), d->m_findDialog );
+}
+
+void KHTMLPart::findText( const QString &str, long options, QWidget *parent, KFindDialog *findDialog )
+{
+ // First do some init to make sure we can search in this frame
+ if ( !d->m_doc )
+ return;
+
+#ifndef QT_NO_CLIPBOARD
+ connect( kapp->clipboard(), SIGNAL(selectionChanged()), SLOT(slotClearSelection()) );
+#endif
+
+ // Create the KFind object
+ delete d->m_find;
+ d->m_find = new KFind( str, options, parent, findDialog );
+ d->m_find->closeFindNextDialog(); // we use KFindDialog non-modal, so we don't want other dlg popping up
+ connect( d->m_find, SIGNAL( highlight( const QString &, int, int ) ),
+ this, SLOT( slotHighlight( const QString &, int, int ) ) );
+ //connect(d->m_find, SIGNAL( findNext() ),
+ // this, SLOT( slotFindNext() ) );
+
+ if ( !findDialog )
+ {
+ d->m_lastFindState.options = options;
+ initFindNode( options & KFindDialog::SelectedText,
+ options & KFindDialog::FindBackwards,
+ options & KFindDialog::FromCursor );
+ }
+}
+
+bool KHTMLPart::findTextNext()
+{
+ return findTextNext( false );
+}
+
+// New method
+bool KHTMLPart::findTextNext( bool reverse )
+{
+ if (!d->m_find)
+ {
+ // We didn't show the find dialog yet, let's do it then (#49442)
+ findText();
+ return false;
+ }
+
+ view()->updateFindAheadTimeout();
+ long options = 0;
+ if ( d->m_findDialog ) // 0 when we close the dialog
+ {
+ if ( d->m_find->pattern() != d->m_findDialog->pattern() ) {
+ d->m_find->setPattern( d->m_findDialog->pattern() );
+ d->m_find->resetCounts();
+ }
+ options = d->m_findDialog->options();
+ if ( d->m_lastFindState.options != options )
+ {
+ d->m_find->setOptions( options );
+
+ if ( options & KFindDialog::SelectedText )
+ Q_ASSERT( hasSelection() );
+
+ long difference = d->m_lastFindState.options ^ options;
+ if ( difference & (KFindDialog::SelectedText | KFindDialog::FromCursor ) )
+ {
+ // Important options changed -> reset search range
+ (void) initFindNode( options & KFindDialog::SelectedText,
+ options & KFindDialog::FindBackwards,
+ options & KFindDialog::FromCursor );
+ }
+ d->m_lastFindState.options = options;
+ }
+ } else
+ options = d->m_lastFindState.options;
+ if( reverse )
+ options = options ^ KFindDialog::FindBackwards;
+ if( d->m_find->options() != options )
+ d->m_find->setOptions( options );
+
+ // Changing find direction. Start and end nodes must be switched.
+ // Additionally since d->m_findNode points after the last node
+ // that was searched, it needs to be "after" it in the opposite direction.
+ if( d->m_lastFindState.last_dir != -1
+ && bool( d->m_lastFindState.last_dir ) != bool( options & KFindDialog::FindBackwards ))
+ {
+ qSwap( d->m_findNodeEnd, d->m_findNodeStart );
+ qSwap( d->m_findPosEnd, d->m_findPosStart );
+ qSwap( d->m_findNode, d->m_findNodePrevious );
+ // d->m_findNode now point at the end of the last searched line - advance one node
+ khtml::RenderObject* obj = d->m_findNode ? d->m_findNode->renderer() : 0;
+ khtml::RenderObject* end = d->m_findNodeEnd ? d->m_findNodeEnd->renderer() : 0;
+ if ( obj == end )
+ obj = 0L;
+ else if ( obj )
+ {
+ do {
+ obj = (options & KFindDialog::FindBackwards) ? obj->objectAbove() : obj->objectBelow();
+ } while ( obj && ( !obj->element() || obj->isInlineContinuation() ) );
+ }
+ if ( obj )
+ d->m_findNode = obj->element();
+ else
+ d->m_findNode = 0;
+ }
+ d->m_lastFindState.last_dir = ( options & KFindDialog::FindBackwards ) ? 1 : 0;
+
+ KFind::Result res = KFind::NoMatch;
+ khtml::RenderObject* obj = d->m_findNode ? d->m_findNode->renderer() : 0;
+ khtml::RenderObject* end = d->m_findNodeEnd ? d->m_findNodeEnd->renderer() : 0;
+ khtml::RenderTextArea *tmpTextArea=0L;
+ //kdDebug(6050) << k_funcinfo << "obj=" << obj << " end=" << end << endl;
+ while( res == KFind::NoMatch )
+ {
+ if ( d->m_find->needData() )
+ {
+ if ( !obj ) {
+ //kdDebug(6050) << k_funcinfo << "obj=0 -> done" << endl;
+ break; // we're done
+ }
+ //kdDebug(6050) << k_funcinfo << " gathering data" << endl;
+ // First make up the QString for the current 'line' (i.e. up to \n)
+ // We also want to remember the DOMNode for every portion of the string.
+ // We store this in an index->node list.
+
+ d->m_stringPortions.clear();
+ bool newLine = false;
+ QString str;
+ DOM::NodeImpl* lastNode = d->m_findNode;
+ while ( obj && !newLine )
+ {
+ // Grab text from render object
+ QString s;
+ bool renderAreaText = obj->parent() && (QCString(obj->parent()->renderName())== "RenderTextArea");
+ bool renderLineText = (QCString(obj->renderName())== "RenderLineEdit");
+ if ( renderAreaText )
+ {
+ khtml::RenderTextArea *parent= static_cast<khtml::RenderTextArea *>(obj->parent());
+ s = parent->text();
+ s = s.replace(0xa0, ' ');
+ tmpTextArea = parent;
+ }
+ else if ( renderLineText )
+ {
+ khtml::RenderLineEdit *parentLine= static_cast<khtml::RenderLineEdit *>(obj);
+ if (parentLine->widget()->echoMode() == QLineEdit::Normal)
+ s = parentLine->widget()->text();
+ s = s.replace(0xa0, ' ');
+ }
+ else if ( obj->isText() )
+ {
+ bool isLink = false;
+
+ // checks whether the node has a <A> parent
+ if ( options & FindLinksOnly )
+ {
+ DOM::NodeImpl *parent = obj->element();
+ while ( parent )
+ {
+ if ( parent->nodeType() == Node::ELEMENT_NODE && parent->id() == ID_A )
+ {
+ isLink = true;
+ break;
+ }
+ parent = parent->parentNode();
+ }
+ }
+ else
+ {
+ isLink = true;
+ }
+
+ if ( isLink && obj->parent()!=tmpTextArea )
+ {
+ s = static_cast<khtml::RenderText *>(obj)->data().string();
+ s = s.replace(0xa0, ' ');
+ }
+ }
+ else if ( obj->isBR() )
+ s = '\n';
+ else if ( !obj->isInline() && !str.isEmpty() )
+ s = '\n';
+
+ if ( lastNode == d->m_findNodeEnd )
+ s.truncate( d->m_findPosEnd );
+ if ( !s.isEmpty() )
+ {
+ newLine = s.find( '\n' ) != -1; // did we just get a newline?
+ if( !( options & KFindDialog::FindBackwards ))
+ {
+ //kdDebug(6050) << "StringPortion: " << index << "-" << index+s.length()-1 << " -> " << lastNode << endl;
+ d->m_stringPortions.append( KHTMLPartPrivate::StringPortion( str.length(), lastNode ) );
+ str += s;
+ }
+ else // KFind itself can search backwards, so str must not be built backwards
+ {
+ for( QValueList<KHTMLPartPrivate::StringPortion>::Iterator it = d->m_stringPortions.begin();
+ it != d->m_stringPortions.end();
+ ++it )
+ (*it).index += s.length();
+ d->m_stringPortions.prepend( KHTMLPartPrivate::StringPortion( 0, lastNode ) );
+ str.prepend( s );
+ }
+ }
+ // Compare obj and end _after_ we processed the 'end' node itself
+ if ( obj == end )
+ obj = 0L;
+ else
+ {
+ // Move on to next object (note: if we found a \n already, then obj (and lastNode)
+ // will point to the _next_ object, i.e. they are in advance.
+ do {
+ // We advance until the next RenderObject that has a NodeImpl as its element().
+ // Otherwise (if we keep the 'last node', and it has a '\n') we might be stuck
+ // on that object forever...
+ obj = (options & KFindDialog::FindBackwards) ? obj->objectAbove() : obj->objectBelow();
+ } while ( obj && ( !obj->element() || obj->isInlineContinuation() ) );
+ }
+ if ( obj )
+ lastNode = obj->element();
+ else
+ lastNode = 0;
+ } // end while
+ //kdDebug()<<" str : "<<str<<endl;
+ if ( !str.isEmpty() )
+ {
+ d->m_find->setData( str, d->m_findPos );
+ }
+
+ d->m_findPos = -1; // not used during the findnext loops. Only during init.
+ d->m_findNodePrevious = d->m_findNode;
+ d->m_findNode = lastNode;
+ }
+ if ( !d->m_find->needData() ) // happens if str was empty
+ {
+ // Let KFind inspect the text fragment, and emit highlighted if a match is found
+ res = d->m_find->find();
+ }
+ } // end while
+
+ if ( res == KFind::NoMatch ) // i.e. we're done
+ {
+ kdDebug() << "No more matches." << endl;
+ if ( !(options & FindNoPopups) && d->m_find->shouldRestart() )
+ {
+ //kdDebug(6050) << "Restarting" << endl;
+ initFindNode( false, options & KFindDialog::FindBackwards, false );
+ d->m_find->resetCounts();
+ findTextNext( reverse );
+ }
+ else // really done
+ {
+ //kdDebug(6050) << "Finishing" << endl;
+ //delete d->m_find;
+ //d->m_find = 0L;
+ initFindNode( false, options & KFindDialog::FindBackwards, false );
+ d->m_find->resetCounts();
+ slotClearSelection();
+ }
+ kdDebug() << "Dialog closed." << endl;
+ }
+
+ return res == KFind::Match;
+}
+
+void KHTMLPart::slotHighlight( const QString& /*text*/, int index, int length )
+{
+ //kdDebug(6050) << "slotHighlight index=" << index << " length=" << length << endl;
+ QValueList<KHTMLPartPrivate::StringPortion>::Iterator it = d->m_stringPortions.begin();
+ const QValueList<KHTMLPartPrivate::StringPortion>::Iterator itEnd = d->m_stringPortions.end();
+ QValueList<KHTMLPartPrivate::StringPortion>::Iterator prev = it;
+ // We stop at the first portion whose index is 'greater than', and then use the previous one
+ while ( it != itEnd && (*it).index <= index )
+ {
+ prev = it;
+ ++it;
+ }
+ Q_ASSERT ( prev != itEnd );
+ DOM::NodeImpl* node = (*prev).node;
+ Q_ASSERT( node );
+
+ d->m_selectionStart = node;
+ d->m_startOffset = index - (*prev).index;
+
+ khtml::RenderObject* obj = node->renderer();
+ khtml::RenderTextArea *parent = 0L;
+ khtml::RenderLineEdit *parentLine = 0L;
+ bool renderLineText =false;
+
+ QRect highlightedRect;
+ bool renderAreaText =false;
+ Q_ASSERT( obj );
+ if ( obj )
+ {
+ int x = 0, y = 0;
+ renderAreaText = (QCString(obj->parent()->renderName())== "RenderTextArea");
+ renderLineText = (QCString(obj->renderName())== "RenderLineEdit");
+
+
+ if( renderAreaText )
+ parent= static_cast<khtml::RenderTextArea *>(obj->parent());
+ if ( renderLineText )
+ parentLine= static_cast<khtml::RenderLineEdit *>(obj);
+ if ( !renderLineText )
+ //if (static_cast<khtml::RenderText *>(node->renderer())
+ // ->posOfChar(d->m_startOffset, x, y))
+ {
+ int dummy;
+ static_cast<khtml::RenderText *>(node->renderer())
+ ->caretPos( d->m_startOffset, false, x, y, dummy, dummy ); // more precise than posOfChar
+ //kdDebug(6050) << "topleft: " << x << "," << y << endl;
+ if ( x != -1 || y != -1 )
+ {
+ int gox = d->m_view->contentsX();
+ if (x+50 > d->m_view->contentsX() + d->m_view->visibleWidth())
+ gox = x - d->m_view->visibleWidth() + 50;
+ if (x-10 < d->m_view->contentsX())
+ gox = x - d->m_view->visibleWidth() - 10;
+ if (gox < 0) gox = 0;
+ d->m_view->setContentsPos(gox, y-50);
+ highlightedRect.setTopLeft( d->m_view->mapToGlobal(QPoint(x, y)) );
+ }
+ }
+ }
+ // Now look for end node
+ it = prev; // no need to start from beginning again
+ while ( it != itEnd && (*it).index < index + length )
+ {
+ prev = it;
+ ++it;
+ }
+ Q_ASSERT ( prev != itEnd );
+
+ d->m_selectionEnd = (*prev).node;
+ d->m_endOffset = index + length - (*prev).index;
+ d->m_startBeforeEnd = true;
+
+ // if the selection is limited to a single link, that link gets focus
+ if(d->m_selectionStart == d->m_selectionEnd)
+ {
+ bool isLink = false;
+
+ // checks whether the node has a <A> parent
+ DOM::NodeImpl *parent = d->m_selectionStart.handle();
+ while ( parent )
+ {
+ if ( parent->nodeType() == Node::ELEMENT_NODE && parent->id() == ID_A )
+ {
+ isLink = true;
+ break;
+ }
+ parent = parent->parentNode();
+ }
+
+ if(isLink == true)
+ {
+ d->m_doc->setFocusNode( parent );
+ }
+ }
+
+#if 0
+ kdDebug(6050) << "slotHighlight: " << d->m_selectionStart.handle() << "," << d->m_startOffset << " - " <<
+ d->m_selectionEnd.handle() << "," << d->m_endOffset << endl;
+ it = d->m_stringPortions.begin();
+ for ( ; it != d->m_stringPortions.end() ; ++it )
+ kdDebug(6050) << " StringPortion: from index=" << (*it).index << " -> node=" << (*it).node << endl;
+#endif
+ if( renderAreaText )
+ {
+ if( parent )
+ parent->highLightWord( length, d->m_endOffset-length );
+ }
+ else if ( renderLineText )
+ {
+ if( parentLine )
+ parentLine->highLightWord( length, d->m_endOffset-length );
+ }
+ else
+ {
+ d->m_doc->setSelection( d->m_selectionStart.handle(), d->m_startOffset,
+ d->m_selectionEnd.handle(), d->m_endOffset );
+ if (d->m_selectionEnd.handle()->renderer() )
+ {
+ int x, y, height, dummy;
+ static_cast<khtml::RenderText *>(d->m_selectionEnd.handle()->renderer())
+ ->caretPos( d->m_endOffset, false, x, y, dummy, height ); // more precise than posOfChar
+ //kdDebug(6050) << "bottomright: " << x << "," << y+height << endl;
+ if ( x != -1 || y != -1 )
+ {
+ // if ( static_cast<khtml::RenderText *>(d->m_selectionEnd.handle()->renderer())
+ // ->posOfChar(d->m_endOffset-1, x, y))
+ highlightedRect.setBottomRight( d->m_view->mapToGlobal( QPoint(x, y+height) ) );
+ }
+ }
+ }
+ emitSelectionChanged();
+
+ // make the finddialog move away from the selected area
+ if ( d->m_findDialog && !highlightedRect.isNull() )
+ {
+ highlightedRect.moveBy( -d->m_view->contentsX(), -d->m_view->contentsY() );
+ //kdDebug(6050) << "avoiding " << highlightedRect << endl;
+ KDialog::avoidArea( d->m_findDialog, highlightedRect );
+ }
+}
+
+QString KHTMLPart::selectedTextAsHTML() const
+{
+ if(!hasSelection()) {
+ kdDebug() << "selectedTextAsHTML(): selection is not valid. Returning empty selection" << endl;
+ return QString::null;
+ }
+ if(d->m_startOffset < 0 || d->m_endOffset <0) {
+ kdDebug() << "invalid values for end/startOffset " << d->m_startOffset << " " << d->m_endOffset << endl;
+ return QString::null;
+ }
+ DOM::Range r = selection();
+ if(r.isNull() || r.isDetached())
+ return QString::null;
+ int exceptioncode = 0; //ignore the result
+ return r.handle()->toHTML(exceptioncode).string();
+}
+
+QString KHTMLPart::selectedText() const
+{
+ bool hasNewLine = true;
+ bool seenTDTag = false;
+ QString text;
+ DOM::Node n = d->m_selectionStart;
+ while(!n.isNull()) {
+ if(n.nodeType() == DOM::Node::TEXT_NODE && n.handle()->renderer()) {
+ DOM::DOMStringImpl *dstr = static_cast<DOM::TextImpl*>(n.handle())->renderString();
+ QString str(dstr->s, dstr->l);
+ if(!str.isEmpty()) {
+ if(seenTDTag) {
+ text += " ";
+ seenTDTag = false;
+ }
+ hasNewLine = false;
+ if(n == d->m_selectionStart && n == d->m_selectionEnd)
+ text = str.mid(d->m_startOffset, d->m_endOffset - d->m_startOffset);
+ else if(n == d->m_selectionStart)
+ text = str.mid(d->m_startOffset);
+ else if(n == d->m_selectionEnd)
+ text += str.left(d->m_endOffset);
+ else
+ text += str;
+ }
+ }
+ else {
+ // This is our simple HTML -> ASCII transformation:
+ unsigned short id = n.elementId();
+ switch(id) {
+ case ID_TEXTAREA:
+ text += static_cast<HTMLTextAreaElementImpl*>(n.handle())->value().string();
+ break;
+ case ID_INPUT:
+ if (static_cast<HTMLInputElementImpl*>(n.handle())->inputType() != HTMLInputElementImpl::PASSWORD)
+ text += static_cast<HTMLInputElementImpl*>(n.handle())->value().string();
+ break;
+ case ID_SELECT:
+ text += static_cast<HTMLSelectElementImpl*>(n.handle())->value().string();
+ break;
+ case ID_BR:
+ text += "\n";
+ hasNewLine = true;
+ break;
+ case ID_IMG:
+ text += static_cast<HTMLImageElementImpl*>(n.handle())->altText().string();
+ break;
+ case ID_TD:
+ break;
+ case ID_TH:
+ case ID_HR:
+ case ID_OL:
+ case ID_UL:
+ case ID_LI:
+ case ID_DD:
+ case ID_DL:
+ case ID_DT:
+ case ID_PRE:
+ case ID_BLOCKQUOTE:
+ case ID_DIV:
+ if (!hasNewLine)
+ text += "\n";
+ hasNewLine = true;
+ break;
+ case ID_P:
+ case ID_TR:
+ case ID_H1:
+ case ID_H2:
+ case ID_H3:
+ case ID_H4:
+ case ID_H5:
+ case ID_H6:
+ if (!hasNewLine)
+ text += "\n";
+// text += "\n";
+ hasNewLine = true;
+ break;
+ }
+ }
+ if(n == d->m_selectionEnd) break;
+ DOM::Node next = n.firstChild();
+ if(next.isNull()) next = n.nextSibling();
+ while( next.isNull() && !n.parentNode().isNull() ) {
+ n = n.parentNode();
+ next = n.nextSibling();
+ unsigned short id = n.elementId();
+ switch(id) {
+ case ID_TD:
+ seenTDTag = true; //Add two spaces after a td if then followed by text.
+ break;
+ case ID_TH:
+ case ID_HR:
+ case ID_OL:
+ case ID_UL:
+ case ID_LI:
+ case ID_DD:
+ case ID_DL:
+ case ID_DT:
+ case ID_PRE:
+ case ID_BLOCKQUOTE:
+ case ID_DIV:
+ seenTDTag = false;
+ if (!hasNewLine)
+ text += "\n";
+ hasNewLine = true;
+ break;
+ case ID_P:
+ case ID_TR:
+ case ID_H1:
+ case ID_H2:
+ case ID_H3:
+ case ID_H4:
+ case ID_H5:
+ case ID_H6:
+ if (!hasNewLine)
+ text += "\n";
+// text += "\n";
+ hasNewLine = true;
+ break;
+ }
+ }
+
+ n = next;
+ }
+
+ if(text.isEmpty())
+ return QString::null;
+
+ int start = 0;
+ int end = text.length();
+
+ // Strip leading LFs
+ while ((start < end) && (text[start] == '\n'))
+ ++start;
+
+ // Strip excessive trailing LFs
+ while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n'))
+ --end;
+
+ return text.mid(start, end-start);
+}
+
+bool KHTMLPart::hasSelection() const
+{
+ if ( d->m_selectionStart.isNull() || d->m_selectionEnd.isNull() )
+ return false;
+ if ( d->m_selectionStart == d->m_selectionEnd &&
+ d->m_startOffset == d->m_endOffset )
+ return false; // empty
+ return true;
+}
+
+DOM::Range KHTMLPart::selection() const
+{
+ if( d->m_selectionStart.isNull() || d->m_selectionEnd.isNull() )
+ return DOM::Range();
+ DOM::Range r = document().createRange();
+ RangeImpl *rng = r.handle();
+ int exception = 0;
+ NodeImpl *n = d->m_selectionStart.handle();
+ if(!n->parentNode() ||
+ !n->renderer() ||
+ (!n->renderer()->isReplaced() && !n->renderer()->isBR())) {
+ rng->setStart( n, d->m_startOffset, exception );
+ if(exception) {
+ kdDebug(6000) << "1 -selection() threw the exception " << exception << ". Returning empty range." << endl;
+ return DOM::Range();
+ }
+ } else {
+ int o_start = 0;
+ while ((n = n->previousSibling()))
+ o_start++;
+ rng->setStart( d->m_selectionStart.parentNode().handle(), o_start + d->m_startOffset, exception );
+ if(exception) {
+ kdDebug(6000) << "2 - selection() threw the exception " << exception << ". Returning empty range." << endl;
+ return DOM::Range();
+ }
+
+ }
+
+ n = d->m_selectionEnd.handle();
+ if(!n->parentNode() ||
+ !n->renderer() ||
+ (!n->renderer()->isReplaced() && !n->renderer()->isBR())) {
+
+ rng->setEnd( n, d->m_endOffset, exception );
+ if(exception) {
+ kdDebug(6000) << "3 - selection() threw the exception " << exception << ". Returning empty range." << endl;
+ return DOM::Range();
+ }
+
+ } else {
+ int o_end = 0;
+ while ((n = n->previousSibling()))
+ o_end++;
+ rng->setEnd( d->m_selectionEnd.parentNode().handle(), o_end + d->m_endOffset, exception);
+ if(exception) {
+ kdDebug(6000) << "4 - selection() threw the exception " << exception << ". Returning empty range." << endl;
+ return DOM::Range();
+ }
+
+ }
+
+ return r;
+}
+
+void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const
+{
+ s = d->m_selectionStart;
+ so = d->m_startOffset;
+ e = d->m_selectionEnd;
+ eo = d->m_endOffset;
+}
+
+void KHTMLPart::setSelection( const DOM::Range &r )
+{
+ // Quick-fix: a collapsed range shouldn't select the whole node.
+ // The real problem is in RenderCanvas::setSelection though (when index==0 the whole node is selected).
+ if ( r.collapsed() )
+ slotClearSelection();
+ else {
+ d->m_selectionStart = r.startContainer();
+ d->m_startOffset = r.startOffset();
+ d->m_selectionEnd = r.endContainer();
+ d->m_endOffset = r.endOffset();
+ d->m_doc->setSelection(d->m_selectionStart.handle(),d->m_startOffset,
+ d->m_selectionEnd.handle(),d->m_endOffset);
+#ifndef KHTML_NO_CARET
+ bool v = d->m_view->placeCaret();
+ emitCaretPositionChanged(v ? d->caretNode() : 0, d->caretOffset());
+#endif
+ }
+}
+
+void KHTMLPart::slotClearSelection()
+{
+ bool hadSelection = hasSelection();
+#ifndef KHTML_NO_CARET
+ //kdDebug(6000) << "d->m_selectionStart " << d->m_selectionStart.handle()
+ // << " d->m_selectionEnd " << d->m_selectionEnd.handle() << endl;
+ // nothing, leave selection parameters as is
+#else
+ d->m_selectionStart = 0;
+ d->m_startOffset = 0;
+ d->m_selectionEnd = 0;
+ d->m_endOffset = 0;
+#endif
+ if ( d->m_doc ) d->m_doc->clearSelection();
+ if ( hadSelection )
+ emitSelectionChanged();
+#ifndef KHTML_NO_CARET
+ bool v = d->m_view->placeCaret();
+ emitCaretPositionChanged(v ? d->caretNode() : 0, d->caretOffset());
+#endif
+}
+
+void KHTMLPart::resetHoverText()
+{
+ if( !d->m_overURL.isEmpty() ) // Only if we were showing a link
+ {
+ d->m_overURL = d->m_overURLTarget = QString::null;
+ emit onURL( QString::null );
+ // revert to default statusbar text
+ setStatusBarText(QString::null, BarHoverText);
+ emit d->m_extension->mouseOverInfo(0);
+ }
+}
+
+void KHTMLPart::overURL( const QString &url, const QString &target, bool /*shiftPressed*/ )
+{
+ KURL u = completeURL(url);
+
+ // special case for <a href="">
+ if ( url.isEmpty() )
+ u.setFileName( url );
+
+ emit onURL( url );
+
+ if ( url.isEmpty() ) {
+ setStatusBarText(u.htmlURL(), BarHoverText);
+ return;
+ }
+
+ if (url.find( QString::fromLatin1( "javascript:" ),0, false ) == 0 ) {
+ QString jscode = KURL::decode_string( url.mid( url.find( "javascript:", 0, false ) ) );
+ jscode = KStringHandler::rsqueeze( jscode, 80 ); // truncate if too long
+ if (url.startsWith("javascript:window.open"))
+ jscode += i18n(" (In new window)");
+ setStatusBarText( QStyleSheet::escape( jscode ), BarHoverText );
+ return;
+ }
+
+ KFileItem item(u, QString::null, KFileItem::Unknown);
+ emit d->m_extension->mouseOverInfo(&item);
+
+ QString com;
+
+ KMimeType::Ptr typ = KMimeType::findByURL( u );
+
+ if ( typ )
+ com = typ->comment( u, false );
+
+ if ( !u.isValid() ) {
+ setStatusBarText(u.htmlURL(), BarHoverText);
+ return;
+ }
+
+ if ( u.isLocalFile() )
+ {
+ // TODO : use KIO::stat() and create a KFileItem out of its result,
+ // to use KFileItem::statusBarText()
+ QCString path = QFile::encodeName( u.path() );
+
+ struct stat buff;
+ bool ok = !stat( path.data(), &buff );
+
+ struct stat lbuff;
+ if (ok) ok = !lstat( path.data(), &lbuff );
+
+ QString text = u.htmlURL();
+ QString text2 = text;
+
+ if (ok && S_ISLNK( lbuff.st_mode ) )
+ {
+ QString tmp;
+ if ( com.isNull() )
+ tmp = i18n( "Symbolic Link");
+ else
+ tmp = i18n("%1 (Link)").arg(com);
+ char buff_two[1024];
+ text += " -> ";
+ int n = readlink ( path.data(), buff_two, 1022);
+ if (n == -1)
+ {
+ text2 += " ";
+ text2 += tmp;
+ setStatusBarText(text2, BarHoverText);
+ return;
+ }
+ buff_two[n] = 0;
+
+ text += buff_two;
+ text += " ";
+ text += tmp;
+ }
+ else if ( ok && S_ISREG( buff.st_mode ) )
+ {
+ if (buff.st_size < 1024)
+ text = i18n("%2 (%1 bytes)").arg((long) buff.st_size).arg(text2); // always put the URL last, in case it contains '%'
+ else
+ {
+ float d = (float) buff.st_size/1024.0;
+ text = i18n("%2 (%1 K)").arg(KGlobal::locale()->formatNumber(d, 2)).arg(text2); // was %.2f
+ }
+ text += " ";
+ text += com;
+ }
+ else if ( ok && S_ISDIR( buff.st_mode ) )
+ {
+ text += " ";
+ text += com;
+ }
+ else
+ {
+ text += " ";
+ text += com;
+ }
+ setStatusBarText(text, BarHoverText);
+ }
+ else
+ {
+ QString extra;
+ if (target.lower() == "_blank")
+ {
+ extra = i18n(" (In new window)");
+ }
+ else if (!target.isEmpty() &&
+ (target.lower() != "_top") &&
+ (target.lower() != "_self") &&
+ (target.lower() != "_parent"))
+ {
+ KHTMLPart *p = this;
+ while (p->parentPart())
+ p = p->parentPart();
+ if (!p->frameExists(target))
+ extra = i18n(" (In new window)");
+ else
+ extra = i18n(" (In other frame)");
+ }
+
+ if (u.protocol() == QString::fromLatin1("mailto")) {
+ QString mailtoMsg /* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
+ mailtoMsg += i18n("Email to: ") + KURL::decode_string(u.path());
+ QStringList queries = QStringList::split('&', u.query().mid(1));
+ QStringList::Iterator it = queries.begin();
+ const QStringList::Iterator itEnd = queries.end();
+ for (; it != itEnd; ++it)
+ if ((*it).startsWith(QString::fromLatin1("subject=")))
+ mailtoMsg += i18n(" - Subject: ") + KURL::decode_string((*it).mid(8));
+ else if ((*it).startsWith(QString::fromLatin1("cc=")))
+ mailtoMsg += i18n(" - CC: ") + KURL::decode_string((*it).mid(3));
+ else if ((*it).startsWith(QString::fromLatin1("bcc=")))
+ mailtoMsg += i18n(" - BCC: ") + KURL::decode_string((*it).mid(4));
+ mailtoMsg = QStyleSheet::escape(mailtoMsg);
+ mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), QString::null);
+ setStatusBarText("<qt>"+mailtoMsg, BarHoverText);
+ return;
+ }
+ // Is this check necessary at all? (Frerich)
+#if 0
+ else if (u.protocol() == QString::fromLatin1("http")) {
+ DOM::Node hrefNode = nodeUnderMouse().parentNode();
+ while (hrefNode.nodeName().string() != QString::fromLatin1("A") && !hrefNode.isNull())
+ hrefNode = hrefNode.parentNode();
+
+ if (!hrefNode.isNull()) {
+ DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
+ if (!hreflangNode.isNull()) {
+ QString countryCode = hreflangNode.nodeValue().string().lower();
+ // Map the language code to an appropriate country code.
+ if (countryCode == QString::fromLatin1("en"))
+ countryCode = QString::fromLatin1("gb");
+ QString flagImg = QString::fromLatin1("<img src=%1>").arg(
+ locate("locale", QString::fromLatin1("l10n/")
+ + countryCode
+ + QString::fromLatin1("/flag.png")));
+ emit setStatusBarText(flagImg + u.prettyURL() + extra);
+ }
+ }
+ }
+#endif
+ setStatusBarText(u.htmlURL() + extra, BarHoverText);
+ }
+}
+
+//
+// This executes in the active part on a click or other url selection action in
+// that active part.
+//
+void KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target, KParts::URLArgs args )
+{
+ // The member var is so that slotRedirection still calls the virtual urlSelected
+ // but is able to know if is opened a url. KDE4: just make urlSelected return a bool
+ // and move the urlSelectedIntern code back here.
+ d->m_urlSelectedOpenedURL = urlSelectedIntern( url, button, state, _target, args );
+}
+
+// Return value: true if an url was opened, false if not (e.g. error, or jumping to anchor)
+bool KHTMLPart::urlSelectedIntern( const QString &url, int button, int state, const QString &_target, KParts::URLArgs args )
+{
+ bool hasTarget = false;
+
+ QString target = _target;
+ if ( target.isEmpty() && d->m_doc )
+ target = d->m_doc->baseTarget();
+ if ( !target.isEmpty() )
+ hasTarget = true;
+
+ if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
+ {
+ crossFrameExecuteScript( target, KURL::decode_string( url.mid( 11 ) ) );
+ return false;
+ }
+
+ KURL cURL = completeURL(url);
+ // special case for <a href=""> (IE removes filename, mozilla doesn't)
+ if ( url.isEmpty() )
+ cURL.setFileName( url ); // removes filename
+
+ if ( !cURL.isValid() )
+ // ### ERROR HANDLING
+ return false;
+
+ kdDebug(6050) << this << " urlSelected: complete URL:" << cURL.url() << " target=" << target << endl;
+
+ if ( state & ControlButton )
+ {
+ args.setNewTab(true);
+ emit d->m_extension->createNewWindow( cURL, args );
+ return true;
+ }
+
+ if ( button == LeftButton && ( state & ShiftButton ) )
+ {
+ KIO::MetaData metaData;
+ metaData["referrer"] = d->m_referrer;
+ KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), cURL, metaData );
+ return false;
+ }
+
+ if (!checkLinkSecurity(cURL,
+ i18n( "<qt>This untrusted page links to<BR><B>%1</B>.<BR>Do you want to follow the link?" ),
+ i18n( "Follow" )))
+ return false;
+
+ args.frameName = target;
+
+ args.metaData().insert("main_frame_request",
+ parentPart() == 0 ? "TRUE":"FALSE");
+ args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
+ args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
+ args.metaData().insert("PropagateHttpHeader", "true");
+ args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
+ args.metaData().insert("ssl_activate_warnings", "TRUE");
+
+ if ( hasTarget && target != "_self" && target != "_top" && target != "_blank" && target != "_parent" )
+ {
+ // unknown frame names should open in a new window.
+ khtml::ChildFrame *frame = recursiveFrameRequest( this, cURL, args, false );
+ if ( frame )
+ {
+ args.metaData()["referrer"] = d->m_referrer;
+ requestObject( frame, cURL, args );
+ return true;
+ }
+ }
+
+ if (!d->m_referrer.isEmpty() && !args.metaData().contains("referrer"))
+ args.metaData()["referrer"] = d->m_referrer;
+
+
+ if ( button == NoButton && (state & ShiftButton) && (state & ControlButton) )
+ {
+ emit d->m_extension->createNewWindow( cURL, args );
+ return true;
+ }
+
+ if ( state & ShiftButton)
+ {
+ KParts::WindowArgs winArgs;
+ winArgs.lowerWindow = true;
+ KParts::ReadOnlyPart *newPart = 0;
+ emit d->m_extension->createNewWindow( cURL, args, winArgs, newPart );
+ return true;
+ }
+
+ //If we're asked to open up an anchor in the current URL, in current window,
+ //merely gotoanchor, and do not reload the new page. Note that this does
+ //not apply if the URL is the same page, but without a ref
+ if (cURL.hasRef() && (!hasTarget || target == "_self"))
+ {
+ KURL curUrl = this->url();
+ if (urlcmp(cURL.url(), curUrl.url(),
+ false, // ignore trailing / diff, IE does, even if FFox doesn't
+ true)) // don't care if the ref changes!
+ {
+ m_url = cURL;
+ emit d->m_extension->openURLNotify();
+ if ( !gotoAnchor( m_url.encodedHtmlRef()) )
+ gotoAnchor( m_url.htmlRef() );
+ emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
+ return false; // we jumped, but we didn't open a URL
+ }
+ }
+
+ if ( !d->m_bComplete && !hasTarget )
+ closeURL();
+
+ view()->viewport()->unsetCursor();
+ emit d->m_extension->openURLRequest( cURL, args );
+ return true;
+}
+
+void KHTMLPart::slotViewDocumentSource()
+{
+ KURL url(m_url);
+ bool isTempFile = false;
+ if (!(url.isLocalFile()) && KHTMLPageCache::self()->isComplete(d->m_cacheId))
+ {
+ KTempFile sourceFile(QString::null, defaultExtension());
+ if (sourceFile.status() == 0)
+ {
+ KHTMLPageCache::self()->saveData(d->m_cacheId, sourceFile.dataStream());
+ url = KURL();
+ url.setPath(sourceFile.name());
+ isTempFile = true;
+ }
+ }
+
+ (void) KRun::runURL( url, QString::fromLatin1("text/plain"), isTempFile );
+}
+
+void KHTMLPart::slotViewPageInfo()
+{
+ KHTMLInfoDlg *dlg = new KHTMLInfoDlg(NULL, "KHTML Page Info Dialog", false, WDestructiveClose);
+ dlg->_close->setGuiItem(KStdGuiItem::close());
+
+ if (d->m_doc)
+ dlg->_title->setText(d->m_doc->title().string());
+
+ // If it's a frame, set the caption to "Frame Information"
+ if ( parentPart() && d->m_doc && d->m_doc->isHTMLDocument() ) {
+ dlg->setCaption(i18n("Frame Information"));
+ }
+
+ QString editStr = QString::null;
+
+ if (!d->m_pageServices.isEmpty())
+ editStr = i18n(" <a href=\"%1\">[Properties]</a>").arg(d->m_pageServices);
+
+ QString squeezedURL = KStringHandler::csqueeze( url().prettyURL(), 80 );
+ dlg->_url->setText("<a href=\"" + url().url() + "\">" + squeezedURL + "</a>" + editStr);
+ if (lastModified().isEmpty())
+ {
+ dlg->_lastModified->hide();
+ dlg->_lmLabel->hide();
+ }
+ else
+ dlg->_lastModified->setText(lastModified());
+
+ const QString& enc = encoding();
+ if (enc.isEmpty()) {
+ dlg->_eLabel->hide();
+ dlg->_encoding->hide();
+ } else {
+ dlg->_encoding->setText(enc);
+ }
+ /* populate the list view now */
+ const QStringList headers = QStringList::split("\n", d->m_httpHeaders);
+
+ QStringList::ConstIterator it = headers.begin();
+ const QStringList::ConstIterator itEnd = headers.end();
+
+ for (; it != itEnd; ++it) {
+ const QStringList header = QStringList::split(QRegExp(":[ ]+"), *it);
+ if (header.count() != 2)
+ continue;
+ new QListViewItem(dlg->_headers, header[0], header[1]);
+ }
+
+ dlg->show();
+ /* put no code here */
+}
+
+
+void KHTMLPart::slotViewFrameSource()
+{
+ KParts::ReadOnlyPart *frame = currentFrame();
+ if ( !frame )
+ return;
+
+ KURL url = frame->url();
+ bool isTempFile = false;
+ if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
+ {
+ long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
+
+ if (KHTMLPageCache::self()->isComplete(cacheId))
+ {
+ KTempFile sourceFile(QString::null, defaultExtension());
+ if (sourceFile.status() == 0)
+ {
+ KHTMLPageCache::self()->saveData(cacheId, sourceFile.dataStream());
+ url = KURL();
+ url.setPath(sourceFile.name());
+ isTempFile = true;
+ }
+ }
+ }
+
+ (void) KRun::runURL( url, QString::fromLatin1("text/plain"), isTempFile );
+}
+
+KURL KHTMLPart::backgroundURL() const
+{
+ // ### what about XML documents? get from CSS?
+ if (!d->m_doc || !d->m_doc->isHTMLDocument())
+ return KURL();
+
+ QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
+
+ return KURL( m_url, relURL );
+}
+
+void KHTMLPart::slotSaveBackground()
+{
+ KIO::MetaData metaData;
+ metaData["referrer"] = d->m_referrer;
+ KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save Background Image As"), backgroundURL(), metaData );
+}
+
+void KHTMLPart::slotSaveDocument()
+{
+ KURL srcURL( m_url );
+
+ if ( srcURL.fileName(false).isEmpty() )
+ srcURL.setFileName( "index" + defaultExtension() );
+
+ KIO::MetaData metaData;
+ // Referre unknown?
+ KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, "text/html", d->m_cacheId );
+}
+
+void KHTMLPart::slotSecurity()
+{
+// kdDebug( 6050 ) << "Meta Data:" << endl
+// << d->m_ssl_peer_cert_subject
+// << endl
+// << d->m_ssl_peer_cert_issuer
+// << endl
+// << d->m_ssl_cipher
+// << endl
+// << d->m_ssl_cipher_desc
+// << endl
+// << d->m_ssl_cipher_version
+// << endl
+// << d->m_ssl_good_from
+// << endl
+// << d->m_ssl_good_until
+// << endl
+// << d->m_ssl_cert_state
+// << endl;
+
+ KSSLInfoDlg *kid = new KSSLInfoDlg(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
+
+ if (d->m_bSecurityInQuestion)
+ kid->setSecurityInQuestion(true);
+
+ if (d->m_ssl_in_use) {
+ KSSLCertificate *x = KSSLCertificate::fromString(d->m_ssl_peer_certificate.local8Bit());
+ if (x) {
+ // Set the chain back onto the certificate
+ const QStringList cl = QStringList::split(QString("\n"), d->m_ssl_peer_chain);
+ QPtrList<KSSLCertificate> ncl;
+
+ ncl.setAutoDelete(true);
+ QStringList::ConstIterator it = cl.begin();
+ const QStringList::ConstIterator itEnd = cl.end();
+ for (; it != itEnd; ++it) {
+ KSSLCertificate* const y = KSSLCertificate::fromString((*it).local8Bit());
+ if (y) ncl.append(y);
+ }
+
+ if (ncl.count() > 0)
+ x->chain().setChain(ncl);
+
+ kid->setup(x,
+ d->m_ssl_peer_ip,
+ m_url.url(),
+ d->m_ssl_cipher,
+ d->m_ssl_cipher_desc,
+ d->m_ssl_cipher_version,
+ d->m_ssl_cipher_used_bits.toInt(),
+ d->m_ssl_cipher_bits.toInt(),
+ (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt()
+ );
+ kid->exec();
+ delete x;
+ } else kid->exec();
+ } else kid->exec();
+}
+
+void KHTMLPart::slotSaveFrame()
+{
+ KParts::ReadOnlyPart *frame = currentFrame();
+ if ( !frame )
+ return;
+
+ KURL srcURL( frame->url() );
+
+ if ( srcURL.fileName(false).isEmpty() )
+ srcURL.setFileName( "index" + defaultExtension() );
+
+ KIO::MetaData metaData;
+ // Referrer unknown?
+ KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save Frame As" ), srcURL, metaData, "text/html" );
+}
+
+void KHTMLPart::slotSetEncoding()
+{
+ d->m_automaticDetection->setItemChecked( int( d->m_autoDetectLanguage ), false );
+ d->m_paSetEncoding->popupMenu()->setItemChecked( 0, false );
+ d->m_paSetEncoding->popupMenu()->setItemChecked( d->m_paSetEncoding->popupMenu()->idAt( 2 ), true );
+
+ QString enc = KGlobal::charsets()->encodingForName( d->m_manualDetection->currentText() );
+ setEncoding( enc, true );
+}
+
+void KHTMLPart::slotUseStylesheet()
+{
+ if (d->m_doc)
+ {
+ bool autoselect = (d->m_paUseStylesheet->currentItem() == 0);
+ d->m_sheetUsed = autoselect ? QString() : d->m_paUseStylesheet->currentText();
+ d->m_doc->updateStyleSelector();
+ }
+}
+
+void KHTMLPart::updateActions()
+{
+ bool frames = false;
+
+ QValueList<khtml::ChildFrame*>::ConstIterator it = d->m_frames.begin();
+ const QValueList<khtml::ChildFrame*>::ConstIterator end = d->m_frames.end();
+ for (; it != end; ++it )
+ if ( (*it)->m_type == khtml::ChildFrame::Frame )
+ {
+ frames = true;
+ break;
+ }
+
+ d->m_paViewFrame->setEnabled( frames );
+ d->m_paSaveFrame->setEnabled( frames );
+
+ if ( frames )
+ d->m_paFind->setText( i18n( "&Find in Frame..." ) );
+ else
+ d->m_paFind->setText( i18n( "&Find..." ) );
+
+ KParts::Part *frame = 0;
+
+ if ( frames )
+ frame = currentFrame();
+
+ bool enableFindAndSelectAll = true;
+
+ if ( frame )
+ enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
+
+ d->m_paFind->setEnabled( enableFindAndSelectAll );
+ d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
+
+ bool enablePrintFrame = false;
+
+ if ( frame )
+ {
+ QObject *ext = KParts::BrowserExtension::childObject( frame );
+ if ( ext )
+ enablePrintFrame = ext->metaObject()->slotNames().contains( "print()" );
+ }
+
+ d->m_paPrintFrame->setEnabled( enablePrintFrame );
+
+ QString bgURL;
+
+ // ### frames
+ if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
+ bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
+
+ d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
+
+ if ( d->m_paDebugScript )
+ d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
+}
+
+KParts::LiveConnectExtension *KHTMLPart::liveConnectExtension( const khtml::RenderPart *frame) const {
+ const ConstFrameIt end = d->m_objects.end();
+ for(ConstFrameIt it = d->m_objects.begin(); it != end; ++it )
+ if ((*it)->m_frame == frame)
+ return (*it)->m_liveconnect;
+ return 0L;
+}
+
+bool KHTMLPart::requestFrame( khtml::RenderPart *frame, const QString &url, const QString &frameName,
+ const QStringList &params, bool isIFrame )
+{
+ //kdDebug( 6050 ) << this << " requestFrame( ..., " << url << ", " << frameName << " )" << endl;
+ FrameIt it = d->m_frames.find( frameName );
+ if ( it == d->m_frames.end() )
+ {
+ khtml::ChildFrame * child = new khtml::ChildFrame;
+ //kdDebug( 6050 ) << "inserting new frame into frame map " << frameName << endl;
+ child->m_name = frameName;
+ it = d->m_frames.append( child );
+ }
+
+ (*it)->m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
+ (*it)->m_frame = frame;
+ (*it)->m_params = params;
+
+ // Support for <frame src="javascript:string">
+ if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
+ {
+ if ( processObjectRequest(*it, KURL("about:blank"), QString("text/html") ) ) {
+ KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>((*it)->m_part));
+
+ // See if we want to replace content with javascript: output..
+ QVariant res = p->executeScript( DOM::Node(), KURL::decode_string( url.right( url.length() - 11) ) );
+ if ( res.type() == QVariant::String ) {
+ p->begin();
+ p->write( res.asString() );
+ p->end();
+ }
+ return true;
+ }
+ return false;
+ }
+ KURL u = url.isEmpty() ? KURL() : completeURL( url );
+ return requestObject( *it, u );
+}
+
+QString KHTMLPart::requestFrameName()
+{
+ return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
+}
+
+bool KHTMLPart::requestObject( khtml::RenderPart *frame, const QString &url, const QString &serviceType,
+ const QStringList &params )
+{
+ //kdDebug( 6005 ) << "KHTMLPart::requestObject " << this << " frame=" << frame << endl;
+ khtml::ChildFrame *child = new khtml::ChildFrame;
+ FrameIt it = d->m_objects.append( child );
+ (*it)->m_frame = frame;
+ (*it)->m_type = khtml::ChildFrame::Object;
+ (*it)->m_params = params;
+
+ KParts::URLArgs args;
+ args.serviceType = serviceType;
+ if (!requestObject( *it, completeURL( url ), args ) && !(*it)->m_run) {
+ (*it)->m_bCompleted = true;
+ return false;
+ }
+ return true;
+}
+
+bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KURL &url, const KParts::URLArgs &_args )
+{
+ if (!checkLinkSecurity(url))
+ {
+ kdDebug(6005) << this << " KHTMLPart::requestObject checkLinkSecurity refused" << endl;
+ return false;
+ }
+ if ( child->m_bPreloaded )
+ {
+ kdDebug(6005) << "KHTMLPart::requestObject preload" << endl;
+ if ( child->m_frame && child->m_part )
+ child->m_frame->setWidget( child->m_part->widget() );
+
+ child->m_bPreloaded = false;
+ return true;
+ }
+
+ //kdDebug(6005) << "KHTMLPart::requestObject child=" << child << " child->m_part=" << child->m_part << endl;
+
+ KParts::URLArgs args( _args );
+
+ if ( child->m_run )
+ child->m_run->abort();
+
+ if ( child->m_part && !args.reload && urlcmp( child->m_part->url().url(), url.url(), true, true ) )
+ args.serviceType = child->m_serviceType;
+
+ child->m_args = args;
+ child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload);
+ child->m_serviceName = QString::null;
+ if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
+ child->m_args.metaData()["referrer"] = d->m_referrer;
+
+ child->m_args.metaData().insert("PropagateHttpHeader", "true");
+ child->m_args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
+ child->m_args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
+ child->m_args.metaData().insert("main_frame_request",
+ parentPart() == 0 ? "TRUE":"FALSE");
+ child->m_args.metaData().insert("ssl_was_in_use",
+ d->m_ssl_in_use ? "TRUE":"FALSE");
+ child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
+ child->m_args.metaData().insert("cross-domain", toplevelURL().url());
+
+ // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
+ if ((url.isEmpty() || url.url() == "about:blank") && args.serviceType.isEmpty())
+ args.serviceType = QString::fromLatin1( "text/html" );
+
+ if ( args.serviceType.isEmpty() ) {
+ kdDebug(6050) << "Running new KHTMLRun for " << this << " and child=" << child << endl;
+ child->m_run = new KHTMLRun( this, child, url, child->m_args, true );
+ d->m_bComplete = false; // ensures we stop it in checkCompleted...
+ return false;
+ } else {
+ return processObjectRequest( child, url, args.serviceType );
+ }
+}
+
+bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KURL &_url, const QString &mimetype )
+{
+ //kdDebug( 6050 ) << "KHTMLPart::processObjectRequest trying to create part for " << mimetype << endl;
+
+ // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
+ // by an emitting frame part (emit openURLRequest( blahurl, ... ) . A few lines below we delete the part
+ // though -> the reference becomes invalid -> crash is likely
+ KURL url( _url );
+
+ // khtmlrun called us this way to indicate a loading error
+ if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
+ {
+ child->m_bCompleted = true;
+ checkCompleted();
+ return true;
+ }
+
+ if (child->m_bNotify)
+ {
+ child->m_bNotify = false;
+ if ( !child->m_args.lockHistory() )
+ emit d->m_extension->openURLNotify();
+ }
+
+ if ( child->m_serviceType != mimetype || !child->m_part )
+ {
+ // Before attempting to load a part, check if the user wants that.
+ // Many don't like getting ZIP files embedded.
+ // However we don't want to ask for flash and other plugin things..
+ if ( child->m_type != khtml::ChildFrame::Object )
+ {
+ QString suggestedFilename;
+ if ( child->m_run )
+ suggestedFilename = child->m_run->suggestedFilename();
+
+ KParts::BrowserRun::AskSaveResult res = KParts::BrowserRun::askEmbedOrSave(
+ url, mimetype, suggestedFilename );
+ switch( res ) {
+ case KParts::BrowserRun::Save:
+ KHTMLPopupGUIClient::saveURL( widget(), i18n( "Save As" ), url, child->m_args.metaData(), QString::null, 0, suggestedFilename);
+ // fall-through
+ case KParts::BrowserRun::Cancel:
+ child->m_bCompleted = true;
+ checkCompleted();
+ return true; // done
+ default: // Open
+ break;
+ }
+ }
+
+ QStringList dummy; // the list of servicetypes handled by the part is now unused.
+ KParts::ReadOnlyPart *part = createPart( d->m_view->viewport(), child->m_name.ascii(), this, child->m_name.ascii(), mimetype, child->m_serviceName, dummy, child->m_params );
+
+ if ( !part )
+ {
+ if ( child->m_frame )
+ if (child->m_frame->partLoadingErrorNotify( child, url, mimetype ))
+ return true; // we succeeded after all (a fallback was used)
+
+ checkEmitLoadEvent();
+ return false;
+ }
+
+ //CRITICAL STUFF
+ if ( child->m_part )
+ {
+ if (!::qt_cast<KHTMLPart*>(child->m_part) && child->m_jscript)
+ child->m_jscript->clear();
+ partManager()->removePart( (KParts::ReadOnlyPart *)child->m_part );
+ delete (KParts::ReadOnlyPart *)child->m_part;
+ if (child->m_liveconnect) {
+ disconnect(child->m_liveconnect, SIGNAL(partEvent(const unsigned long, const QString &, const KParts::LiveConnectExtension::ArgList &)), child, SLOT(liveConnectEvent(const unsigned long, const QString&, const KParts::LiveConnectExtension::ArgList &)));
+ child->m_liveconnect = 0L;
+ }
+ }
+
+ child->m_serviceType = mimetype;
+ if ( child->m_frame && part->widget() )
+ child->m_frame->setWidget( part->widget() );
+
+ if ( child->m_type != khtml::ChildFrame::Object )
+ partManager()->addPart( part, false );
+// else
+// kdDebug(6005) << "AH! NO FRAME!!!!!" << endl;
+
+ child->m_part = part;
+
+ if (::qt_cast<KHTMLPart*>(part)) {
+ static_cast<KHTMLPart*>(part)->d->m_frame = child;
+ } else if (child->m_frame) {
+ child->m_liveconnect = KParts::LiveConnectExtension::childObject(part);
+ if (child->m_liveconnect)
+ connect(child->m_liveconnect, SIGNAL(partEvent(const unsigned long, const QString &, const KParts::LiveConnectExtension::ArgList &)), child, SLOT(liveConnectEvent(const unsigned long, const QString&, const KParts::LiveConnectExtension::ArgList &)));
+ }
+ KParts::StatusBarExtension *sb = KParts::StatusBarExtension::childObject(part);
+ if (sb)
+ sb->setStatusBar( d->m_statusBarExtension->statusBar() );
+
+ connect( part, SIGNAL( started( KIO::Job *) ),
+ this, SLOT( slotChildStarted( KIO::Job *) ) );
+ connect( part, SIGNAL( completed() ),
+ this, SLOT( slotChildCompleted() ) );
+ connect( part, SIGNAL( completed(bool) ),
+ this, SLOT( slotChildCompleted(bool) ) );
+ connect( part, SIGNAL( setStatusBarText( const QString & ) ),
+ this, SIGNAL( setStatusBarText( const QString & ) ) );
+ if ( part->inherits( "KHTMLPart" ) )
+ {
+ connect( this, SIGNAL( completed() ),
+ part, SLOT( slotParentCompleted() ) );
+ connect( this, SIGNAL( completed(bool) ),
+ part, SLOT( slotParentCompleted() ) );
+ // As soon as the child's document is created, we need to set its domain
+ // (but we do so only once, so it can't be simply done in the child)
+ connect( part, SIGNAL( docCreated() ),
+ this, SLOT( slotChildDocCreated() ) );
+ }
+
+ child->m_extension = KParts::BrowserExtension::childObject( part );
+
+ if ( child->m_extension )
+ {
+ connect( child->m_extension, SIGNAL( openURLNotify() ),
+ d->m_extension, SIGNAL( openURLNotify() ) );
+
+ connect( child->m_extension, SIGNAL( openURLRequestDelayed( const KURL &, const KParts::URLArgs & ) ),
+ this, SLOT( slotChildURLRequest( const KURL &, const KParts::URLArgs & ) ) );
+
+ connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ),
+ d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ) );
+ connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs &, const KParts::WindowArgs &, KParts::ReadOnlyPart *& ) ),
+ d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & , const KParts::WindowArgs &, KParts::ReadOnlyPart *&) ) );
+
+ connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ),
+ d->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ) );
+ connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ),
+ d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ) );
+ connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList &, const KParts::URLArgs &, KParts::BrowserExtension::PopupFlags ) ),
+ d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList &, const KParts::URLArgs &, KParts::BrowserExtension::PopupFlags ) ) );
+ connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ),
+ d->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ) );
+ connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ),
+ d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ) );
+ connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const KParts::URLArgs &, KParts::BrowserExtension::PopupFlags, mode_t ) ),
+ d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const KParts::URLArgs &, KParts::BrowserExtension::PopupFlags, mode_t ) ) );
+
+ connect( child->m_extension, SIGNAL( infoMessage( const QString & ) ),
+ d->m_extension, SIGNAL( infoMessage( const QString & ) ) );
+
+ connect( child->m_extension, SIGNAL( requestFocus( KParts::ReadOnlyPart * ) ),
+ this, SLOT( slotRequestFocus( KParts::ReadOnlyPart * ) ) );
+
+ child->m_extension->setBrowserInterface( d->m_extension->browserInterface() );
+ }
+ }
+ else if ( child->m_frame && child->m_part &&
+ child->m_frame->widget() != child->m_part->widget() )
+ child->m_frame->setWidget( child->m_part->widget() );
+
+ checkEmitLoadEvent();
+ // Some JS code in the load event may have destroyed the part
+ // In that case, abort
+ if ( !child->m_part )
+ return false;
+
+ if ( child->m_bPreloaded )
+ {
+ if ( child->m_frame && child->m_part )
+ child->m_frame->setWidget( child->m_part->widget() );
+
+ child->m_bPreloaded = false;
+ return true;
+ }
+
+ child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload);
+
+ // make sure the part has a way to find out about the mimetype.
+ // we actually set it in child->m_args in requestObject already,
+ // but it's useless if we had to use a KHTMLRun instance, as the
+ // point the run object is to find out exactly the mimetype.
+ child->m_args.serviceType = mimetype;
+
+ // if not a frame set child as completed
+ child->m_bCompleted = child->m_type == khtml::ChildFrame::Object;
+
+ if ( child->m_extension )
+ child->m_extension->setURLArgs( child->m_args );
+
+ if(url.protocol() == "javascript" || url.url() == "about:blank") {
+ if (!child->m_part->inherits("KHTMLPart"))
+ return false;
+
+ KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(child->m_part));
+
+ p->begin();
+ if (d->m_doc && p->d->m_doc)
+ p->d->m_doc->setBaseURL(d->m_doc->baseURL());
+ if (!url.url().startsWith("about:")) {
+ p->write(url.path());
+ } else {
+ p->m_url = url;
+ // we need a body element. testcase: <iframe id="a"></iframe><script>alert(a.document.body);</script>
+ p->write("<HTML><TITLE></TITLE><BODY></BODY></HTML>");
+ }
+ p->end();
+ return true;
+ }
+ else if ( !url.isEmpty() )
+ {
+ //kdDebug( 6050 ) << "opening " << url.url() << " in frame " << child->m_part << endl;
+ bool b = child->m_part->openURL( url );
+ if (child->m_bCompleted)
+ checkCompleted();
+ return b;
+ }
+ else
+ {
+ child->m_bCompleted = true;
+ checkCompleted();
+ return true;
+ }
+}
+
+KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, const QString &mimetype,
+ QString &serviceName, QStringList &serviceTypes,
+ const QStringList &params )
+{
+ QString constr;
+ if ( !serviceName.isEmpty() )
+ constr.append( QString::fromLatin1( "Name == '%1'" ).arg( serviceName ) );
+
+ KTrader::OfferList offers = KTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr, QString::null );
+
+ if ( offers.isEmpty() ) {
+ int pos = mimetype.find( "-plugin" );
+ if (pos < 0)
+ return 0L;
+ QString stripped_mime = mimetype.left( pos );
+ offers = KTrader::self()->query( stripped_mime, "KParts/ReadOnlyPart", constr, QString::null );
+ if ( offers.isEmpty() )
+ return 0L;
+ }
+
+ KTrader::OfferList::ConstIterator it = offers.begin();
+ const KTrader::OfferList::ConstIterator itEnd = offers.end();
+ for ( ; it != itEnd; ++it )
+ {
+ KService::Ptr service = (*it);
+
+ KLibFactory* const factory = KLibLoader::self()->factory( QFile::encodeName(service->library()) );
+ if ( factory ) {
+ KParts::ReadOnlyPart *res = 0L;
+
+ const char *className = "KParts::ReadOnlyPart";
+ if ( service->serviceTypes().contains( "Browser/View" ) )
+ className = "Browser/View";
+
+ if ( factory->inherits( "KParts::Factory" ) )
+ res = static_cast<KParts::ReadOnlyPart *>(static_cast<KParts::Factory *>( factory )->createPart( parentWidget, widgetName, parent, name, className, params ));
+ else
+ res = static_cast<KParts::ReadOnlyPart *>(factory->create( parentWidget, widgetName, className ));
+
+ if ( res ) {
+ serviceTypes = service->serviceTypes();
+ serviceName = service->name();
+ return res;
+ }
+ } else {
+ // TODO KMessageBox::error and i18n, like in KonqFactory::createView?
+ kdWarning() << QString("There was an error loading the module %1.\nThe diagnostics is:\n%2")
+ .arg(service->name()).arg(KLibLoader::self()->lastErrorMessage()) << endl;
+ }
+ }
+ return 0;
+}
+
+KParts::PartManager *KHTMLPart::partManager()
+{
+ if ( !d->m_manager && d->m_view )
+ {
+ d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this, "khtml part manager" );
+ d->m_manager->setAllowNestedParts( true );
+ connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
+ this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
+ connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ),
+ this, SLOT( slotPartRemoved( KParts::Part * ) ) );
+ }
+
+ return d->m_manager;
+}
+
+void KHTMLPart::submitFormAgain()
+{
+ disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
+ if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
+ 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 );
+
+ delete d->m_submitForm;
+ d->m_submitForm = 0;
+}
+
+void KHTMLPart::submitFormProxy( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
+{
+ submitForm(action, url, formData, _target, contentType, boundary);
+}
+
+void KHTMLPart::submitForm( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
+{
+ kdDebug(6000) << this << ": KHTMLPart::submitForm target=" << _target << " url=" << url << endl;
+ if (d->m_formNotification == KHTMLPart::Only) {
+ emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
+ return;
+ } else if (d->m_formNotification == KHTMLPart::Before) {
+ emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
+ }
+
+ KURL u = completeURL( url );
+
+ if ( !u.isValid() )
+ {
+ // ### ERROR HANDLING!
+ return;
+ }
+
+ // Form security checks
+ //
+ /*
+ * If these form security checks are still in this place in a month or two
+ * I'm going to simply delete them.
+ */
+
+ /* This is separate for a reason. It has to be _before_ all script, etc,
+ * AND I don't want to break anything that uses checkLinkSecurity() in
+ * other places.
+ */
+
+ if (!d->m_submitForm) {
+ if (u.protocol() != "https" && u.protocol() != "mailto") {
+ if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
+ int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
+ "\nA third party may be able to intercept and view this information."
+ "\nAre you sure you wish to continue?"),
+ i18n("Network Transmission"),KGuiItem(i18n("&Send Unencrypted")));
+ if (rc == KMessageBox::Cancel)
+ return;
+ } else { // Going from nonSSL -> nonSSL
+ KSSLSettings kss(true);
+ if (kss.warnOnUnencrypted()) {
+ int rc = KMessageBox::warningContinueCancel(NULL,
+ i18n("Warning: Your data is about to be transmitted across the network unencrypted."
+ "\nAre you sure you wish to continue?"),
+ i18n("Network Transmission"),
+ KGuiItem(i18n("&Send Unencrypted")),
+ "WarnOnUnencryptedForm");
+ // Move this setting into KSSL instead
+ KConfig *config = kapp->config();
+ QString grpNotifMsgs = QString::fromLatin1("Notification Messages");
+ KConfigGroupSaver saver( config, grpNotifMsgs );
+
+ if (!config->readBoolEntry("WarnOnUnencryptedForm", true)) {
+ config->deleteEntry("WarnOnUnencryptedForm");
+ config->sync();
+ kss.setWarnOnUnencrypted(false);
+ kss.save();
+ }
+ if (rc == KMessageBox::Cancel)
+ return;
+ }
+ }
+ }
+
+ if (u.protocol() == "mailto") {
+ int rc = KMessageBox::warningContinueCancel(NULL,
+ i18n("This site is attempting to submit form data via email.\n"
+ "Do you want to continue?"),
+ i18n("Network Transmission"),
+ KGuiItem(i18n("&Send Email")),
+ "WarnTriedEmailSubmit");
+
+ if (rc == KMessageBox::Cancel) {
+ return;
+ }
+ }
+ }
+
+ // End form security checks
+ //
+
+ QString urlstring = u.url();
+
+ if ( urlstring.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
+ urlstring = KURL::decode_string(urlstring);
+ crossFrameExecuteScript( _target, urlstring.right( urlstring.length() - 11) );
+ return;
+ }
+
+ if (!checkLinkSecurity(u,
+ 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?" ),
+ i18n( "Submit" )))
+ return;
+
+ KParts::URLArgs args;
+
+ if (!d->m_referrer.isEmpty())
+ args.metaData()["referrer"] = d->m_referrer;
+
+ args.metaData().insert("PropagateHttpHeader", "true");
+ args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
+ args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
+ args.metaData().insert("main_frame_request",
+ parentPart() == 0 ? "TRUE":"FALSE");
+ args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
+ args.metaData().insert("ssl_activate_warnings", "TRUE");
+//WABA: When we post a form we should treat it as the main url
+//the request should never be considered cross-domain
+//args.metaData().insert("cross-domain", toplevelURL().url());
+ args.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
+
+ // Handle mailto: forms
+ if (u.protocol() == "mailto") {
+ // 1) Check for attach= and strip it
+ QString q = u.query().mid(1);
+ QStringList nvps = QStringList::split("&", q);
+ bool triedToAttach = false;
+
+ QStringList::Iterator nvp = nvps.begin();
+ const QStringList::Iterator nvpEnd = nvps.end();
+
+// cannot be a for loop as if something is removed we don't want to do ++nvp, as
+// remove returns an iterator pointing to the next item
+
+ while (nvp != nvpEnd) {
+ const QStringList pair = QStringList::split("=", *nvp);
+ if (pair.count() >= 2) {
+ if (pair.first().lower() == "attach") {
+ nvp = nvps.remove(nvp);
+ triedToAttach = true;
+ } else {
+ ++nvp;
+ }
+ } else {
+ ++nvp;
+ }
+ }
+
+ if (triedToAttach)
+ 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");
+
+ // 2) Append body=
+ QString bodyEnc;
+ if (contentType.lower() == "multipart/form-data") {
+ // FIXME: is this correct? I suspect not
+ bodyEnc = KURL::encode_string(QString::fromLatin1(formData.data(),
+ formData.size()));
+ } else if (contentType.lower() == "text/plain") {
+ // Convention seems to be to decode, and s/&/\n/
+ QString tmpbody = QString::fromLatin1(formData.data(),
+ formData.size());
+ tmpbody.replace(QRegExp("[&]"), "\n");
+ tmpbody.replace(QRegExp("[+]"), " ");
+ tmpbody = KURL::decode_string(tmpbody); // Decode the rest of it
+ bodyEnc = KURL::encode_string(tmpbody); // Recode for the URL
+ } else {
+ bodyEnc = KURL::encode_string(QString::fromLatin1(formData.data(),
+ formData.size()));
+ }
+
+ nvps.append(QString("body=%1").arg(bodyEnc));
+ q = nvps.join("&");
+ u.setQuery(q);
+ }
+
+ if ( strcmp( action, "get" ) == 0 ) {
+ if (u.protocol() != "mailto")
+ u.setQuery( QString::fromLatin1( formData.data(), formData.size() ) );
+ args.setDoPost( false );
+ }
+ else {
+ args.postData = formData;
+ args.setDoPost( true );
+
+ // construct some user headers if necessary
+ if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
+ args.setContentType( "Content-Type: application/x-www-form-urlencoded" );
+ else // contentType must be "multipart/form-data"
+ args.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
+ }
+
+ if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
+ if( d->m_submitForm ) {
+ kdDebug(6000) << "KHTMLPart::submitForm ABORTING!" << endl;
+ return;
+ }
+ d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
+ d->m_submitForm->submitAction = action;
+ d->m_submitForm->submitUrl = url;
+ d->m_submitForm->submitFormData = formData;
+ d->m_submitForm->target = _target;
+ d->m_submitForm->submitContentType = contentType;
+ d->m_submitForm->submitBoundary = boundary;
+ connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
+ }
+ else
+ {
+ emit d->m_extension->openURLRequest( u, args );
+ }
+}
+
+void KHTMLPart::popupMenu( const QString &linkUrl )
+{
+ KURL popupURL;
+ KURL linkKURL;
+ KParts::URLArgs args;
+ QString referrer;
+ KParts::BrowserExtension::PopupFlags itemflags=KParts::BrowserExtension::ShowBookmark | KParts::BrowserExtension::ShowReload;
+
+ if ( linkUrl.isEmpty() ) { // click on background
+ KHTMLPart* khtmlPart = this;
+ while ( khtmlPart->parentPart() )
+ {
+ khtmlPart=khtmlPart->parentPart();
+ }
+ popupURL = khtmlPart->url();
+ referrer = khtmlPart->pageReferrer();
+ if (hasSelection())
+ itemflags = KParts::BrowserExtension::ShowTextSelectionItems;
+ else
+ itemflags |= KParts::BrowserExtension::ShowNavigationItems;
+ } else { // click on link
+ popupURL = completeURL( linkUrl );
+ linkKURL = popupURL;
+ referrer = this->referrer();
+
+ if (!(d->m_strSelectedURLTarget).isEmpty() &&
+ (d->m_strSelectedURLTarget.lower() != "_top") &&
+ (d->m_strSelectedURLTarget.lower() != "_self") &&
+ (d->m_strSelectedURLTarget.lower() != "_parent")) {
+ if (d->m_strSelectedURLTarget.lower() == "_blank")
+ args.setForcesNewWindow(true);
+ else {
+ KHTMLPart *p = this;
+ while (p->parentPart())
+ p = p->parentPart();
+ if (!p->frameExists(d->m_strSelectedURLTarget))
+ args.setForcesNewWindow(true);
+ }
+ }
+ }
+
+ // Danger, Will Robinson. The Popup might stay around for a much
+ // longer time than KHTMLPart. Deal with it.
+ KHTMLPopupGUIClient* client = new KHTMLPopupGUIClient( this, d->m_popupMenuXML, linkKURL );
+ QGuardedPtr<QObject> guard( client );
+
+ QString mimetype = QString::fromLatin1( "text/html" );
+ args.metaData()["referrer"] = referrer;
+
+ if (!linkUrl.isEmpty()) // over a link
+ {
+ if (popupURL.isLocalFile()) // safe to do this
+ {
+ mimetype = KMimeType::findByURL(popupURL,0,true,false)->name();
+ }
+ else // look at "extension" of link
+ {
+ const QString fname(popupURL.fileName(false));
+ if (!fname.isEmpty() && !popupURL.hasRef() && popupURL.query().isEmpty())
+ {
+ KMimeType::Ptr pmt = KMimeType::findByPath(fname,0,true);
+
+ // Further check for mime types guessed from the extension which,
+ // on a web page, are more likely to be a script delivering content
+ // of undecidable type. If the mime type from the extension is one
+ // of these, don't use it. Retain the original type 'text/html'.
+ if (pmt->name() != KMimeType::defaultMimeType() &&
+ !pmt->is("application/x-perl") &&
+ !pmt->is("application/x-perl-module") &&
+ !pmt->is("application/x-php") &&
+ !pmt->is("application/x-python-bytecode") &&
+ !pmt->is("application/x-python") &&
+ !pmt->is("application/x-shellscript"))
+ mimetype = pmt->name();
+ }
+ }
+ }
+
+ args.serviceType = mimetype;
+
+ emit d->m_extension->popupMenu( client, QCursor::pos(), popupURL, args, itemflags, S_IFREG /*always a file*/);
+
+ if ( !guard.isNull() ) {
+ delete client;
+ emit popupMenu(linkUrl, QCursor::pos());
+ d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
+ }
+}
+
+void KHTMLPart::slotParentCompleted()
+{
+ //kdDebug(6050) << this << " slotParentCompleted()" << endl;
+ if ( !d->m_redirectURL.isEmpty() && !d->m_redirectionTimer.isActive() )
+ {
+ //kdDebug(6050) << this << ": starting timer for child redirection -> " << d->m_redirectURL << endl;
+ d->m_redirectionTimer.start( 1000 * d->m_delayRedirect, true );
+ }
+}
+
+void KHTMLPart::slotChildStarted( KIO::Job *job )
+{
+ khtml::ChildFrame *child = frame( sender() );
+
+ assert( child );
+
+ child->m_bCompleted = false;
+
+ if ( d->m_bComplete )
+ {
+#if 0
+ // WABA: Looks like this belongs somewhere else
+ if ( !parentPart() ) // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes
+ {
+ emit d->m_extension->openURLNotify();
+ }
+#endif
+ d->m_bComplete = false;
+ emit started( job );
+ }
+}
+
+void KHTMLPart::slotChildCompleted()
+{
+ slotChildCompleted( false );
+}
+
+void KHTMLPart::slotChildCompleted( bool pendingAction )
+{
+ khtml::ChildFrame *child = frame( sender() );
+
+ if ( child ) {
+ kdDebug(6050) << this << " slotChildCompleted child=" << child << " m_frame=" << child->m_frame << endl;
+ child->m_bCompleted = true;
+ child->m_bPendingRedirection = pendingAction;
+ child->m_args = KParts::URLArgs();
+ }
+ checkCompleted();
+}
+
+void KHTMLPart::slotChildDocCreated()
+{
+ const KHTMLPart* htmlFrame = static_cast<const KHTMLPart *>(sender());
+ // Set domain to the frameset's domain
+ // This must only be done when loading the frameset initially (#22039),
+ // not when following a link in a frame (#44162).
+ if ( d->m_doc && d->m_doc->isHTMLDocument() )
+ {
+ if ( sender()->inherits("KHTMLPart") )
+ {
+ DOMString domain = static_cast<HTMLDocumentImpl*>(d->m_doc)->domain();
+ if (htmlFrame->d->m_doc && htmlFrame->d->m_doc->isHTMLDocument() )
+ //kdDebug(6050) << "KHTMLPart::slotChildDocCreated: url: " << htmlFrame->m_url.url() << endl;
+ static_cast<HTMLDocumentImpl*>(htmlFrame->d->m_doc)->setDomain( domain );
+ }
+ }
+ // So it only happens once
+ disconnect( htmlFrame, SIGNAL( docCreated() ), this, SLOT( slotChildDocCreated() ) );
+}
+
+void KHTMLPart::slotChildURLRequest( const KURL &url, const KParts::URLArgs &args )
+{
+ khtml::ChildFrame *child = frame( sender()->parent() );
+ KHTMLPart *callingHtmlPart = const_cast<KHTMLPart *>(dynamic_cast<const KHTMLPart *>(sender()->parent()));
+
+ // TODO: handle child target correctly! currently the script are always executed fur the parent
+ QString urlStr = url.url();
+ if ( urlStr.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
+ QString script = KURL::decode_string( urlStr.right( urlStr.length() - 11 ) );
+ executeScript( DOM::Node(), script );
+ return;
+ }
+
+ QString frameName = args.frameName.lower();
+ if ( !frameName.isEmpty() ) {
+ if ( frameName == QString::fromLatin1( "_top" ) )
+ {
+ emit d->m_extension->openURLRequest( url, args );
+ return;
+ }
+ else if ( frameName == QString::fromLatin1( "_blank" ) )
+ {
+ emit d->m_extension->createNewWindow( url, args );
+ return;
+ }
+ else if ( frameName == QString::fromLatin1( "_parent" ) )
+ {
+ KParts::URLArgs newArgs( args );
+ newArgs.frameName = QString::null;
+
+ emit d->m_extension->openURLRequest( url, newArgs );
+ return;
+ }
+ else if ( frameName != QString::fromLatin1( "_self" ) )
+ {
+ khtml::ChildFrame *_frame = recursiveFrameRequest( callingHtmlPart, url, args );
+
+ if ( !_frame )
+ {
+ emit d->m_extension->openURLRequest( url, args );
+ return;
+ }
+
+ child = _frame;
+ }
+ }
+
+ if ( child && child->m_type != khtml::ChildFrame::Object ) {
+ // Inform someone that we are about to show something else.
+ child->m_bNotify = true;
+ requestObject( child, url, args );
+ } else if ( frameName== "_self" ) // this is for embedded objects (via <object>) which want to replace the current document
+ {
+ KParts::URLArgs newArgs( args );
+ newArgs.frameName = QString::null;
+ emit d->m_extension->openURLRequest( url, newArgs );
+ }
+}
+
+void KHTMLPart::slotRequestFocus( KParts::ReadOnlyPart * )
+{
+ emit d->m_extension->requestFocus(this);
+}
+
+khtml::ChildFrame *KHTMLPart::frame( const QObject *obj )
+{
+ assert( obj->inherits( "KParts::ReadOnlyPart" ) );
+ const KParts::ReadOnlyPart* const part = static_cast<const KParts::ReadOnlyPart *>( obj );
+
+ FrameIt it = d->m_frames.begin();
+ const FrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ if ( (KParts::ReadOnlyPart *)(*it)->m_part == part )
+ return *it;
+
+ FrameIt oi = d->m_objects.begin();
+ const FrameIt oiEnd = d->m_objects.end();
+ for (; oi != oiEnd; ++oi )
+ if ( (KParts::ReadOnlyPart *)(*oi)->m_part == part )
+ return *oi;
+
+ return 0L;
+}
+
+//#define DEBUG_FINDFRAME
+
+bool KHTMLPart::checkFrameAccess(KHTMLPart *callingHtmlPart)
+{
+ if (callingHtmlPart == this)
+ return true; // trivial
+
+ if (htmlDocument().isNull()) {
+#ifdef DEBUG_FINDFRAME
+ kdDebug(6050) << "KHTMLPart::checkFrameAccess: Empty part " << this << " URL = " << m_url << endl;
+#endif
+ return false; // we are empty?
+ }
+
+ // now compare the domains
+ if (callingHtmlPart && !callingHtmlPart->htmlDocument().isNull() &&
+ !htmlDocument().isNull()) {
+ DOM::DOMString actDomain = callingHtmlPart->htmlDocument().domain();
+ DOM::DOMString destDomain = htmlDocument().domain();
+
+#ifdef DEBUG_FINDFRAME
+ kdDebug(6050) << "KHTMLPart::checkFrameAccess: actDomain = '" << actDomain.string() << "' destDomain = '" << destDomain.string() << "'" << endl;
+#endif
+
+ if (actDomain == destDomain)
+ return true;
+ }
+#ifdef DEBUG_FINDFRAME
+ else
+ {
+ kdDebug(6050) << "KHTMLPart::checkFrameAccess: Unknown part/domain " << callingHtmlPart << " tries to access part " << this << endl;
+ }
+#endif
+ return false;
+}
+
+KHTMLPart *
+KHTMLPart::findFrameParent( KParts::ReadOnlyPart *callingPart, const QString &f, khtml::ChildFrame **childFrame )
+{
+#ifdef DEBUG_FINDFRAME
+ kdDebug(6050) << "KHTMLPart::findFrameParent: this = " << this << " URL = " << m_url << " name = " << name() << " findFrameParent( " << f << " )" << endl;
+#endif
+ // Check access
+ KHTMLPart* const callingHtmlPart = dynamic_cast<KHTMLPart *>(callingPart);
+
+ if (!checkFrameAccess(callingHtmlPart))
+ return 0;
+
+ // match encoding used in KonqView::setViewName()
+ if (!childFrame && !parentPart() && (QString::fromLocal8Bit(name()) == f))
+ return this;
+
+ FrameIt it = d->m_frames.find( f );
+ const FrameIt end = d->m_frames.end();
+ if ( it != end )
+ {
+#ifdef DEBUG_FINDFRAME
+ kdDebug(6050) << "KHTMLPart::findFrameParent: FOUND!" << endl;
+#endif
+ if (childFrame)
+ *childFrame = *it;
+ return this;
+ }
+
+ it = d->m_frames.begin();
+ for (; it != end; ++it )
+ {
+ KParts::ReadOnlyPart* const p = (*it)->m_part;
+ if ( p && p->inherits( "KHTMLPart" ))
+ {
+ KHTMLPart* const frameParent = static_cast<KHTMLPart*>(p)->findFrameParent(callingPart, f, childFrame);
+ if (frameParent)
+ return frameParent;
+ }
+ }
+ return 0;
+}
+
+
+KHTMLPart *KHTMLPart::findFrame( const QString &f )
+{
+ khtml::ChildFrame *childFrame;
+ KHTMLPart *parentFrame = findFrameParent(this, f, &childFrame);
+ if (parentFrame)
+ {
+ KParts::ReadOnlyPart *p = childFrame->m_part;
+ if ( p && p->inherits( "KHTMLPart" ))
+ return static_cast<KHTMLPart *>(p);
+ }
+ return 0;
+}
+
+KParts::ReadOnlyPart *KHTMLPart::findFramePart(const QString &f)
+{
+ khtml::ChildFrame *childFrame;
+ return findFrameParent(this, f, &childFrame) ? static_cast<KParts::ReadOnlyPart *>(childFrame->m_part) : 0L;
+}
+
+KParts::ReadOnlyPart *KHTMLPart::currentFrame() const
+{
+ KParts::ReadOnlyPart* part = (KParts::ReadOnlyPart*)(this);
+ // Find active part in our frame manager, in case we are a frameset
+ // and keep doing that (in case of nested framesets).
+ // Just realized we could also do this recursively, calling part->currentFrame()...
+ while ( part && part->inherits("KHTMLPart") &&
+ static_cast<KHTMLPart *>(part)->d->m_frames.count() > 0 ) {
+ KHTMLPart* frameset = static_cast<KHTMLPart *>(part);
+ part = static_cast<KParts::ReadOnlyPart *>(frameset->partManager()->activePart());
+ if ( !part ) return frameset;
+ }
+ return part;
+}
+
+bool KHTMLPart::frameExists( const QString &frameName )
+{
+ ConstFrameIt it = d->m_frames.find( frameName );
+ if ( it == d->m_frames.end() )
+ return false;
+
+ // WABA: We only return true if the child actually has a frame
+ // set. Otherwise we might find our preloaded-selve.
+ // This happens when we restore the frameset.
+ return (!(*it)->m_frame.isNull());
+}
+
+KJSProxy *KHTMLPart::framejScript(KParts::ReadOnlyPart *framePart)
+{
+ KHTMLPart* const kp = ::qt_cast<KHTMLPart*>(framePart);
+ if (kp)
+ return kp->jScript();
+
+ FrameIt it = d->m_frames.begin();
+ const FrameIt itEnd = d->m_frames.end();
+
+ for (; it != itEnd; ++it)
+ if (framePart == (*it)->m_part) {
+ if (!(*it)->m_jscript)
+ createJScript(*it);
+ return (*it)->m_jscript;
+ }
+ return 0L;
+}
+
+KHTMLPart *KHTMLPart::parentPart()
+{
+ return ::qt_cast<KHTMLPart *>( parent() );
+}
+
+khtml::ChildFrame *KHTMLPart::recursiveFrameRequest( KHTMLPart *callingHtmlPart, const KURL &url,
+ const KParts::URLArgs &args, bool callParent )
+{
+#ifdef DEBUG_FINDFRAME
+ kdDebug( 6050 ) << "KHTMLPart::recursiveFrameRequest this = " << this << ", frame = " << args.frameName << ", url = " << url << endl;
+#endif
+ khtml::ChildFrame *childFrame;
+ KHTMLPart *childPart = findFrameParent(callingHtmlPart, args.frameName, &childFrame);
+ if (childPart)
+ {
+ if (childPart == this)
+ return childFrame;
+
+ childPart->requestObject( childFrame, url, args );
+ return 0;
+ }
+
+ if ( parentPart() && callParent )
+ {
+ khtml::ChildFrame *res = parentPart()->recursiveFrameRequest( callingHtmlPart, url, args, callParent );
+
+ if ( res )
+ parentPart()->requestObject( res, url, args );
+ }
+
+ return 0L;
+}
+
+#ifndef NDEBUG
+static int s_saveStateIndentLevel = 0;
+#endif
+
+void KHTMLPart::saveState( QDataStream &stream )
+{
+#ifndef NDEBUG
+ QString indent = QString().leftJustify( s_saveStateIndentLevel * 4, ' ' );
+ const int indentLevel = s_saveStateIndentLevel++;
+ kdDebug( 6050 ) << indent << "saveState this=" << this << " '" << name() << "' saving URL " << m_url.url() << endl;
+#endif
+
+ stream << m_url << (Q_INT32)d->m_view->contentsX() << (Q_INT32)d->m_view->contentsY()
+ << (Q_INT32) d->m_view->contentsWidth() << (Q_INT32) d->m_view->contentsHeight() << (Q_INT32) d->m_view->marginWidth() << (Q_INT32) d->m_view->marginHeight();
+
+ // save link cursor position
+ int focusNodeNumber;
+ if (!d->m_focusNodeRestored)
+ focusNodeNumber = d->m_focusNodeNumber;
+ else if (d->m_doc && d->m_doc->focusNode())
+ focusNodeNumber = d->m_doc->nodeAbsIndex(d->m_doc->focusNode());
+ else
+ focusNodeNumber = -1;
+ stream << focusNodeNumber;
+
+ // Save the doc's cache id.
+ stream << d->m_cacheId;
+
+ // Save the state of the document (Most notably the state of any forms)
+ QStringList docState;
+ if (d->m_doc)
+ {
+ docState = d->m_doc->docState();
+ }
+ stream << d->m_encoding << d->m_sheetUsed << docState;
+
+ stream << d->m_zoomFactor;
+
+ stream << d->m_httpHeaders;
+ stream << d->m_pageServices;
+ stream << d->m_pageReferrer;
+
+ // Save ssl data
+ stream << d->m_ssl_in_use
+ << d->m_ssl_peer_certificate
+ << d->m_ssl_peer_chain
+ << d->m_ssl_peer_ip
+ << d->m_ssl_cipher
+ << d->m_ssl_cipher_desc
+ << d->m_ssl_cipher_version
+ << d->m_ssl_cipher_used_bits
+ << d->m_ssl_cipher_bits
+ << d->m_ssl_cert_state
+ << d->m_ssl_parent_ip
+ << d->m_ssl_parent_cert;
+
+
+ QStringList frameNameLst, frameServiceTypeLst, frameServiceNameLst;
+ KURL::List frameURLLst;
+ QValueList<QByteArray> frameStateBufferLst;
+
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ {
+ if ( !(*it)->m_part )
+ continue;
+
+ frameNameLst << (*it)->m_name;
+ frameServiceTypeLst << (*it)->m_serviceType;
+ frameServiceNameLst << (*it)->m_serviceName;
+ frameURLLst << (*it)->m_part->url();
+
+ QByteArray state;
+ QDataStream frameStream( state, IO_WriteOnly );
+
+ if ( (*it)->m_extension )
+ (*it)->m_extension->saveState( frameStream );
+
+ frameStateBufferLst << state;
+ }
+
+ // Save frame data
+ stream << (Q_UINT32) frameNameLst.count();
+ stream << frameNameLst << frameServiceTypeLst << frameServiceNameLst << frameURLLst << frameStateBufferLst;
+#ifndef NDEBUG
+ s_saveStateIndentLevel = indentLevel;
+#endif
+}
+
+void KHTMLPart::restoreState( QDataStream &stream )
+{
+ KURL u;
+ Q_INT32 xOffset, yOffset, wContents, hContents, mWidth, mHeight;
+ Q_UINT32 frameCount;
+ QStringList frameNames, frameServiceTypes, docState, frameServiceNames;
+ KURL::List frameURLs;
+ QValueList<QByteArray> frameStateBuffers;
+ QValueList<int> fSizes;
+ QString encoding, sheetUsed;
+ long old_cacheId = d->m_cacheId;
+
+ stream >> u >> xOffset >> yOffset >> wContents >> hContents >> mWidth >> mHeight;
+
+ d->m_view->setMarginWidth( mWidth );
+ d->m_view->setMarginHeight( mHeight );
+
+ // restore link cursor position
+ // nth node is active. value is set in checkCompleted()
+ stream >> d->m_focusNodeNumber;
+ d->m_focusNodeRestored = false;
+
+ stream >> d->m_cacheId;
+
+ stream >> encoding >> sheetUsed >> docState;
+
+ d->m_encoding = encoding;
+ d->m_sheetUsed = sheetUsed;
+
+ int zoomFactor;
+ stream >> zoomFactor;
+ setZoomFactor(zoomFactor);
+
+ stream >> d->m_httpHeaders;
+ stream >> d->m_pageServices;
+ stream >> d->m_pageReferrer;
+
+ // Restore ssl data
+ stream >> d->m_ssl_in_use
+ >> d->m_ssl_peer_certificate
+ >> d->m_ssl_peer_chain
+ >> d->m_ssl_peer_ip
+ >> d->m_ssl_cipher
+ >> d->m_ssl_cipher_desc
+ >> d->m_ssl_cipher_version
+ >> d->m_ssl_cipher_used_bits
+ >> d->m_ssl_cipher_bits
+ >> d->m_ssl_cert_state
+ >> d->m_ssl_parent_ip
+ >> d->m_ssl_parent_cert;
+
+ setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
+
+ stream >> frameCount >> frameNames >> frameServiceTypes >> frameServiceNames
+ >> frameURLs >> frameStateBuffers;
+
+ d->m_bComplete = false;
+ d->m_bLoadEventEmitted = false;
+
+// kdDebug( 6050 ) << "restoreState() docState.count() = " << docState.count() << endl;
+// kdDebug( 6050 ) << "m_url " << m_url.url() << " <-> " << u.url() << endl;
+// kdDebug( 6050 ) << "m_frames.count() " << d->m_frames.count() << " <-> " << frameCount << endl;
+
+ if (d->m_cacheId == old_cacheId)
+ {
+ // Partial restore
+ d->m_redirectionTimer.stop();
+
+ FrameIt fIt = d->m_frames.begin();
+ const FrameIt fEnd = d->m_frames.end();
+
+ for (; fIt != fEnd; ++fIt )
+ (*fIt)->m_bCompleted = false;
+
+ fIt = d->m_frames.begin();
+
+ QStringList::ConstIterator fNameIt = frameNames.begin();
+ QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.begin();
+ QStringList::ConstIterator fServiceNameIt = frameServiceNames.begin();
+ KURL::List::ConstIterator fURLIt = frameURLs.begin();
+ QValueList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.begin();
+
+ for (; fIt != fEnd; ++fIt, ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt )
+ {
+ khtml::ChildFrame* const child = *fIt;
+
+// kdDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt << endl;
+
+ if ( child->m_name != *fNameIt || child->m_serviceType != *fServiceTypeIt )
+ {
+ child->m_bPreloaded = true;
+ child->m_name = *fNameIt;
+ child->m_serviceName = *fServiceNameIt;
+ processObjectRequest( child, *fURLIt, *fServiceTypeIt );
+ }
+ if ( child->m_part )
+ {
+ child->m_bCompleted = false;
+ if ( child->m_extension && !(*fBufferIt).isEmpty() )
+ {
+ QDataStream frameStream( *fBufferIt, IO_ReadOnly );
+ child->m_extension->restoreState( frameStream );
+ }
+ else
+ child->m_part->openURL( *fURLIt );
+ }
+ }
+
+ KParts::URLArgs args( d->m_extension->urlArgs() );
+ args.xOffset = xOffset;
+ args.yOffset = yOffset;
+ args.docState = docState;
+ d->m_extension->setURLArgs( args );
+
+ d->m_view->resizeContents( wContents, hContents);
+ d->m_view->setContentsPos( xOffset, yOffset );
+
+ m_url = u;
+ }
+ else
+ {
+ // Full restore.
+ closeURL();
+ // We must force a clear because we want to be sure to delete all
+ // frames.
+ d->m_bCleared = false;
+ clear();
+ d->m_encoding = encoding;
+ d->m_sheetUsed = sheetUsed;
+
+ QStringList::ConstIterator fNameIt = frameNames.begin();
+ const QStringList::ConstIterator fNameEnd = frameNames.end();
+
+ QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.begin();
+ QStringList::ConstIterator fServiceNameIt = frameServiceNames.begin();
+ KURL::List::ConstIterator fURLIt = frameURLs.begin();
+ QValueList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.begin();
+
+ for (; fNameIt != fNameEnd; ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt )
+ {
+ khtml::ChildFrame* const newChild = new khtml::ChildFrame;
+ newChild->m_bPreloaded = true;
+ newChild->m_name = *fNameIt;
+ newChild->m_serviceName = *fServiceNameIt;
+
+// kdDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt << endl;
+
+ const FrameIt childFrame = d->m_frames.append( newChild );
+
+ processObjectRequest( *childFrame, *fURLIt, *fServiceTypeIt );
+
+ (*childFrame)->m_bPreloaded = true;
+
+ if ( (*childFrame)->m_part )
+ {
+ if ( (*childFrame)->m_extension )
+ if ( (*childFrame)->m_extension && !(*fBufferIt).isEmpty() )
+ {
+ QDataStream frameStream( *fBufferIt, IO_ReadOnly );
+ (*childFrame)->m_extension->restoreState( frameStream );
+ }
+ else
+ (*childFrame)->m_part->openURL( *fURLIt );
+ }
+ }
+
+ KParts::URLArgs args( d->m_extension->urlArgs() );
+ args.xOffset = xOffset;
+ args.yOffset = yOffset;
+ args.docState = docState;
+
+ d->m_extension->setURLArgs( args );
+ if (!KHTMLPageCache::self()->isComplete(d->m_cacheId))
+ {
+ d->m_restored = true;
+ openURL( u );
+ d->m_restored = false;
+ }
+ else
+ {
+ restoreURL( u );
+ }
+ }
+
+}
+
+void KHTMLPart::show()
+{
+ if ( d->m_view )
+ d->m_view->show();
+}
+
+void KHTMLPart::hide()
+{
+ if ( d->m_view )
+ d->m_view->hide();
+}
+
+DOM::Node KHTMLPart::nodeUnderMouse() const
+{
+ return d->m_view->nodeUnderMouse();
+}
+
+DOM::Node KHTMLPart::nonSharedNodeUnderMouse() const
+{
+ return d->m_view->nonSharedNodeUnderMouse();
+}
+
+void KHTMLPart::emitSelectionChanged()
+{
+ emit d->m_extension->enableAction( "copy", hasSelection() );
+ if ( d->m_findDialog )
+ d->m_findDialog->setHasSelection( hasSelection() );
+
+ emit d->m_extension->selectionInfo( selectedText() );
+ emit selectionChanged();
+}
+
+int KHTMLPart::zoomFactor() const
+{
+ return d->m_zoomFactor;
+}
+
+// ### make the list configurable ?
+static const int zoomSizes[] = { 20, 40, 60, 80, 90, 95, 100, 105, 110, 120, 140, 160, 180, 200, 250, 300 };
+static const int zoomSizeCount = (sizeof(zoomSizes) / sizeof(int));
+static const int minZoom = 20;
+static const int maxZoom = 300;
+
+// My idea of useful stepping ;-) (LS)
+extern const int KDE_NO_EXPORT fastZoomSizes[] = { 20, 50, 75, 90, 100, 120, 150, 200, 300 };
+extern const int KDE_NO_EXPORT fastZoomSizeCount = sizeof fastZoomSizes / sizeof fastZoomSizes[0];
+
+void KHTMLPart::slotIncZoom()
+{
+ zoomIn(zoomSizes, zoomSizeCount);
+}
+
+void KHTMLPart::slotDecZoom()
+{
+ zoomOut(zoomSizes, zoomSizeCount);
+}
+
+void KHTMLPart::slotIncZoomFast()
+{
+ zoomIn(fastZoomSizes, fastZoomSizeCount);
+}
+
+void KHTMLPart::slotDecZoomFast()
+{
+ zoomOut(fastZoomSizes, fastZoomSizeCount);
+}
+
+void KHTMLPart::zoomIn(const int stepping[], int count)
+{
+ int zoomFactor = d->m_zoomFactor;
+
+ if (zoomFactor < maxZoom) {
+ // find the entry nearest to the given zoomsizes
+ for (int i = 0; i < count; ++i)
+ if (stepping[i] > zoomFactor) {
+ zoomFactor = stepping[i];
+ break;
+ }
+ setZoomFactor(zoomFactor);
+ }
+}
+
+void KHTMLPart::zoomOut(const int stepping[], int count)
+{
+ int zoomFactor = d->m_zoomFactor;
+ if (zoomFactor > minZoom) {
+ // find the entry nearest to the given zoomsizes
+ for (int i = count-1; i >= 0; --i)
+ if (stepping[i] < zoomFactor) {
+ zoomFactor = stepping[i];
+ break;
+ }
+ setZoomFactor(zoomFactor);
+ }
+}
+
+void KHTMLPart::setZoomFactor (int percent)
+{
+ if (percent < minZoom) percent = minZoom;
+ if (percent > maxZoom) percent = maxZoom;
+ if (d->m_zoomFactor == percent) return;
+ d->m_zoomFactor = percent;
+
+ if(d->m_doc) {
+ QApplication::setOverrideCursor( waitCursor );
+ if (d->m_doc->styleSelector())
+ d->m_doc->styleSelector()->computeFontSizes(d->m_doc->paintDeviceMetrics(), d->m_zoomFactor);
+ d->m_doc->recalcStyle( NodeImpl::Force );
+ QApplication::restoreOverrideCursor();
+ }
+
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
+ KParts::ReadOnlyPart* const p = ( *it )->m_part;
+ static_cast<KHTMLPart*>( p )->setZoomFactor(d->m_zoomFactor);
+ }
+
+ if ( d->m_guiProfile == BrowserViewGUI ) {
+ d->m_paDecZoomFactor->setEnabled( d->m_zoomFactor > minZoom );
+ d->m_paIncZoomFactor->setEnabled( d->m_zoomFactor < maxZoom );
+ }
+}
+
+void KHTMLPart::slotZoomView( int delta )
+{
+ if ( delta < 0 )
+ slotIncZoom();
+ else
+ slotDecZoom();
+}
+
+void KHTMLPart::setStatusBarText( const QString& text, StatusBarPriority p)
+{
+ if (!d->m_statusMessagesEnabled)
+ return;
+
+ d->m_statusBarText[p] = text;
+
+ // shift handling ?
+ QString tobe = d->m_statusBarText[BarHoverText];
+ if (tobe.isEmpty())
+ tobe = d->m_statusBarText[BarOverrideText];
+ if (tobe.isEmpty()) {
+ tobe = d->m_statusBarText[BarDefaultText];
+ if (!tobe.isEmpty() && d->m_jobspeed)
+ tobe += " ";
+ if (d->m_jobspeed)
+ tobe += i18n( "(%1/s)" ).arg( KIO::convertSize( d->m_jobspeed ) );
+ }
+ tobe = "<qt>"+tobe;
+
+ emit ReadOnlyPart::setStatusBarText(tobe);
+}
+
+
+void KHTMLPart::setJSStatusBarText( const QString &text )
+{
+ setStatusBarText(text, BarOverrideText);
+}
+
+void KHTMLPart::setJSDefaultStatusBarText( const QString &text )
+{
+ setStatusBarText(text, BarDefaultText);
+}
+
+QString KHTMLPart::jsStatusBarText() const
+{
+ return d->m_statusBarText[BarOverrideText];
+}
+
+QString KHTMLPart::jsDefaultStatusBarText() const
+{
+ return d->m_statusBarText[BarDefaultText];
+}
+
+QString KHTMLPart::referrer() const
+{
+ return d->m_referrer;
+}
+
+QString KHTMLPart::pageReferrer() const
+{
+ KURL referrerURL = KURL( d->m_pageReferrer );
+ if (referrerURL.isValid())
+ {
+ QString protocol = referrerURL.protocol();
+
+ if ((protocol == "http") ||
+ ((protocol == "https") && (m_url.protocol() == "https")))
+ {
+ referrerURL.setRef(QString::null);
+ referrerURL.setUser(QString::null);
+ referrerURL.setPass(QString::null);
+ return referrerURL.url();
+ }
+ }
+
+ return QString::null;
+}
+
+
+QString KHTMLPart::lastModified() const
+{
+ if ( d->m_lastModified.isEmpty() && m_url.isLocalFile() ) {
+ // Local file: set last-modified from the file's mtime.
+ // Done on demand to save time when this isn't needed - but can lead
+ // to slightly wrong results if updating the file on disk w/o reloading.
+ QDateTime lastModif = QFileInfo( m_url.path() ).lastModified();
+ d->m_lastModified = lastModif.toString( Qt::LocalDate );
+ }
+ //kdDebug(6050) << "KHTMLPart::lastModified: " << d->m_lastModified << endl;
+ return d->m_lastModified;
+}
+
+void KHTMLPart::slotLoadImages()
+{
+ if (d->m_doc )
+ d->m_doc->docLoader()->setAutoloadImages( !d->m_doc->docLoader()->autoloadImages() );
+
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
+ KParts::ReadOnlyPart* const p = ( *it )->m_part;
+ static_cast<KHTMLPart*>( p )->slotLoadImages();
+ }
+}
+
+void KHTMLPart::reparseConfiguration()
+{
+ KHTMLSettings *settings = KHTMLFactory::defaultHTMLSettings();
+ settings->init();
+
+ setAutoloadImages( settings->autoLoadImages() );
+ if (d->m_doc)
+ d->m_doc->docLoader()->setShowAnimations( settings->showAnimations() );
+
+ d->m_bOpenMiddleClick = settings->isOpenMiddleClickEnabled();
+ d->m_bBackRightClick = settings->isBackRightClickEnabled();
+ d->m_bJScriptEnabled = settings->isJavaScriptEnabled(m_url.host());
+ setDebugScript( settings->isJavaScriptDebugEnabled() );
+ d->m_bJavaEnabled = settings->isJavaEnabled(m_url.host());
+ d->m_bPluginsEnabled = settings->isPluginsEnabled(m_url.host());
+ d->m_metaRefreshEnabled = settings->isAutoDelayedActionsEnabled ();
+
+ delete d->m_settings;
+ d->m_settings = new KHTMLSettings(*KHTMLFactory::defaultHTMLSettings());
+
+ QApplication::setOverrideCursor( waitCursor );
+ khtml::CSSStyleSelector::reparseConfiguration();
+ if(d->m_doc) d->m_doc->updateStyleSelector();
+ QApplication::restoreOverrideCursor();
+
+ if (KHTMLFactory::defaultHTMLSettings()->isAdFilterEnabled())
+ runAdFilter();
+}
+
+QStringList KHTMLPart::frameNames() const
+{
+ QStringList res;
+
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ if (!(*it)->m_bPreloaded)
+ res += (*it)->m_name;
+
+ return res;
+}
+
+QPtrList<KParts::ReadOnlyPart> KHTMLPart::frames() const
+{
+ QPtrList<KParts::ReadOnlyPart> res;
+
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it )
+ if (!(*it)->m_bPreloaded)
+ res.append( (*it)->m_part );
+
+ return res;
+}
+
+bool KHTMLPart::openURLInFrame( const KURL &url, const KParts::URLArgs &urlArgs )
+{
+ kdDebug( 6050 ) << this << "KHTMLPart::openURLInFrame " << url << endl;
+ FrameIt it = d->m_frames.find( urlArgs.frameName );
+
+ if ( it == d->m_frames.end() )
+ return false;
+
+ // Inform someone that we are about to show something else.
+ if ( !urlArgs.lockHistory() )
+ emit d->m_extension->openURLNotify();
+
+ requestObject( *it, url, urlArgs );
+
+ return true;
+}
+
+void KHTMLPart::setDNDEnabled( bool b )
+{
+ d->m_bDnd = b;
+}
+
+bool KHTMLPart::dndEnabled() const
+{
+ return d->m_bDnd;
+}
+
+void KHTMLPart::customEvent( QCustomEvent *event )
+{
+ if ( khtml::MousePressEvent::test( event ) )
+ {
+ khtmlMousePressEvent( static_cast<khtml::MousePressEvent *>( event ) );
+ return;
+ }
+
+ if ( khtml::MouseDoubleClickEvent::test( event ) )
+ {
+ khtmlMouseDoubleClickEvent( static_cast<khtml::MouseDoubleClickEvent *>( event ) );
+ return;
+ }
+
+ if ( khtml::MouseMoveEvent::test( event ) )
+ {
+ khtmlMouseMoveEvent( static_cast<khtml::MouseMoveEvent *>( event ) );
+ return;
+ }
+
+ if ( khtml::MouseReleaseEvent::test( event ) )
+ {
+ khtmlMouseReleaseEvent( static_cast<khtml::MouseReleaseEvent *>( event ) );
+ return;
+ }
+
+ if ( khtml::DrawContentsEvent::test( event ) )
+ {
+ khtmlDrawContentsEvent( static_cast<khtml::DrawContentsEvent *>( event ) );
+ return;
+ }
+
+ KParts::ReadOnlyPart::customEvent( event );
+}
+
+/** returns the position of the first inline text box of the line at
+ * coordinate y in renderNode
+ *
+ * This is a helper function for line-by-line text selection.
+ */
+static bool firstRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
+{
+ for (khtml::RenderObject *n = renderNode; n; n = n->nextSibling()) {
+ if (n->isText()) {
+ khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
+ const khtml::InlineTextBoxArray &runs = textRenderer->inlineTextBoxes();
+ const unsigned lim = runs.count();
+ for (unsigned i = 0; i != lim; ++i) {
+ if (runs[i]->m_y == y && textRenderer->element()) {
+ startNode = textRenderer->element();
+ startOffset = runs[i]->m_start;
+ return true;
+ }
+ }
+ }
+
+ if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** returns the position of the last inline text box of the line at
+ * coordinate y in renderNode
+ *
+ * This is a helper function for line-by-line text selection.
+ */
+static bool lastRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
+{
+ khtml::RenderObject *n = renderNode;
+ if (!n) {
+ return false;
+ }
+ khtml::RenderObject *next;
+ while ((next = n->nextSibling())) {
+ n = next;
+ }
+
+ while (1) {
+ if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
+ return true;
+ }
+
+ if (n->isText()) {
+ khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
+ const khtml::InlineTextBoxArray &runs = textRenderer->inlineTextBoxes();
+ for (int i = (int)runs.count()-1; i >= 0; --i) {
+ if (runs[i]->m_y == y && textRenderer->element()) {
+ endNode = textRenderer->element();
+ endOffset = runs[i]->m_start + runs[i]->m_len;
+ return true;
+ }
+ }
+ }
+
+ if (n == renderNode) {
+ return false;
+ }
+
+ n = n->previousSibling();
+ }
+}
+
+void KHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent *event )
+{
+ DOM::DOMString url = event->url();
+ QMouseEvent *_mouse = event->qmouseEvent();
+ DOM::Node innerNode = event->innerNode();
+ d->m_mousePressNode = innerNode;
+
+ d->m_dragStartPos = _mouse->pos();
+
+ if ( !event->url().isNull() ) {
+ d->m_strSelectedURL = event->url().string();
+ d->m_strSelectedURLTarget = event->target().string();
+ }
+ else
+ d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
+
+ if ( _mouse->button() == LeftButton ||
+ _mouse->button() == MidButton )
+ {
+ d->m_bMousePressed = true;
+
+#ifndef KHTML_NO_SELECTION
+ if ( _mouse->button() == LeftButton )
+ {
+ if ( (!d->m_strSelectedURL.isNull() && !isEditable())
+ || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) )
+ return;
+ if ( !innerNode.isNull() && innerNode.handle()->renderer()) {
+ int offset = 0;
+ DOM::NodeImpl* node = 0;
+ khtml::RenderObject::SelPointState state;
+ innerNode.handle()->renderer()->checkSelectionPoint( event->x(), event->y(),
+ event->absX()-innerNode.handle()->renderer()->xPos(),
+ event->absY()-innerNode.handle()->renderer()->yPos(), node, offset, state );
+ d->m_extendMode = d->ExtendByChar;
+#ifdef KHTML_NO_CARET
+ d->m_selectionStart = node;
+ d->m_startOffset = offset;
+ //if ( node )
+ // kdDebug(6005) << "KHTMLPart::khtmlMousePressEvent selectionStart=" << d->m_selectionStart.handle()->renderer()
+ // << " offset=" << d->m_startOffset << endl;
+ //else
+ // kdDebug(6005) << "KHTML::khtmlMousePressEvent selectionStart=(nil)" << endl;
+ d->m_selectionEnd = d->m_selectionStart;
+ d->m_endOffset = d->m_startOffset;
+ d->m_doc->clearSelection();
+#else // KHTML_NO_CARET
+ d->m_view->moveCaretTo(node, offset, (_mouse->state() & ShiftButton) == 0);
+#endif // KHTML_NO_CARET
+ d->m_initialNode = d->m_selectionStart;
+ d->m_initialOffset = d->m_startOffset;
+// kdDebug(6000) << "press: initOfs " << d->m_initialOffset << endl;
+ }
+ else
+ {
+#ifndef KHTML_NO_CARET
+ // simply leave it. Is this a good idea?
+#else
+ d->m_selectionStart = DOM::Node();
+ d->m_selectionEnd = DOM::Node();
+#endif
+ }
+ emitSelectionChanged();
+ startAutoScroll();
+ }
+#else
+ d->m_dragLastPos = _mouse->globalPos();
+#endif
+ }
+
+ if ( _mouse->button() == RightButton && parentPart() != 0 && d->m_bBackRightClick )
+ {
+ d->m_bRightMousePressed = true;
+ } else if ( _mouse->button() == RightButton )
+ {
+ popupMenu( d->m_strSelectedURL );
+ // might be deleted, don't touch "this"
+ }
+}
+
+void KHTMLPart::khtmlMouseDoubleClickEvent( khtml::MouseDoubleClickEvent *event )
+{
+ QMouseEvent *_mouse = event->qmouseEvent();
+ if ( _mouse->button() == LeftButton )
+ {
+ d->m_bMousePressed = true;
+ DOM::Node innerNode = event->innerNode();
+ // Find selectionStart again, khtmlMouseReleaseEvent lost it
+ if ( !innerNode.isNull() && innerNode.handle()->renderer()) {
+ int offset = 0;
+ DOM::NodeImpl* node = 0;
+ khtml::RenderObject::SelPointState state;
+ innerNode.handle()->renderer()->checkSelectionPoint( event->x(), event->y(),
+ event->absX()-innerNode.handle()->renderer()->xPos(),
+ event->absY()-innerNode.handle()->renderer()->yPos(), node, offset, state);
+
+ //kdDebug() << k_funcinfo << "checkSelectionPoint returned node=" << node << " offset=" << offset << endl;
+
+ if ( node && node->renderer() )
+ {
+ // Extend selection to a complete word (double-click) or line (triple-click)
+ bool selectLine = (event->clickCount() == 3);
+ d->m_extendMode = selectLine ? d->ExtendByLine : d->ExtendByWord;
+
+ // Extend existing selection if Shift was pressed
+ if (_mouse->state() & ShiftButton) {
+ d->caretNode() = node;
+ d->caretOffset() = offset;
+ d->m_startBeforeEnd = RangeImpl::compareBoundaryPoints(
+ d->m_selectionStart.handle(), d->m_startOffset,
+ d->m_selectionEnd.handle(), d->m_endOffset) <= 0;
+ d->m_initialNode = d->m_extendAtEnd ? d->m_selectionStart : d->m_selectionEnd;
+ d->m_initialOffset = d->m_extendAtEnd ? d->m_startOffset : d->m_endOffset;
+ } else {
+ d->m_selectionStart = d->m_selectionEnd = node;
+ d->m_startOffset = d->m_endOffset = offset;
+ d->m_startBeforeEnd = true;
+ d->m_initialNode = node;
+ d->m_initialOffset = offset;
+ }
+// kdDebug(6000) << "dblclk: initOfs " << d->m_initialOffset << endl;
+
+ // Extend the start
+ extendSelection( d->m_selectionStart.handle(), d->m_startOffset, d->m_selectionStart, d->m_startOffset, !d->m_startBeforeEnd, selectLine );
+ // Extend the end
+ extendSelection( d->m_selectionEnd.handle(), d->m_endOffset, d->m_selectionEnd, d->m_endOffset, d->m_startBeforeEnd, selectLine );
+
+ //kdDebug() << d->m_selectionStart.handle() << " " << d->m_startOffset << " - " <<
+ // d->m_selectionEnd.handle() << " " << d->m_endOffset << endl;
+
+ emitSelectionChanged();
+ d->m_doc
+ ->setSelection(d->m_selectionStart.handle(),d->m_startOffset,
+ d->m_selectionEnd.handle(),d->m_endOffset);
+#ifndef KHTML_NO_CARET
+ bool v = d->m_view->placeCaret();
+ emitCaretPositionChanged(v ? d->caretNode() : 0, d->caretOffset());
+#endif
+ startAutoScroll();
+ }
+ }
+ }
+}
+
+void KHTMLPart::extendSelection( DOM::NodeImpl* node, long offset, DOM::Node& selectionNode, long& selectionOffset, bool right, bool selectLines )
+{
+ khtml::RenderObject* obj = node->renderer();
+
+ if (obj->isText() && selectLines) {
+ int pos;
+ khtml::RenderText *renderer = static_cast<khtml::RenderText *>(obj);
+ khtml::InlineTextBox *run = renderer->findInlineTextBox( offset, pos );
+ DOMString t = node->nodeValue();
+ DOM::NodeImpl* selNode = 0;
+ long selOfs = 0;
+
+ if (!run)
+ return;
+
+ int selectionPointY = run->m_y;
+
+ // Go up to first non-inline element.
+ khtml::RenderObject *renderNode = renderer;
+ while (renderNode && renderNode->isInline())
+ renderNode = renderNode->parent();
+
+ renderNode = renderNode->firstChild();
+
+ if (right) {
+ // Look for all the last child in the block that is on the same line
+ // as the selection point.
+ if (!lastRunAt (renderNode, selectionPointY, selNode, selOfs))
+ return;
+ } else {
+ // Look for all the first child in the block that is on the same line
+ // as the selection point.
+ if (!firstRunAt (renderNode, selectionPointY, selNode, selOfs))
+ return;
+ }
+
+ selectionNode = selNode;
+ selectionOffset = selOfs;
+ return;
+ }
+
+ QString str;
+ int len = 0;
+ if ( obj->isText() ) { // can be false e.g. when double-clicking on a disabled submit button
+ str = static_cast<khtml::RenderText *>(obj)->data().string();
+ len = str.length();
+ }
+ //kdDebug() << "extendSelection right=" << right << " offset=" << offset << " len=" << len << " Starting at obj=" << obj << endl;
+ QChar ch;
+ do {
+ // Last char was ok, point to it
+ if ( node ) {
+ selectionNode = node;
+ selectionOffset = offset;
+ }
+
+ // Get another char
+ while ( obj && ( (right && offset >= len-1) || (!right && offset <= 0) ) )
+ {
+ obj = right ? obj->objectBelow() : obj->objectAbove();
+ //kdDebug() << "obj=" << obj << endl;
+ if ( obj ) {
+ //kdDebug() << "isText=" << obj->isText() << endl;
+ str = QString::null;
+ if ( obj->isText() )
+ str = static_cast<khtml::RenderText *>(obj)->data().string();
+ else if ( obj->isBR() )
+ str = '\n';
+ else if ( !obj->isInline() ) {
+ obj = 0L; // parag limit -> done
+ break;
+ }
+ len = str.length();
+ //kdDebug() << "str=" << str << " length=" << len << endl;
+ // set offset - note that the first thing will be a ++ or -- on it.
+ if ( right )
+ offset = -1;
+ else
+ offset = len;
+ }
+ }
+ if ( !obj ) // end of parag or document
+ break;
+ node = obj->element();
+ if ( right )
+ {
+ Q_ASSERT( offset < len-1 );
+ ++offset;
+ }
+ else
+ {
+ Q_ASSERT( offset > 0 );
+ --offset;
+ }
+
+ // Test that char
+ ch = str[ (int)offset ];
+ //kdDebug() << " offset=" << offset << " ch=" << QString(ch) << endl;
+ } while ( !ch.isSpace() && !ch.isPunct() );
+
+ // make offset point after last char
+ if (right) ++selectionOffset;
+}
+
+#ifndef KHTML_NO_SELECTION
+void KHTMLPart::extendSelectionTo(int x, int y, int absX, int absY, const DOM::Node &innerNode)
+{
+ int offset;
+ //kdDebug(6000) << "KHTMLPart::khtmlMouseMoveEvent x=" << event->x() << " y=" << event->y() << endl;
+ DOM::NodeImpl* node=0;
+ khtml::RenderObject::SelPointState state;
+ innerNode.handle()->renderer()->checkSelectionPoint( x, y,
+ absX-innerNode.handle()->renderer()->xPos(),
+ absY-innerNode.handle()->renderer()->yPos(), node, offset, state);
+ if (!node || !node->renderer()) return;
+
+ // Words at the beginning/end of line cannot be deselected in
+ // ExtendByWord mode. Therefore, do not enforce it if the selection
+ // point does not match the node under the mouse cursor.
+ bool withinNode = innerNode == node;
+
+ // we have to get to know if end is before start or not...
+ // shouldn't be null but it can happen with dynamic updating of nodes
+ if (d->m_selectionStart.isNull() || d->m_selectionEnd.isNull() ||
+ d->m_initialNode.isNull() ||
+ !d->m_selectionStart.handle()->renderer() ||
+ !d->m_selectionEnd.handle()->renderer()) return;
+
+ if (d->m_extendMode != d->ExtendByChar) {
+ // check whether we should extend at the front, or at the back
+ bool caretBeforeInit = RangeImpl::compareBoundaryPoints(
+ d->caretNode().handle(), d->caretOffset(),
+ d->m_initialNode.handle(), d->m_initialOffset) <= 0;
+ bool nodeBeforeInit = RangeImpl::compareBoundaryPoints(node, offset,
+ d->m_initialNode.handle(), d->m_initialOffset) <= 0;
+ // have to fix up start to point to the original end
+ if (caretBeforeInit != nodeBeforeInit) {
+// kdDebug(6000) << "extto cbi: " << caretBeforeInit << " startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << ")" << " initOfs " << d->m_initialOffset << endl;
+ extendSelection(d->m_initialNode.handle(), d->m_initialOffset,
+ d->m_extendAtEnd ? d->m_selectionStart : d->m_selectionEnd,
+ d->m_extendAtEnd ? d->m_startOffset : d->m_endOffset,
+ nodeBeforeInit, d->m_extendMode == d->ExtendByLine);
+ }
+ }
+
+ d->caretNode() = node;
+ d->caretOffset() = offset;
+ //kdDebug( 6000 ) << "setting end of selection to " << d->m_selectionEnd.handle() << "/" << d->m_endOffset << endl;
+
+ d->m_startBeforeEnd = RangeImpl::compareBoundaryPoints(
+ d->m_selectionStart.handle(), d->m_startOffset,
+ d->m_selectionEnd.handle(), d->m_endOffset) <= 0;
+
+ if ( !d->m_selectionStart.isNull() && !d->m_selectionEnd.isNull() )
+ {
+// kdDebug(6000) << "extto: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << ")" << " initOfs " << d->m_initialOffset << endl;
+ if (d->m_extendMode != d->ExtendByChar && withinNode)
+ extendSelection( node, offset, d->caretNode(), d->caretOffset(), d->m_startBeforeEnd ^ !d->m_extendAtEnd, d->m_extendMode == d->ExtendByLine );
+
+ if (d->m_selectionEnd == d->m_selectionStart && d->m_endOffset < d->m_startOffset)
+ d->m_doc
+ ->setSelection(d->m_selectionStart.handle(),d->m_endOffset,
+ d->m_selectionEnd.handle(),d->m_startOffset);
+ else if (d->m_startBeforeEnd)
+ d->m_doc
+ ->setSelection(d->m_selectionStart.handle(),d->m_startOffset,
+ d->m_selectionEnd.handle(),d->m_endOffset);
+ else
+ d->m_doc
+ ->setSelection(d->m_selectionEnd.handle(),d->m_endOffset,
+ d->m_selectionStart.handle(),d->m_startOffset);
+ }
+#ifndef KHTML_NO_CARET
+ d->m_view->placeCaret();
+#endif
+}
+
+bool KHTMLPart::isExtendingSelection() const
+{
+ // This is it, the whole detection. khtmlMousePressEvent only sets this
+ // on LMB or MMB, but never on RMB. As text selection doesn't work for MMB,
+ // it's sufficient to only rely on this flag to detect selection extension.
+ return d->m_bMousePressed;
+}
+#endif // KHTML_NO_SELECTION
+
+void KHTMLPart::khtmlMouseMoveEvent( khtml::MouseMoveEvent *event )
+{
+ QMouseEvent *_mouse = event->qmouseEvent();
+
+ if( d->m_bRightMousePressed && parentPart() != 0 && d->m_bBackRightClick )
+ {
+ popupMenu( d->m_strSelectedURL );
+ d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
+ d->m_bRightMousePressed = false;
+ }
+
+ DOM::DOMString url = event->url();
+ DOM::DOMString target = event->target();
+ DOM::Node innerNode = event->innerNode();
+
+#ifndef QT_NO_DRAGANDDROP
+ if( d->m_bDnd && d->m_bMousePressed &&
+ ( (!d->m_strSelectedURL.isEmpty() && !isEditable())
+ || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) ) ) {
+ if ( ( d->m_dragStartPos - _mouse->pos() ).manhattanLength() <= KGlobalSettings::dndEventDelay() )
+ return;
+
+ QPixmap pix;
+ HTMLImageElementImpl *img = 0L;
+ QDragObject *drag = 0;
+ KURL u;
+
+ // qDebug("****************** Event URL: %s", url.string().latin1());
+ // qDebug("****************** Event Target: %s", target.string().latin1());
+
+ // Normal image...
+ if ( url.length() == 0 && innerNode.handle() && innerNode.handle()->id() == ID_IMG )
+ {
+ img = static_cast<HTMLImageElementImpl *>(innerNode.handle());
+ u = KURL( completeURL( khtml::parseURL(img->getAttribute(ATTR_SRC)).string() ) );
+ pix = KMimeType::mimeType("image/png")->pixmap(KIcon::Desktop);
+ }
+ else
+ {
+ // Text or image link...
+ u = completeURL( d->m_strSelectedURL );
+ pix = KMimeType::pixmapForURL(u, 0, KIcon::Desktop, KIcon::SizeMedium);
+ }
+
+ u.setPass(QString::null);
+
+ KURLDrag* urlDrag = new KURLDrag( u, img ? 0 : d->m_view->viewport() );
+ if ( !d->m_referrer.isEmpty() )
+ urlDrag->metaData()["referrer"] = d->m_referrer;
+
+ if( img && img->complete()) {
+ KMultipleDrag *mdrag = new KMultipleDrag( d->m_view->viewport() );
+ mdrag->addDragObject( new QImageDrag( img->currentImage(), 0L ) );
+ mdrag->addDragObject( urlDrag );
+ drag = mdrag;
+ }
+ else
+ drag = urlDrag;
+
+ if ( !pix.isNull() )
+ drag->setPixmap( pix );
+
+ stopAutoScroll();
+ if(drag)
+ drag->drag();
+
+ // when we finish our drag, we need to undo our mouse press
+ d->m_bMousePressed = false;
+ d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
+ return;
+ }
+#endif
+
+ // Not clicked -> mouse over stuff
+ if ( !d->m_bMousePressed )
+ {
+ // The mouse is over something
+ if ( url.length() )
+ {
+ bool shiftPressed = ( _mouse->state() & ShiftButton );
+
+ // Image map
+ if ( !innerNode.isNull() && innerNode.elementId() == ID_IMG )
+ {
+ HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
+ if ( i && i->isServerMap() )
+ {
+ khtml::RenderObject *r = i->renderer();
+ if(r)
+ {
+ int absx, absy, vx, vy;
+ r->absolutePosition(absx, absy);
+ view()->contentsToViewport( absx, absy, vx, vy );
+
+ int x(_mouse->x() - vx), y(_mouse->y() - vy);
+
+ d->m_overURL = url.string() + QString("?%1,%2").arg(x).arg(y);
+ d->m_overURLTarget = target.string();
+ overURL( d->m_overURL, target.string(), shiftPressed );
+ return;
+ }
+ }
+ }
+
+ // normal link
+ if ( d->m_overURL.isEmpty() || d->m_overURL != url || d->m_overURLTarget != target )
+ {
+ d->m_overURL = url.string();
+ d->m_overURLTarget = target.string();
+ overURL( d->m_overURL, target.string(), shiftPressed );
+ }
+ }
+ else // Not over a link...
+ {
+ // reset to "default statusbar text"
+ resetHoverText();
+ }
+ }
+ else {
+#ifndef KHTML_NO_SELECTION
+ // selection stuff
+ if( d->m_bMousePressed && innerNode.handle() && innerNode.handle()->renderer() &&
+ ( (_mouse->state() & LeftButton) != 0 )) {
+ extendSelectionTo(event->x(), event->y(),
+ event->absX(), event->absY(), innerNode);
+#else
+ if ( d->m_doc && d->m_view ) {
+ QPoint diff( _mouse->globalPos() - d->m_dragLastPos );
+
+ if ( abs( diff.x() ) > 64 || abs( diff.y() ) > 64 ) {
+ d->m_view->scrollBy( -diff.x(), -diff.y() );
+ d->m_dragLastPos = _mouse->globalPos();
+ }
+#endif
+ }
+ }
+
+}
+
+void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
+{
+ DOM::Node innerNode = event->innerNode();
+ d->m_mousePressNode = DOM::Node();
+
+ if ( d->m_bMousePressed ) {
+ setStatusBarText(QString::null, BarHoverText);
+ stopAutoScroll();
+ }
+
+ // Used to prevent mouseMoveEvent from initiating a drag before
+ // the mouse is pressed again.
+ d->m_bMousePressed = false;
+
+ QMouseEvent *_mouse = event->qmouseEvent();
+ if ( _mouse->button() == RightButton && parentPart() != 0 && d->m_bBackRightClick )
+ {
+ d->m_bRightMousePressed = false;
+ KParts::BrowserInterface *tmp_iface = d->m_extension->browserInterface();
+ if( tmp_iface ) {
+ tmp_iface->callMethod( "goHistory(int)", -1 );
+ }
+ }
+#ifndef QT_NO_CLIPBOARD
+ if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == MidButton) && (event->url().isNull())) {
+ kdDebug( 6050 ) << "KHTMLPart::khtmlMouseReleaseEvent() MMB shouldOpen="
+ << d->m_bOpenMiddleClick << endl;
+
+ if (d->m_bOpenMiddleClick) {
+ KHTMLPart *p = this;
+ while (p->parentPart()) p = p->parentPart();
+ p->d->m_extension->pasteRequest();
+ }
+ }
+#endif
+
+#ifndef KHTML_NO_SELECTION
+ // delete selection in case start and end position are at the same point
+ if(d->m_selectionStart == d->m_selectionEnd && d->m_startOffset == d->m_endOffset) {
+#ifndef KHTML_NO_CARET
+ d->m_extendAtEnd = true;
+#else
+ d->m_selectionStart = 0;
+ d->m_selectionEnd = 0;
+ d->m_startOffset = 0;
+ d->m_endOffset = 0;
+#endif
+ emitSelectionChanged();
+ } else {
+ // we have to get to know if end is before start or not...
+// kdDebug(6000) << "rel: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << ")" << endl;
+ DOM::Node n = d->m_selectionStart;
+ d->m_startBeforeEnd = false;
+ if( d->m_selectionStart == d->m_selectionEnd ) {
+ if( d->m_startOffset < d->m_endOffset )
+ d->m_startBeforeEnd = true;
+ } else {
+#if 0
+ while(!n.isNull()) {
+ if(n == d->m_selectionEnd) {
+ d->m_startBeforeEnd = true;
+ break;
+ }
+ DOM::Node next = n.firstChild();
+ if(next.isNull()) next = n.nextSibling();
+ while( next.isNull() && !n.parentNode().isNull() ) {
+ n = n.parentNode();
+ next = n.nextSibling();
+ }
+ n = next;
+ }
+#else
+ // shouldn't be null but it can happen with dynamic updating of nodes
+ if (d->m_selectionStart.isNull() || d->m_selectionEnd.isNull() ||
+ !d->m_selectionStart.handle()->renderer() ||
+ !d->m_selectionEnd.handle()->renderer()) return;
+ d->m_startBeforeEnd = RangeImpl::compareBoundaryPoints(
+ d->m_selectionStart.handle(), d->m_startOffset,
+ d->m_selectionEnd.handle(), d->m_endOffset) <= 0;
+#endif
+ }
+ if(!d->m_startBeforeEnd)
+ {
+ DOM::Node tmpNode = d->m_selectionStart;
+ int tmpOffset = d->m_startOffset;
+ d->m_selectionStart = d->m_selectionEnd;
+ d->m_startOffset = d->m_endOffset;
+ d->m_selectionEnd = tmpNode;
+ d->m_endOffset = tmpOffset;
+ d->m_startBeforeEnd = true;
+ d->m_extendAtEnd = !d->m_extendAtEnd;
+ }
+#ifndef KHTML_NO_CARET
+ bool v = d->m_view->placeCaret();
+ emitCaretPositionChanged(v ? d->caretNode() : 0, d->caretOffset());
+#endif
+ // get selected text and paste to the clipboard
+#ifndef QT_NO_CLIPBOARD
+ QString text = selectedText();
+ text.replace(QChar(0xa0), ' ');
+ disconnect( kapp->clipboard(), SIGNAL( selectionChanged()), this, SLOT( slotClearSelection()));
+ kapp->clipboard()->setText(text,QClipboard::Selection);
+ connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
+#endif
+ //kdDebug( 6000 ) << "selectedText = " << text << endl;
+ emitSelectionChanged();
+//kdDebug(6000) << "rel2: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << "), caretOfs " << d->caretOffset() << endl;
+ }
+#endif
+ d->m_initialNode = 0; // don't hold nodes longer than necessary
+ d->m_initialOffset = 0;
+
+}
+
+void KHTMLPart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * )
+{
+}
+
+void KHTMLPart::guiActivateEvent( KParts::GUIActivateEvent *event )
+{
+ if ( event->activated() )
+ {
+ emitSelectionChanged();
+ emit d->m_extension->enableAction( "print", d->m_doc != 0 );
+
+ if ( !d->m_settings->autoLoadImages() && d->m_paLoadImages )
+ {
+ QPtrList<KAction> lst;
+ lst.append( d->m_paLoadImages );
+ plugActionList( "loadImages", lst );
+ }
+ }
+}
+
+void KHTMLPart::slotPrintFrame()
+{
+ if ( d->m_frames.count() == 0 )
+ return;
+
+ KParts::ReadOnlyPart *frame = currentFrame();
+ if (!frame)
+ return;
+
+ KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject( frame );
+
+ if ( !ext )
+ return;
+
+ QMetaObject *mo = ext->metaObject();
+
+ int idx = mo->findSlot( "print()", true );
+ if ( idx >= 0 ) {
+ QUObject o[ 1 ];
+ ext->qt_invoke( idx, o );
+ }
+}
+
+void KHTMLPart::slotSelectAll()
+{
+ KParts::ReadOnlyPart *part = currentFrame();
+ if (part && part->inherits("KHTMLPart"))
+ static_cast<KHTMLPart *>(part)->selectAll();
+}
+
+void KHTMLPart::startAutoScroll()
+{
+ connect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ));
+ d->m_scrollTimer.start(100, false);
+}
+
+void KHTMLPart::stopAutoScroll()
+{
+ disconnect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ));
+ if (d->m_scrollTimer.isActive())
+ d->m_scrollTimer.stop();
+}
+
+
+void KHTMLPart::slotAutoScroll()
+{
+ if (d->m_view)
+ d->m_view->doAutoScroll();
+ else
+ stopAutoScroll(); // Safety
+}
+
+void KHTMLPart::runAdFilter()
+{
+ if ( parentPart() )
+ parentPart()->runAdFilter();
+
+ if ( !d->m_doc )
+ return;
+
+ QPtrDictIterator<khtml::CachedObject> it( d->m_doc->docLoader()->m_docObjects );
+ for ( ; it.current(); ++it )
+ if ( it.current()->type() == khtml::CachedObject::Image ) {
+ khtml::CachedImage *image = static_cast<khtml::CachedImage *>(it.current());
+ bool wasBlocked = image->m_wasBlocked;
+ image->m_wasBlocked = KHTMLFactory::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( (*it).url().string() ) );
+ if ( image->m_wasBlocked != wasBlocked )
+ image->do_notify(image->pixmap(), image->valid_rect());
+ }
+
+ if ( KHTMLFactory::defaultHTMLSettings()->isHideAdsEnabled() ) {
+ for ( NodeImpl *nextNode, *node = d->m_doc; node; node = nextNode ) {
+
+ // We might be deleting 'node' shortly.
+ nextNode = node->traverseNextNode();
+
+ if ( node->id() == ID_IMG ||
+ node->id() == ID_IFRAME ||
+ (node->id() == ID_INPUT && static_cast<HTMLInputElementImpl *>(node)->inputType() == HTMLInputElementImpl::IMAGE ))
+ {
+ if ( KHTMLFactory::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( static_cast<ElementImpl *>(node)->getAttribute(ATTR_SRC).string() ) ) )
+ {
+ // We found an IMG, IFRAME or INPUT (of type IMAGE) matching a filter.
+ node->ref();
+ NodeImpl *parent = node->parent();
+ if( parent )
+ {
+ int exception = 0;
+ parent->removeChild(node, exception);
+ }
+ node->deref();
+ }
+ }
+ }
+ }
+}
+
+void KHTMLPart::selectAll()
+{
+ if (!d->m_doc) return;
+
+ NodeImpl *first;
+ if (d->m_doc->isHTMLDocument())
+ first = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
+ else
+ first = d->m_doc;
+ NodeImpl *next;
+
+ // Look for first text/cdata node that has a renderer,
+ // or first childless replaced element
+ while ( first && !(first->renderer()
+ && ((first->nodeType() == Node::TEXT_NODE || first->nodeType() == Node::CDATA_SECTION_NODE)
+ || (first->renderer()->isReplaced() && !first->renderer()->firstChild()))))
+ {
+ next = first->firstChild();
+ if ( !next ) next = first->nextSibling();
+ while( first && !next )
+ {
+ first = first->parentNode();
+ if ( first )
+ next = first->nextSibling();
+ }
+ first = next;
+ }
+
+ NodeImpl *last;
+ if (d->m_doc->isHTMLDocument())
+ last = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
+ else
+ last = d->m_doc;
+ // Look for last text/cdata node that has a renderer,
+ // or last childless replaced element
+ // ### Instead of changing this loop, use findLastSelectableNode
+ // in render_table.cpp (LS)
+ while ( last && !(last->renderer()
+ && ((last->nodeType() == Node::TEXT_NODE || last->nodeType() == Node::CDATA_SECTION_NODE)
+ || (last->renderer()->isReplaced() && !last->renderer()->lastChild()))))
+ {
+ next = last->lastChild();
+ if ( !next ) next = last->previousSibling();
+ while ( last && !next )
+ {
+ last = last->parentNode();
+ if ( last )
+ next = last->previousSibling();
+ }
+ last = next;
+ }
+
+ if ( !first || !last )
+ return;
+ Q_ASSERT(first->renderer());
+ Q_ASSERT(last->renderer());
+ d->m_selectionStart = first;
+ d->m_startOffset = 0;
+ d->m_selectionEnd = last;
+ d->m_endOffset = last->nodeValue().length();
+ d->m_startBeforeEnd = true;
+
+ d->m_doc->setSelection( d->m_selectionStart.handle(), d->m_startOffset,
+ d->m_selectionEnd.handle(), d->m_endOffset );
+
+ emitSelectionChanged();
+}
+
+bool KHTMLPart::checkLinkSecurity(const KURL &linkURL,const QString &message, const QString &button)
+{
+ bool linkAllowed = true;
+
+ if ( d->m_doc )
+ linkAllowed = kapp && kapp->authorizeURLAction("redirect", url(), linkURL);
+
+ if ( !linkAllowed ) {
+ khtml::Tokenizer *tokenizer = d->m_doc->tokenizer();
+ if (tokenizer)
+ tokenizer->setOnHold(true);
+
+ int response = KMessageBox::Cancel;
+ if (!message.isEmpty())
+ {
+ response = KMessageBox::warningContinueCancel( 0,
+ message.arg(linkURL.htmlURL()),
+ i18n( "Security Warning" ),
+ button);
+ }
+ else
+ {
+ KMessageBox::error( 0,
+ i18n( "<qt>Access by untrusted page to<BR><B>%1</B><BR> denied.").arg(linkURL.htmlURL()),
+ i18n( "Security Alert" ));
+ }
+
+ if (tokenizer)
+ tokenizer->setOnHold(false);
+ return (response==KMessageBox::Continue);
+ }
+ return true;
+}
+
+void KHTMLPart::slotPartRemoved( KParts::Part *part )
+{
+// kdDebug(6050) << "KHTMLPart::slotPartRemoved " << part << endl;
+ if ( part == d->m_activeFrame )
+ {
+ d->m_activeFrame = 0L;
+ if ( !part->inherits( "KHTMLPart" ) )
+ {
+ if (factory()) {
+ factory()->removeClient( part );
+ }
+ if (childClients()->containsRef(part)) {
+ removeChildClient( part );
+ }
+ }
+ }
+}
+
+void KHTMLPart::slotActiveFrameChanged( KParts::Part *part )
+{
+// kdDebug(6050) << "KHTMLPart::slotActiveFrameChanged this=" << this << "part=" << part << endl;
+ if ( part == this )
+ {
+ kdError(6050) << "strange error! we activated ourselves" << endl;
+ assert( false );
+ return;
+ }
+// kdDebug(6050) << "KHTMLPart::slotActiveFrameChanged d->m_activeFrame=" << d->m_activeFrame << endl;
+ if ( d->m_activeFrame && d->m_activeFrame->widget() && d->m_activeFrame->widget()->inherits( "QFrame" ) )
+ {
+ QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
+ if (frame->frameStyle() != QFrame::NoFrame)
+ {
+ frame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken);
+ frame->repaint();
+ }
+ }
+
+ if( d->m_activeFrame && !d->m_activeFrame->inherits( "KHTMLPart" ) )
+ {
+ if (factory()) {
+ factory()->removeClient( d->m_activeFrame );
+ }
+ removeChildClient( d->m_activeFrame );
+ }
+ if( part && !part->inherits( "KHTMLPart" ) )
+ {
+ if (factory()) {
+ factory()->addClient( part );
+ }
+ insertChildClient( part );
+ }
+
+
+ d->m_activeFrame = part;
+
+ if ( d->m_activeFrame && d->m_activeFrame->widget()->inherits( "QFrame" ) )
+ {
+ QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
+ if (frame->frameStyle() != QFrame::NoFrame)
+ {
+ frame->setFrameStyle( QFrame::StyledPanel | QFrame::Plain);
+ frame->repaint();
+ }
+ kdDebug(6050) << "new active frame " << d->m_activeFrame << endl;
+ }
+
+ updateActions();
+
+ // (note: childObject returns 0 if the argument is 0)
+ d->m_extension->setExtensionProxy( KParts::BrowserExtension::childObject( d->m_activeFrame ) );
+}
+
+void KHTMLPart::setActiveNode(const DOM::Node &node)
+{
+ if (!d->m_doc || !d->m_view)
+ return;
+
+ // Set the document's active node
+ d->m_doc->setFocusNode(node.handle());
+
+ // Scroll the view if necessary to ensure that the new focus node is visible
+ QRect rect = node.handle()->getRect();
+ d->m_view->ensureVisible(rect.right(), rect.bottom());
+ d->m_view->ensureVisible(rect.left(), rect.top());
+}
+
+DOM::Node KHTMLPart::activeNode() const
+{
+ return DOM::Node(d->m_doc?d->m_doc->focusNode():0);
+}
+
+DOM::EventListener *KHTMLPart::createHTMLEventListener( QString code, QString name, NodeImpl* node )
+{
+ KJSProxy *proxy = jScript();
+
+ if (!proxy)
+ return 0;
+
+ return proxy->createHTMLEventHandler( m_url.url(), name, code, node );
+}
+
+KHTMLPart *KHTMLPart::opener()
+{
+ return d->m_opener;
+}
+
+void KHTMLPart::setOpener(KHTMLPart *_opener)
+{
+ d->m_opener = _opener;
+}
+
+bool KHTMLPart::openedByJS()
+{
+ return d->m_openedByJS;
+}
+
+void KHTMLPart::setOpenedByJS(bool _openedByJS)
+{
+ d->m_openedByJS = _openedByJS;
+}
+
+void KHTMLPart::preloadStyleSheet(const QString &url, const QString &stylesheet)
+{
+ khtml::Cache::preloadStyleSheet(url, stylesheet);
+}
+
+void KHTMLPart::preloadScript(const QString &url, const QString &script)
+{
+ khtml::Cache::preloadScript(url, script);
+}
+
+QCString KHTMLPart::dcopObjectId() const
+{
+ QCString id;
+ id.sprintf("html-widget%d", d->m_dcop_counter);
+ return id;
+}
+
+long KHTMLPart::cacheId() const
+{
+ return d->m_cacheId;
+}
+
+bool KHTMLPart::restored() const
+{
+ return d->m_restored;
+}
+
+bool KHTMLPart::pluginPageQuestionAsked(const QString& mimetype) const
+{
+ // parentPart() should be const!
+ KHTMLPart* parent = const_cast<KHTMLPart *>(this)->parentPart();
+ if ( parent )
+ return parent->pluginPageQuestionAsked(mimetype);
+
+ return d->m_pluginPageQuestionAsked.contains(mimetype);
+}
+
+void KHTMLPart::setPluginPageQuestionAsked(const QString& mimetype)
+{
+ if ( parentPart() )
+ parentPart()->setPluginPageQuestionAsked(mimetype);
+
+ d->m_pluginPageQuestionAsked.append(mimetype);
+}
+
+void KHTMLPart::slotAutomaticDetectionLanguage( int _id )
+{
+ d->m_automaticDetection->setItemChecked( _id, true );
+
+ switch ( _id ) {
+ case 0 :
+ d->m_autoDetectLanguage = khtml::Decoder::SemiautomaticDetection;
+ break;
+ case 1 :
+ d->m_autoDetectLanguage = khtml::Decoder::Arabic;
+ break;
+ case 2 :
+ d->m_autoDetectLanguage = khtml::Decoder::Baltic;
+ break;
+ case 3 :
+ d->m_autoDetectLanguage = khtml::Decoder::CentralEuropean;
+ break;
+ case 4 :
+ d->m_autoDetectLanguage = khtml::Decoder::Chinese;
+ break;
+ case 5 :
+ d->m_autoDetectLanguage = khtml::Decoder::Greek;
+ break;
+ case 6 :
+ d->m_autoDetectLanguage = khtml::Decoder::Hebrew;
+ break;
+ case 7 :
+ d->m_autoDetectLanguage = khtml::Decoder::Japanese;
+ break;
+ case 8 :
+ d->m_autoDetectLanguage = khtml::Decoder::Korean;
+ break;
+ case 9 :
+ d->m_autoDetectLanguage = khtml::Decoder::Russian;
+ break;
+ case 10 :
+ d->m_autoDetectLanguage = khtml::Decoder::Thai;
+ break;
+ case 11 :
+ d->m_autoDetectLanguage = khtml::Decoder::Turkish;
+ break;
+ case 12 :
+ d->m_autoDetectLanguage = khtml::Decoder::Ukrainian;
+ break;
+ case 13 :
+ d->m_autoDetectLanguage = khtml::Decoder::Unicode;
+ break;
+ case 14 :
+ d->m_autoDetectLanguage = khtml::Decoder::WesternEuropean;
+ break;
+ default :
+ d->m_autoDetectLanguage = khtml::Decoder::SemiautomaticDetection;
+ break;
+ }
+
+ for ( int i = 0; i <= 14; ++i ) {
+ if ( i != _id )
+ d->m_automaticDetection->setItemChecked( i, false );
+ }
+
+ d->m_paSetEncoding->popupMenu()->setItemChecked( 0, true );
+
+ setEncoding( QString::null, false );
+
+ if( d->m_manualDetection )
+ d->m_manualDetection->setCurrentItem( -1 );
+ d->m_paSetEncoding->popupMenu()->setItemChecked( d->m_paSetEncoding->popupMenu()->idAt( 2 ), false );
+}
+
+khtml::Decoder *KHTMLPart::createDecoder()
+{
+ khtml::Decoder *dec = new khtml::Decoder();
+ if( !d->m_encoding.isNull() )
+ dec->setEncoding( d->m_encoding.latin1(),
+ d->m_haveEncoding ? khtml::Decoder::UserChosenEncoding : khtml::Decoder::EncodingFromHTTPHeader);
+ else {
+ // Inherit the default encoding from the parent frame if there is one.
+ const char *defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
+ ? parentPart()->d->m_decoder->encoding() : settings()->encoding().latin1();
+ dec->setEncoding(defaultEncoding, khtml::Decoder::DefaultEncoding);
+ }
+#ifdef APPLE_CHANGES
+ if (d->m_doc)
+ d->m_doc->setDecoder(d->m_decoder);
+#endif
+ dec->setAutoDetectLanguage( d->m_autoDetectLanguage );
+ return dec;
+}
+
+void KHTMLPart::emitCaretPositionChanged(const DOM::Node &node, long offset) {
+ emit caretPositionChanged(node, offset);
+}
+
+void KHTMLPart::restoreScrollPosition()
+{
+ KParts::URLArgs args = d->m_extension->urlArgs();
+
+ if ( m_url.hasRef() && !d->m_restoreScrollPosition && !args.reload) {
+ if ( !d->m_doc || !d->m_doc->parsing() )
+ disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
+ if ( !gotoAnchor(m_url.encodedHtmlRef()) )
+ gotoAnchor(m_url.htmlRef());
+ return;
+ }
+
+ // Check whether the viewport has become large enough to encompass the stored
+ // offsets. If the document has been fully loaded, force the new coordinates,
+ // even if the canvas is too short (can happen when user resizes the window
+ // during loading).
+ if (d->m_view->contentsHeight() - d->m_view->visibleHeight() >= args.yOffset
+ || d->m_bComplete) {
+ d->m_view->setContentsPos(args.xOffset, args.yOffset);
+ disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
+ }
+}
+
+
+void KHTMLPart::openWallet(DOM::HTMLFormElementImpl *form)
+{
+#ifndef KHTML_NO_WALLET
+ KHTMLPart *p;
+
+ for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
+ }
+
+ if (p) {
+ p->openWallet(form);
+ return;
+ }
+
+ if (onlyLocalReferences()) { // avoid triggering on local apps, thumbnails
+ return;
+ }
+
+ if (d->m_wallet) {
+ if (d->m_bWalletOpened) {
+ if (d->m_wallet->isOpen()) {
+ form->walletOpened(d->m_wallet);
+ return;
+ }
+ d->m_wallet->deleteLater();
+ d->m_wallet = 0L;
+ d->m_bWalletOpened = false;
+ }
+ }
+
+ if (!d->m_wq) {
+ KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
+ d->m_wq = new KHTMLWalletQueue(this);
+ d->m_wq->wallet = wallet;
+ connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
+ connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
+ }
+ assert(form);
+ d->m_wq->callers.append(KHTMLWalletQueue::Caller(form, form->getDocument()));
+#endif // KHTML_NO_WALLET
+}
+
+
+void KHTMLPart::saveToWallet(const QString& key, const QMap<QString,QString>& data)
+{
+#ifndef KHTML_NO_WALLET
+ KHTMLPart *p;
+
+ for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
+ }
+
+ if (p) {
+ p->saveToWallet(key, data);
+ return;
+ }
+
+ if (d->m_wallet) {
+ if (d->m_bWalletOpened) {
+ if (d->m_wallet->isOpen()) {
+ if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder())) {
+ d->m_wallet->createFolder(KWallet::Wallet::FormDataFolder());
+ }
+ d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder());
+ d->m_wallet->writeMap(key, data);
+ return;
+ }
+ d->m_wallet->deleteLater();
+ d->m_wallet = 0L;
+ d->m_bWalletOpened = false;
+ }
+ }
+
+ if (!d->m_wq) {
+ KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
+ d->m_wq = new KHTMLWalletQueue(this);
+ d->m_wq->wallet = wallet;
+ connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
+ connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
+ }
+ d->m_wq->savers.append(qMakePair(key, data));
+#endif // KHTML_NO_WALLET
+}
+
+
+void KHTMLPart::dequeueWallet(DOM::HTMLFormElementImpl *form) {
+#ifndef KHTML_NO_WALLET
+ KHTMLPart *p;
+
+ for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
+ }
+
+ if (p) {
+ p->dequeueWallet(form);
+ return;
+ }
+
+ if (d->m_wq) {
+ d->m_wq->callers.remove(KHTMLWalletQueue::Caller(form, form->getDocument()));
+ }
+#endif // KHTML_NO_WALLET
+}
+
+
+void KHTMLPart::walletOpened(KWallet::Wallet *wallet) {
+#ifndef KHTML_NO_WALLET
+ assert(!d->m_wallet);
+ assert(d->m_wq);
+
+ d->m_wq->deleteLater(); // safe?
+ d->m_wq = 0L;
+
+ if (!wallet) {
+ d->m_bWalletOpened = false;
+ return;
+ }
+
+ d->m_wallet = wallet;
+ d->m_bWalletOpened = true;
+ connect(d->m_wallet, SIGNAL(walletClosed()), SLOT(slotWalletClosed()));
+
+ if (!d->m_statusBarWalletLabel) {
+ d->m_statusBarWalletLabel = new KURLLabel(d->m_statusBarExtension->statusBar());
+ d->m_statusBarWalletLabel->setFixedHeight(instance()->iconLoader()->currentSize(KIcon::Small));
+ d->m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ d->m_statusBarWalletLabel->setUseCursor(false);
+ d->m_statusBarExtension->addStatusBarItem(d->m_statusBarWalletLabel, 0, false);
+ d->m_statusBarWalletLabel->setPixmap(SmallIcon("wallet_open", instance()));
+ connect(d->m_statusBarWalletLabel, SIGNAL(leftClickedURL()), SLOT(launchWalletManager()));
+ connect(d->m_statusBarWalletLabel, SIGNAL(rightClickedURL()), SLOT(walletMenu()));
+ } else {
+ QToolTip::remove(d->m_statusBarWalletLabel);
+ }
+ QToolTip::add(d->m_statusBarWalletLabel, i18n("The wallet '%1' is open and being used for form data and passwords.").arg(KWallet::Wallet::NetworkWallet()));
+#endif // KHTML_NO_WALLET
+}
+
+
+KWallet::Wallet *KHTMLPart::wallet()
+{
+#ifndef KHTML_NO_WALLET
+ KHTMLPart *p;
+
+ for (p = parentPart(); p && p->parentPart(); p = p->parentPart())
+ ;
+
+ if (p)
+ return p->wallet();
+
+#endif // KHTML_NO_WALLET
+ return d->m_wallet;
+}
+
+
+void KHTMLPart::slotWalletClosed()
+{
+#ifndef KHTML_NO_WALLET
+ if (d->m_wallet) {
+ d->m_wallet->deleteLater();
+ d->m_wallet = 0L;
+ }
+ d->m_bWalletOpened = false;
+ if (d->m_statusBarWalletLabel) {
+ d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarWalletLabel);
+ delete d->m_statusBarWalletLabel;
+ d->m_statusBarWalletLabel = 0L;
+ }
+#endif // KHTML_NO_WALLET
+}
+
+void KHTMLPart::launchWalletManager()
+{
+#ifndef KHTML_NO_WALLET
+ if (!DCOPClient::mainClient()->isApplicationRegistered("kwalletmanager")) {
+ KApplication::startServiceByDesktopName("kwalletmanager_show");
+ } else {
+ DCOPRef r("kwalletmanager", "kwalletmanager-mainwindow#1");
+ r.send("show");
+ r.send("raise");
+ }
+#endif // KHTML_NO_WALLET
+}
+
+void KHTMLPart::walletMenu()
+{
+#ifndef KHTML_NO_WALLET
+ KPopupMenu *m = new KPopupMenu(0L);
+ m->insertItem(i18n("&Close Wallet"), this, SLOT(slotWalletClosed()));
+ m->popup(QCursor::pos());
+#endif // KHTML_NO_WALLET
+}
+
+void KHTMLPart::slotToggleCaretMode()
+{
+ setCaretMode(d->m_paToggleCaretMode->isChecked());
+}
+
+void KHTMLPart::setFormNotification(KHTMLPart::FormNotification fn) {
+ d->m_formNotification = fn;
+}
+
+KHTMLPart::FormNotification KHTMLPart::formNotification() const {
+ return d->m_formNotification;
+}
+
+KURL KHTMLPart::toplevelURL()
+{
+ KHTMLPart* part = this;
+ while (part->parentPart())
+ part = part->parentPart();
+
+ if (!part)
+ return KURL();
+
+ return part->url();
+}
+
+bool KHTMLPart::isModified() const
+{
+ if ( !d->m_doc )
+ return false;
+
+ return d->m_doc->unsubmittedFormChanges();
+}
+
+void KHTMLPart::setDebugScript( bool enable )
+{
+ unplugActionList( "debugScriptList" );
+ if ( enable ) {
+ if (!d->m_paDebugScript) {
+ d->m_paDebugScript = new KAction( i18n( "JavaScript &Debugger" ), 0, this, SLOT( slotDebugScript() ), actionCollection(), "debugScript" );
+ }
+ d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
+ QPtrList<KAction> lst;
+ lst.append( d->m_paDebugScript );
+ plugActionList( "debugScriptList", lst );
+ }
+ d->m_bJScriptDebugEnabled = enable;
+}
+
+void KHTMLPart::setSuppressedPopupIndicator( bool enable )
+{
+ setSuppressedPopupIndicator( enable, 0 );
+}
+
+void KHTMLPart::setSuppressedPopupIndicator( bool enable, KHTMLPart *originPart )
+{
+ if ( parentPart() ) {
+ parentPart()->setSuppressedPopupIndicator( enable, originPart );
+ return;
+ }
+
+ if ( enable && originPart ) {
+ d->m_openableSuppressedPopups++;
+ if ( d->m_suppressedPopupOriginParts.findIndex( originPart ) == -1 )
+ d->m_suppressedPopupOriginParts.append( originPart );
+ }
+
+ if ( enable && !d->m_statusBarPopupLabel ) {
+ d->m_statusBarPopupLabel = new KURLLabel( d->m_statusBarExtension->statusBar() );
+ d->m_statusBarPopupLabel->setFixedHeight( instance()->iconLoader()->currentSize( KIcon::Small) );
+ d->m_statusBarPopupLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ));
+ d->m_statusBarPopupLabel->setUseCursor( false );
+ d->m_statusBarExtension->addStatusBarItem( d->m_statusBarPopupLabel, 0, false );
+ d->m_statusBarPopupLabel->setPixmap( SmallIcon( "window_suppressed", instance() ) );
+ QToolTip::add( d->m_statusBarPopupLabel, i18n("This page was prevented from opening a new window via JavaScript." ) );
+
+ connect(d->m_statusBarPopupLabel, SIGNAL(leftClickedURL()), SLOT(suppressedPopupMenu()));
+ if (d->m_settings->jsPopupBlockerPassivePopup()) {
+ QPixmap px;
+ px = MainBarIcon( "window_suppressed" );
+ KPassivePopup::message(i18n("Popup Window Blocked"),i18n("This page has attempted to open a popup window but was blocked.\nYou can click on this icon in the status bar to control this behavior\nor to open the popup."),px,d->m_statusBarPopupLabel);
+ }
+ } else if ( !enable && d->m_statusBarPopupLabel ) {
+ QToolTip::remove( d->m_statusBarPopupLabel );
+ d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarPopupLabel );
+ delete d->m_statusBarPopupLabel;
+ d->m_statusBarPopupLabel = 0L;
+ }
+}
+
+void KHTMLPart::suppressedPopupMenu() {
+ KPopupMenu *m = new KPopupMenu(0L);
+ m->setCheckable(true);
+ if ( d->m_openableSuppressedPopups )
+ m->insertItem(i18n("&Show Blocked Popup Window","Show %n Blocked Popup Windows", d->m_openableSuppressedPopups), this, SLOT(showSuppressedPopups()));
+ m->insertItem(i18n("Show Blocked Window Passive Popup &Notification"), this, SLOT(togglePopupPassivePopup()),0,57);
+ m->setItemChecked(57,d->m_settings->jsPopupBlockerPassivePopup());
+ m->insertItem(i18n("&Configure JavaScript New Window Policies..."), this, SLOT(launchJSConfigDialog()));
+ m->popup(QCursor::pos());
+}
+
+void KHTMLPart::togglePopupPassivePopup() {
+ // Same hack as in disableJSErrorExtension()
+ d->m_settings->setJSPopupBlockerPassivePopup( !d->m_settings->jsPopupBlockerPassivePopup() );
+ DCOPClient::mainClient()->send("konqueror*", "KonquerorIface", "reparseConfiguration()", QByteArray());
+}
+
+void KHTMLPart::showSuppressedPopups() {
+ for ( QValueListIterator<QGuardedPtr<KHTMLPart> > i = d->m_suppressedPopupOriginParts.begin();
+ i != d->m_suppressedPopupOriginParts.end(); ++i ) {
+ if (KHTMLPart* part = *i) {
+ KJS::Window *w = KJS::Window::retrieveWindow( part );
+ if (w) {
+ w->showSuppressedWindows();
+ w->forgetSuppressedWindows();
+ }
+ }
+ }
+ setSuppressedPopupIndicator( false );
+ d->m_openableSuppressedPopups = 0;
+ d->m_suppressedPopupOriginParts.clear();
+}
+
+// Extension to use for "view document source", "save as" etc.
+// Using the right extension can help the viewer get into the right mode (#40496)
+QString KHTMLPart::defaultExtension() const
+{
+ if ( !d->m_doc )
+ return ".html";
+ if ( !d->m_doc->isHTMLDocument() )
+ return ".xml";
+ return d->m_doc->htmlMode() == DOM::DocumentImpl::XHtml ? ".xhtml" : ".html";
+}
+
+bool KHTMLPart::inProgress() const
+{
+ if (d->m_runningScripts || (d->m_doc && d->m_doc->parsing()))
+ return true;
+
+ // Any frame that hasn't completed yet ?
+ ConstFrameIt it = d->m_frames.begin();
+ const ConstFrameIt end = d->m_frames.end();
+ for (; it != end; ++it ) {
+ if ((*it)->m_run || !(*it)->m_bCompleted)
+ return true;
+ }
+
+ return d->m_submitForm || !d->m_redirectURL.isEmpty() || d->m_redirectionTimer.isActive() || d->m_job;
+}
+
+using namespace KParts;
+#include "khtml_part.moc"
+#include "khtmlpart_p.moc"