khtml_part.cpp

00001 // -*- c-basic-offset: 2 -*-
00002 /* This file is part of the KDE project
00003  *
00004  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00005  *                     1999 Lars Knoll <knoll@kde.org>
00006  *                     1999 Antti Koivisto <koivisto@kde.org>
00007  *                     2000 Simon Hausmann <hausmann@kde.org>
00008  *                     2000 Stefan Schimanski <1Stein@gmx.de>
00009  *                     2001-2003 George Staikos <staikos@kde.org>
00010  *                     2001-2003 Dirk Mueller <mueller@kde.org>
00011  *                     2000-2005 David Faure <faure@kde.org>
00012  *                     2002 Apple Computer, Inc.
00013  *
00014  * This library is free software; you can redistribute it and/or
00015  * modify it under the terms of the GNU Library General Public
00016  * License as published by the Free Software Foundation; either
00017  * version 2 of the License, or (at your option) any later version.
00018  *
00019  * This library is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00022  * Library General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Library General Public License
00025  * along with this library; see the file COPYING.LIB.  If not, write to
00026  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00027  * Boston, MA 02110-1301, USA.
00028  */
00029 
00030 //#define SPEED_DEBUG
00031 #include "khtml_part.h"
00032 
00033 #include "khtml_pagecache.h"
00034 
00035 #include "dom/dom_string.h"
00036 #include "dom/dom_element.h"
00037 #include "dom/dom_exception.h"
00038 #include "html/html_documentimpl.h"
00039 #include "html/html_baseimpl.h"
00040 #include "html/html_objectimpl.h"
00041 #include "html/html_miscimpl.h"
00042 #include "html/html_imageimpl.h"
00043 #include "html/html_objectimpl.h"
00044 #include "rendering/render_text.h"
00045 #include "rendering/render_frames.h"
00046 #include "rendering/render_layer.h"
00047 #include "misc/htmlhashes.h"
00048 #include "misc/loader.h"
00049 #include "xml/dom2_eventsimpl.h"
00050 #include "xml/dom2_rangeimpl.h"
00051 #include "xml/xml_tokenizer.h"
00052 #include "css/cssstyleselector.h"
00053 #include "css/csshelper.h"
00054 using namespace DOM;
00055 
00056 #include "khtmlview.h"
00057 #include <kparts/partmanager.h>
00058 #include "ecma/kjs_proxy.h"
00059 #include "ecma/kjs_window.h"
00060 #include "khtml_settings.h"
00061 #include "kjserrordlg.h"
00062 
00063 #include <kjs/function.h>
00064 #include <kjs/interpreter.h>
00065 
00066 #include "htmlpageinfo.h"
00067 
00068 #include <sys/types.h>
00069 #include <assert.h>
00070 #include <unistd.h>
00071 
00072 #include <config.h>
00073 
00074 #include <dcopclient.h>
00075 #include <dcopref.h>
00076 #include <kstandarddirs.h>
00077 #include <kstringhandler.h>
00078 #include <kio/job.h>
00079 #include <kio/global.h>
00080 #include <kio/netaccess.h>
00081 #include <kprotocolmanager.h>
00082 #include <kdebug.h>
00083 #include <kiconloader.h>
00084 #include <klocale.h>
00085 #include <kcharsets.h>
00086 #include <kmessagebox.h>
00087 #include <kstdaction.h>
00088 #include <kfiledialog.h>
00089 #include <ktrader.h>
00090 #include <kdatastream.h>
00091 #include <ktempfile.h>
00092 #include <kglobalsettings.h>
00093 #include <kurldrag.h>
00094 #include <kapplication.h>
00095 #include <kparts/browserinterface.h>
00096 #if !defined(QT_NO_DRAGANDDROP)
00097 #include <kmultipledrag.h>
00098 #endif
00099 #include "../kutils/kfinddialog.h"
00100 #include "../kutils/kfind.h"
00101 
00102 #include <ksslcertchain.h>
00103 #include <ksslinfodlg.h>
00104 
00105 #include <kfileitem.h>
00106 #include <kurifilter.h>
00107 #include <kstatusbar.h>
00108 #include <kurllabel.h>
00109 
00110 #include <qclipboard.h>
00111 #include <qfile.h>
00112 #include <qtooltip.h>
00113 #include <qmetaobject.h>
00114 #include <private/qucomextra_p.h>
00115 
00116 #include "khtmlpart_p.h"
00117 #include "kpassivepopup.h"
00118 #include "kpopupmenu.h"
00119 #include "rendering/render_form.h"
00120 #include <kwin.h>
00121 
00122 #define HINT_UTF8   106
00123 
00124 namespace khtml {
00125     class PartStyleSheetLoader : public CachedObjectClient
00126     {
00127     public:
00128         PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
00129         {
00130             m_part = part;
00131             m_cachedSheet = dl->requestStyleSheet(url, QString::null, "text/css",
00132                                                   true /* "user sheet" */);
00133             if (m_cachedSheet)
00134         m_cachedSheet->ref( this );
00135         }
00136         virtual ~PartStyleSheetLoader()
00137         {
00138             if ( m_cachedSheet ) m_cachedSheet->deref(this);
00139         }
00140         virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet, const DOM::DOMString &)
00141         {
00142           if ( m_part )
00143             m_part->setUserStyleSheet( sheet.string() );
00144 
00145             delete this;
00146         }
00147         virtual void error( int, const QString& ) {
00148           delete this;
00149         }
00150         QGuardedPtr<KHTMLPart> m_part;
00151         khtml::CachedCSSStyleSheet *m_cachedSheet;
00152     };
00153 }
00154 
00155 void khtml::ChildFrame::liveConnectEvent(const unsigned long, const QString & event, const KParts::LiveConnectExtension::ArgList & args)
00156 {
00157     if (!m_part || !m_frame || !m_liveconnect)
00158         // hmmm
00159         return;
00160 
00161     QString script;
00162     script.sprintf("%s(", event.latin1());
00163 
00164     KParts::LiveConnectExtension::ArgList::const_iterator i = args.begin();
00165     const KParts::LiveConnectExtension::ArgList::const_iterator argsBegin = i;
00166     const KParts::LiveConnectExtension::ArgList::const_iterator argsEnd = args.end();
00167 
00168     for ( ; i != argsEnd; ++i) {
00169         if (i != argsBegin)
00170             script += ",";
00171         if ((*i).first == KParts::LiveConnectExtension::TypeString) {
00172             script += "\"";
00173             script += QString((*i).second).replace('\\', "\\\\").replace('"', "\\\"");
00174             script += "\"";
00175         } else
00176             script += (*i).second;
00177     }
00178     script += ")";
00179     kdDebug(6050) << "khtml::ChildFrame::liveConnectEvent " << script << endl;
00180 
00181     KHTMLPart * part = ::qt_cast<KHTMLPart *>(m_part->parent());
00182     if (!part)
00183         return;
00184     if (!m_jscript)
00185         part->framejScript(m_part);
00186     if (m_jscript) {
00187         // we have a jscript => a part in an iframe
00188         KJS::Completion cmp;
00189         m_jscript->evaluate(QString::null, 1, script, 0L, &cmp);
00190     } else
00191         part->executeScript(m_frame->element(), script);
00192 }
00193 
00194 KHTMLFrameList::Iterator KHTMLFrameList::find( const QString &name )
00195 {
00196     Iterator it = begin();
00197     const Iterator e = end();
00198 
00199     for (; it!=e; ++it )
00200         if ( (*it)->m_name==name )
00201             break;
00202 
00203     return it;
00204 }
00205 
00206 KHTMLPart::KHTMLPart( QWidget *parentWidget, const char *widgetname, QObject *parent, const char *name, GUIProfile prof )
00207 : KParts::ReadOnlyPart( parent, name )
00208 {
00209     d = 0;
00210     KHTMLFactory::registerPart( this );
00211     setInstance(  KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
00212     // TODO KDE4 - don't load plugins yet
00213     //setInstance( KHTMLFactory::instance(), false );
00214     init( new KHTMLView( this, parentWidget, widgetname ), prof );
00215 }
00216 
00217 KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, const char *name, GUIProfile prof )
00218 : KParts::ReadOnlyPart( parent, name )
00219 {
00220     d = 0;
00221     KHTMLFactory::registerPart( this );
00222     setInstance(  KHTMLFactory::instance(), prof == BrowserViewGUI && !parentPart() );
00223     // TODO KDE4 - don't load plugins yet
00224     //setInstance( KHTMLFactory::instance(), false );
00225     assert( view );
00226     init( view, prof );
00227 }
00228 
00229 void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
00230 {
00231   if ( prof == DefaultGUI )
00232     setXMLFile( "khtml.rc" );
00233   else if ( prof == BrowserViewGUI )
00234     setXMLFile( "khtml_browser.rc" );
00235 
00236   d = new KHTMLPartPrivate(parent());
00237 
00238   d->m_view = view;
00239   setWidget( d->m_view );
00240 
00241   d->m_guiProfile = prof;
00242   d->m_extension = new KHTMLPartBrowserExtension( this, "KHTMLBrowserExtension" );
00243   d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
00244   d->m_statusBarExtension = new KParts::StatusBarExtension( this );
00245   d->m_statusBarIconLabel = 0L;
00246   d->m_statusBarPopupLabel = 0L;
00247   d->m_openableSuppressedPopups = 0;
00248 
00249   d->m_bSecurityInQuestion = false;
00250   d->m_paLoadImages = 0;
00251   d->m_paDebugScript = 0;
00252   d->m_bMousePressed = false;
00253   d->m_bRightMousePressed = false;
00254   d->m_bCleared = false;
00255   d->m_paViewDocument = new KAction( i18n( "View Do&cument Source" ), CTRL + Key_U, this, SLOT( slotViewDocumentSource() ), actionCollection(), "viewDocumentSource" );
00256   d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), 0, this, SLOT( slotViewFrameSource() ), actionCollection(), "viewFrameSource" );
00257   d->m_paViewInfo = new KAction( i18n( "View Document Information" ), CTRL+Key_I, this, SLOT( slotViewPageInfo() ), actionCollection(), "viewPageInfo" );
00258   d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), 0, this, SLOT( slotSaveBackground() ), actionCollection(), "saveBackground" );
00259   d->m_paSaveDocument = KStdAction::saveAs( this, SLOT( slotSaveDocument() ), actionCollection(), "saveDocument" );
00260   if ( parentPart() )
00261       d->m_paSaveDocument->setShortcut( KShortcut() ); // avoid clashes
00262   d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), 0, this, SLOT( slotSaveFrame() ), actionCollection(), "saveFrame" );
00263   d->m_paSecurity = new KAction( i18n( "Security..." ), "decrypted", 0, this, SLOT( slotSecurity() ), actionCollection(), "security" );
00264   d->m_paSecurity->setWhatsThis( i18n( "Security Settings<p>"
00265                                        "Shows the certificate of the displayed page. Only "
00266                        "pages that have been transmitted using a secure, encrypted connection have a "
00267                        "certificate.<p> "
00268                        "Hint: If the image shows a closed lock, the page has been transmitted over a "
00269                        "secure connection.") );
00270   d->m_paDebugRenderTree = new KAction( i18n( "Print Rendering Tree to STDOUT" ), ALT + CTRL + SHIFT + Key_A, this, SLOT( slotDebugRenderTree() ), actionCollection(), "debugRenderTree" );
00271   d->m_paDebugDOMTree = new KAction( i18n( "Print DOM Tree to STDOUT" ), ALT + CTRL + SHIFT + Key_D, this, SLOT( slotDebugDOMTree() ), actionCollection(), "debugDOMTree" );
00272   d->m_paStopAnimations = new KAction( i18n( "Stop Animated Images" ), 0, this, SLOT( slotStopAnimations() ), actionCollection(), "stopAnimations" );
00273 
00274   d->m_paSetEncoding = new KActionMenu( i18n( "Set &Encoding" ), "charset", actionCollection(), "setEncoding" );
00275   d->m_paSetEncoding->setDelayed( false );
00276 
00277   d->m_automaticDetection = new KPopupMenu( 0L );
00278 
00279   d->m_automaticDetection->insertItem( i18n( "Semi-Automatic" ), 0 );
00280   d->m_automaticDetection->insertItem( i18n( "Arabic" ), 1 );
00281   d->m_automaticDetection->insertItem( i18n( "Baltic" ), 2 );
00282   d->m_automaticDetection->insertItem( i18n( "Central European" ), 3 );
00283   //d->m_automaticDetection->insertItem( i18n( "Chinese" ), 4 );
00284   d->m_automaticDetection->insertItem( i18n( "Greek" ), 5 );
00285   d->m_automaticDetection->insertItem( i18n( "Hebrew" ), 6 );
00286   d->m_automaticDetection->insertItem( i18n( "Japanese" ), 7 );
00287   //d->m_automaticDetection->insertItem( i18n( "Korean" ), 8 );
00288   d->m_automaticDetection->insertItem( i18n( "Russian" ), 9 );
00289   //d->m_automaticDetection->insertItem( i18n( "Thai" ), 10 );
00290   d->m_automaticDetection->insertItem( i18n( "Turkish" ), 11 );
00291   d->m_automaticDetection->insertItem( i18n( "Ukrainian" ), 12 );
00292   //d->m_automaticDetection->insertItem( i18n( "Unicode" ), 13 );
00293   d->m_automaticDetection->insertItem( i18n( "Western European" ), 14 );
00294 
00295   connect( d->m_automaticDetection, SIGNAL( activated( int ) ), this, SLOT( slotAutomaticDetectionLanguage( int ) ) );
00296 
00297   d->m_paSetEncoding->popupMenu()->insertItem( i18n( "Automatic Detection" ), d->m_automaticDetection, 0 );
00298 
00299   d->m_paSetEncoding->insert( new KActionSeparator( actionCollection() ) );
00300 
00301 
00302   d->m_manualDetection = new KSelectAction( i18n( "short for Manual Detection", "Manual" ), 0, this, SLOT( slotSetEncoding() ), actionCollection(), "manualDetection" );
00303   QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames();
00304   d->m_manualDetection->setItems( encodings );
00305   d->m_manualDetection->setCurrentItem( -1 );
00306   d->m_paSetEncoding->insert( d->m_manualDetection );
00307 
00308 
00309   KConfig *config = KGlobal::config();
00310   if ( config->hasGroup( "HTML Settings" ) ) {
00311     config->setGroup( "HTML Settings" );
00312     khtml::Decoder::AutoDetectLanguage language;
00313     QCString name = QTextCodec::codecForLocale()->name();
00314     name = name.lower();
00315 
00316     if ( name == "cp1256" || name == "iso-8859-6" ) {
00317       language = khtml::Decoder::Arabic;
00318     }
00319     else if ( name == "cp1257" || name == "iso-8859-13" || name == "iso-8859-4" ) {
00320       language = khtml::Decoder::Baltic;
00321     }
00322     else if ( name == "cp1250" || name == "ibm852" || name == "iso-8859-2" || name == "iso-8859-3" ) {
00323       language = khtml::Decoder::CentralEuropean;
00324     }
00325     else if ( name == "cp1251" || name == "koi8-r" || name == "iso-8859-5" ) {
00326       language = khtml::Decoder::Russian;
00327     }
00328     else if ( name == "koi8-u" ) {
00329       language = khtml::Decoder::Ukrainian;
00330     }
00331     else if ( name == "cp1253" || name == "iso-8859-7" ) {
00332       language = khtml::Decoder::Greek;
00333     }
00334     else if ( name == "cp1255" || name == "iso-8859-8" || name == "iso-8859-8-i" ) {
00335       language = khtml::Decoder::Hebrew;
00336     }
00337     else if ( name == "jis7" || name == "eucjp" || name == "sjis"  ) {
00338       language = khtml::Decoder::Japanese;
00339     }
00340     else if ( name == "cp1254" || name == "iso-8859-9" ) {
00341       language = khtml::Decoder::Turkish;
00342     }
00343     else if ( name == "cp1252" || name == "iso-8859-1" || name == "iso-8859-15" ) {
00344       language = khtml::Decoder::WesternEuropean;
00345     }
00346     else
00347       language = khtml::Decoder::SemiautomaticDetection;
00348 
00349     int _id = config->readNumEntry( "AutomaticDetectionLanguage", language );
00350     d->m_automaticDetection->setItemChecked( _id, true );
00351     d->m_paSetEncoding->popupMenu()->setItemChecked( 0, true );
00352 
00353     d->m_autoDetectLanguage = static_cast< khtml::Decoder::AutoDetectLanguage >( _id );
00354   }
00355 
00356 
00357   d->m_paUseStylesheet = new KSelectAction( i18n( "Use S&tylesheet"), 0, this, SLOT( slotUseStylesheet() ), actionCollection(), "useStylesheet" );
00358 
00359   if ( prof == BrowserViewGUI ) {
00360       d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, i18n(
00361                   "Enlarge Font" ), "viewmag+", "CTRL++;CTRL+=", this,
00362               SLOT( slotIncZoomFast() ), actionCollection(), "incFontSizes" );
00363       d->m_paIncZoomFactor->setWhatsThis( i18n( "Enlarge Font<p>"
00364                                                 "Make the font in this window bigger. "
00365                             "Click and hold down the mouse button for a menu with all available font sizes." ) );
00366       d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, i18n(
00367                   "Shrink Font" ), "viewmag-", CTRL + Key_Minus, this,
00368               SLOT( slotDecZoomFast() ), actionCollection(), "decFontSizes" );
00369       d->m_paDecZoomFactor->setWhatsThis( i18n( "Shrink Font<p>"
00370                                                 "Make the font in this window smaller. "
00371                             "Click and hold down the mouse button for a menu with all available font sizes." ) );
00372   }
00373 
00374   d->m_paFind = KStdAction::find( this, SLOT( slotFind() ), actionCollection(), "find" );
00375   d->m_paFind->setWhatsThis( i18n( "Find text<p>"
00376                    "Shows a dialog that allows you to find text on the displayed page." ) );
00377 
00378   d->m_paFindNext = KStdAction::findNext( this, SLOT( slotFindNext() ), actionCollection(), "findNext" );
00379   d->m_paFindNext->setWhatsThis( i18n( "Find next<p>"
00380                        "Find the next occurrence of the text that you "
00381                        "have found using the <b>Find Text</b> function" ) );
00382 
00383   d->m_paFindPrev = KStdAction::findPrev( this, SLOT( slotFindPrev() ), actionCollection(), "findPrevious" );
00384   d->m_paFindPrev->setWhatsThis( i18n( "Find previous<p>"
00385                        "Find the previous occurrence of the text that you "
00386                        "have found using the <b>Find Text</b> function" ) );
00387 
00388   d->m_paFindAheadText = new KAction( i18n("Find Text as You Type"), KShortcut( '/' ), this, SLOT( slotFindAheadText()),
00389       actionCollection(), "findAheadText");
00390   d->m_paFindAheadLinks = new KAction( i18n("Find Links as You Type"), KShortcut( '\'' ), this, SLOT( slotFindAheadLink()),
00391       actionCollection(), "findAheadLink");
00392   d->m_paFindAheadText->setEnabled( false );
00393   d->m_paFindAheadLinks->setEnabled( false );
00394 
00395   if ( parentPart() )
00396   {
00397       d->m_paFind->setShortcut( KShortcut() ); // avoid clashes
00398       d->m_paFindNext->setShortcut( KShortcut() ); // avoid clashes
00399       d->m_paFindPrev->setShortcut( KShortcut() ); // avoid clashes
00400       d->m_paFindAheadText->setShortcut( KShortcut());
00401       d->m_paFindAheadLinks->setShortcut( KShortcut());
00402   }
00403 
00404   d->m_paPrintFrame = new KAction( i18n( "Print Frame..." ), "frameprint", 0, this, SLOT( slotPrintFrame() ), actionCollection(), "printFrame" );
00405   d->m_paPrintFrame->setWhatsThis( i18n( "Print Frame<p>"
00406                      "Some pages have several frames. To print only a single frame, click "
00407                      "on it and then use this function." ) );
00408 
00409   d->m_paSelectAll = KStdAction::selectAll( this, SLOT( slotSelectAll() ), actionCollection(), "selectAll" );
00410   if ( parentPart() )
00411       d->m_paSelectAll->setShortcut( KShortcut() ); // avoid clashes
00412 
00413   d->m_paToggleCaretMode = new KToggleAction(i18n("Toggle Caret Mode"),
00414                 Key_F7, this, SLOT(slotToggleCaretMode()),
00415                                 actionCollection(), "caretMode");
00416   d->m_paToggleCaretMode->setChecked(isCaretMode());
00417   if (parentPart())
00418       d->m_paToggleCaretMode->setShortcut(KShortcut()); // avoid clashes
00419 
00420   // set the default java(script) flags according to the current host.
00421   d->m_bOpenMiddleClick = d->m_settings->isOpenMiddleClickEnabled();
00422   d->m_bBackRightClick = d->m_settings->isBackRightClickEnabled();
00423   d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
00424   setDebugScript( d->m_settings->isJavaScriptDebugEnabled() );
00425   d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
00426   d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
00427 
00428   // Set the meta-refresh flag...
00429   d->m_metaRefreshEnabled = d->m_settings->isAutoDelayedActionsEnabled ();
00430 
00431   connect( view, SIGNAL( zoomView( int ) ), SLOT( slotZoomView( int ) ) );
00432 
00433   connect( this, SIGNAL( completed() ),
00434            this, SLOT( updateActions() ) );
00435   connect( this, SIGNAL( completed( bool ) ),
00436            this, SLOT( updateActions() ) );
00437   connect( this, SIGNAL( started( KIO::Job * ) ),
00438            this, SLOT( updateActions() ) );
00439 
00440   d->m_popupMenuXML = KXMLGUIFactory::readConfigFile( locate( "data", "khtml/khtml_popupmenu.rc", KHTMLFactory::instance() ) );
00441 
00442   connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
00443            this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
00444   connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
00445            this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
00446   connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
00447            this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
00448 
00449   connect ( &d->m_progressUpdateTimer, SIGNAL( timeout() ), this, SLOT( slotProgressUpdate() ) );
00450 
00451   findTextBegin(); //reset find variables
00452 
00453   connect( &d->m_redirectionTimer, SIGNAL( timeout() ),
00454            this, SLOT( slotRedirect() ) );
00455 
00456   d->m_dcopobject = new KHTMLPartIface(this);
00457 
00458   // TODO KDE4 - load plugins now (see also the constructors)
00459   //if ( prof == BrowserViewGUI && !parentPart() )
00460   //        loadPlugins( partObject(), this, instance() );
00461 
00462   // "khtml" catalog does not exist, our translations are in kdelibs.
00463   // removing this catalog from KGlobal::locale() prevents problems
00464   // with changing the language in applications at runtime -Thomas Reitelbach
00465   KGlobal::locale()->removeCatalogue("khtml");
00466 }
00467 
00468 KHTMLPart::~KHTMLPart()
00469 {
00470   //kdDebug(6050) << "KHTMLPart::~KHTMLPart " << this << endl;
00471 
00472   KConfig *config = KGlobal::config();
00473   config->setGroup( "HTML Settings" );
00474   config->writeEntry( "AutomaticDetectionLanguage", d->m_autoDetectLanguage );
00475 
00476   delete d->m_automaticDetection;
00477   delete d->m_manualDetection;
00478 
00479   slotWalletClosed();
00480   if (!parentPart()) { // only delete it if the top khtml_part closes
00481     removeJSErrorExtension();
00482     delete d->m_statusBarPopupLabel;
00483   }
00484 
00485   d->m_find = 0; // deleted by its parent, the view.
00486 
00487   if ( d->m_manager )
00488   {
00489     d->m_manager->setActivePart( 0 );
00490     // We specify "this" as parent qobject for d->manager, so no need to delete it.
00491   }
00492 
00493   stopAutoScroll();
00494   d->m_redirectionTimer.stop();
00495 
00496   if (!d->m_bComplete)
00497     closeURL();
00498 
00499   disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
00500            this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
00501   disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
00502            this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
00503   disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
00504            this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
00505 
00506   clear();
00507 
00508   if ( d->m_view )
00509   {
00510     d->m_view->hide();
00511     d->m_view->viewport()->hide();
00512     d->m_view->m_part = 0;
00513   }
00514 
00515   // Have to delete this here since we forward declare it in khtmlpart_p and
00516   // at least some compilers won't call the destructor in this case.
00517   delete d->m_jsedlg;
00518   d->m_jsedlg = 0;
00519 
00520   if (!parentPart()) // only delete d->m_frame if the top khtml_part closes
00521       delete d->m_frame;
00522   delete d; d = 0;
00523   KHTMLFactory::deregisterPart( this );
00524 }
00525 
00526 bool KHTMLPart::restoreURL( const KURL &url )
00527 {
00528   kdDebug( 6050 ) << "KHTMLPart::restoreURL " << url.url() << endl;
00529 
00530   d->m_redirectionTimer.stop();
00531 
00532   /*
00533    * That's not a good idea as it will call closeURL() on all
00534    * child frames, preventing them from further loading. This
00535    * method gets called from restoreState() in case of a full frameset
00536    * restoral, and restoreState() calls closeURL() before restoring
00537    * anyway.
00538   kdDebug( 6050 ) << "closing old URL" << endl;
00539   closeURL();
00540   */
00541 
00542   d->m_bComplete = false;
00543   d->m_bLoadEventEmitted = false;
00544   d->m_workingURL = url;
00545 
00546   // set the java(script) flags according to the current host.
00547   d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
00548   setDebugScript( KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
00549   d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
00550   d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
00551 
00552   m_url = url;
00553 
00554   d->m_restoreScrollPosition = true;
00555   disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
00556   connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
00557 
00558   KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &)));
00559 
00560   emit started( 0L );
00561 
00562   return true;
00563 }
00564 
00565 
00566 bool KHTMLPart::openURL( const KURL &url )
00567 {
00568   kdDebug( 6050 ) << "KHTMLPart(" << this << ")::openURL " << url.url() << endl;
00569 
00570   d->m_redirectionTimer.stop();
00571 
00572   // check to see if this is an "error://" URL. This is caused when an error
00573   // occurs before this part was loaded (e.g. KonqRun), and is passed to
00574   // khtmlpart so that it can display the error.
00575   if ( url.protocol() == "error" && url.hasSubURL() ) {
00576     closeURL();
00577 
00578     if(  d->m_bJScriptEnabled )
00579       d->m_statusBarText[BarOverrideText] = d->m_statusBarText[BarDefaultText] = QString::null;
00580 
00586     KURL::List urls = KURL::split( url );
00587     //kdDebug(6050) << "Handling error URL. URL count:" << urls.count() << endl;
00588 
00589     if ( urls.count() > 1 ) {
00590       KURL mainURL = urls.first();
00591       int error = mainURL.queryItem( "error" ).toInt();
00592       // error=0 isn't a valid error code, so 0 means it's missing from the URL
00593       if ( error == 0 ) error = KIO::ERR_UNKNOWN;
00594       QString errorText = mainURL.queryItem( "errText", HINT_UTF8 );
00595       urls.pop_front();
00596       d->m_workingURL = KURL::join( urls );
00597       //kdDebug(6050) << "Emitting fixed URL " << d->m_workingURL.prettyURL() << endl;
00598       emit d->m_extension->setLocationBarURL( d->m_workingURL.prettyURL() );
00599       htmlError( error, errorText, d->m_workingURL );
00600       return true;
00601     }
00602   }
00603 
00604   if (!parentPart()) { // only do it for toplevel part
00605     QString host = url.isLocalFile() ? "localhost" : url.host();
00606     QString userAgent = KProtocolManager::userAgentForHost(host);
00607     if (userAgent != KProtocolManager::userAgentForHost(QString::null)) {
00608       if (!d->m_statusBarUALabel) {
00609         d->m_statusBarUALabel = new KURLLabel(d->m_statusBarExtension->statusBar());
00610         d->m_statusBarUALabel->setFixedHeight(instance()->iconLoader()->currentSize(KIcon::Small));
00611         d->m_statusBarUALabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
00612         d->m_statusBarUALabel->setUseCursor(false);
00613         d->m_statusBarExtension->addStatusBarItem(d->m_statusBarUALabel, 0, false);
00614         d->m_statusBarUALabel->setPixmap(SmallIcon("agent", instance()));
00615       } else {
00616         QToolTip::remove(d->m_statusBarUALabel);
00617       }
00618       QToolTip::add(d->m_statusBarUALabel, i18n("The fake user-agent '%1' is in use.").arg(userAgent));
00619     } else if (d->m_statusBarUALabel) {
00620       d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarUALabel);
00621       delete d->m_statusBarUALabel;
00622       d->m_statusBarUALabel = 0L;
00623     }
00624   }
00625 
00626   KParts::URLArgs args( d->m_extension->urlArgs() );
00627 
00628   // in case
00629   // a) we have no frameset (don't test m_frames.count(), iframes get in there)
00630   // b) the url is identical with the currently displayed one (except for the htmlref!)
00631   // c) the url request is not a POST operation and
00632   // d) the caller did not request to reload the page
00633   // e) there was no HTTP redirection meanwhile (testcase: webmin's software/tree.cgi)
00634   // => we don't reload the whole document and
00635   // we just jump to the requested html anchor
00636   bool isFrameSet = false;
00637   if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
00638       HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
00639       isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET);
00640   }
00641 
00642   if ( url.hasRef() && !isFrameSet )
00643   {
00644     bool noReloadForced = !args.reload && !args.redirectedRequest() && !args.doPost();
00645     if (noReloadForced && urlcmp( url.url(), m_url.url(), true, true ))
00646     {
00647         kdDebug( 6050 ) << "KHTMLPart::openURL, jumping to anchor. m_url = " << url.url() << endl;
00648         m_url = url;
00649         emit started( 0L );
00650 
00651         if ( !gotoAnchor( url.encodedHtmlRef()) )
00652           gotoAnchor( url.htmlRef() );
00653 
00654         d->m_bComplete = true;
00655         if (d->m_doc)
00656         d->m_doc->setParsing(false);
00657 
00658         kdDebug( 6050 ) << "completed..." << endl;
00659         emit completed();
00660         return true;
00661     }
00662   }
00663 
00664   // Save offset of viewport when page is reloaded to be compliant
00665   // to every other capable browser out there.
00666   if (args.reload) {
00667     args.xOffset = d->m_view->contentsX();
00668     args.yOffset = d->m_view->contentsY();
00669     d->m_extension->setURLArgs(args);
00670   }
00671 
00672   if (!d->m_restored)
00673     closeURL();
00674 
00675   d->m_restoreScrollPosition = d->m_restored;
00676   disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
00677   connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
00678 
00679   // 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
00680   // data arrives) (Simon)
00681   m_url = url;
00682   if(m_url.protocol().startsWith( "http" ) && !m_url.host().isEmpty() &&
00683      m_url.path().isEmpty()) {
00684     m_url.setPath("/");
00685     emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
00686   }
00687   // copy to m_workingURL after fixing m_url above
00688   d->m_workingURL = m_url;
00689 
00690   args.metaData().insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" );
00691   args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
00692   args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
00693   args.metaData().insert("PropagateHttpHeader", "true");
00694   args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" );
00695   args.metaData().insert("ssl_activate_warnings", "TRUE" );
00696   args.metaData().insert("cross-domain", toplevelURL().url());
00697 
00698   if (d->m_restored)
00699   {
00700      args.metaData().insert("referrer", d->m_pageReferrer);
00701      d->m_cachePolicy = KIO::CC_Cache;
00702   }
00703   else if (args.reload)
00704      d->m_cachePolicy = KIO::CC_Reload;
00705   else
00706      d->m_cachePolicy = KProtocolManager::cacheControl();
00707 
00708   if ( args.doPost() && (m_url.protocol().startsWith("http")) )
00709   {
00710       d->m_job = KIO::http_post( m_url, args.postData, false );
00711       d->m_job->addMetaData("content-type", args.contentType() );
00712   }
00713   else
00714   {
00715       d->m_job = KIO::get( m_url, false, false );
00716       d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
00717   }
00718 
00719   if (widget())
00720      d->m_job->setWindow(widget()->topLevelWidget());
00721   d->m_job->addMetaData(args.metaData());
00722 
00723   connect( d->m_job, SIGNAL( result( KIO::Job* ) ),
00724            SLOT( slotFinished( KIO::Job* ) ) );
00725   connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
00726            SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
00727   connect ( d->m_job, SIGNAL( infoMessage( KIO::Job*, const QString& ) ),
00728            SLOT( slotInfoMessage(KIO::Job*, const QString& ) ) );
00729   connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KURL& ) ),
00730            SLOT( slotRedirection(KIO::Job*, const KURL&) ) );
00731 
00732   d->m_bComplete = false;
00733   d->m_bLoadEventEmitted = false;
00734 
00735   // delete old status bar msg's from kjs (if it _was_ activated on last URL)
00736   if( d->m_bJScriptEnabled )
00737     d->m_statusBarText[BarOverrideText] = d->m_statusBarText[BarDefaultText] = QString::null;
00738 
00739   // set the javascript flags according to the current url
00740   d->m_bJScriptEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
00741   setDebugScript( KHTMLFactory::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
00742   d->m_bJavaEnabled = KHTMLFactory::defaultHTMLSettings()->isJavaEnabled(url.host());
00743   d->m_bPluginsEnabled = KHTMLFactory::defaultHTMLSettings()->isPluginsEnabled(url.host());
00744 
00745 
00746   connect( d->m_job, SIGNAL( speed( KIO::Job*, unsigned long ) ),
00747            this, SLOT( slotJobSpeed( KIO::Job*, unsigned long ) ) );
00748 
00749   connect( d->m_job, SIGNAL( percent( KIO::Job*, unsigned long ) ),
00750            this, SLOT( slotJobPercent( KIO::Job*, unsigned long ) ) );
00751 
00752   connect( d->m_job, SIGNAL( result( KIO::Job* ) ),
00753            this, SLOT( slotJobDone( KIO::Job* ) ) );
00754 
00755   d->m_jobspeed = 0;
00756 
00757   // If this was an explicit reload and the user style sheet should be used,
00758   // do a stat to see whether the stylesheet was changed in the meanwhile.
00759   if ( args.reload && !settings()->userStyleSheet().isEmpty() ) {
00760     KURL url( settings()->userStyleSheet() );
00761     KIO::StatJob *job = KIO::stat( url, false /* don't show progress */ );
00762     connect( job, SIGNAL( result( KIO::Job * ) ),
00763              this, SLOT( slotUserSheetStatDone( KIO::Job * ) ) );
00764   }
00765   emit started( 0L );
00766 
00767   return true;
00768 }
00769 
00770 bool KHTMLPart::closeURL()
00771 {
00772   if ( d->m_job )
00773   {
00774     KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
00775     d->m_job->kill();
00776     d->m_job = 0;
00777   }
00778 
00779   if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
00780     HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
00781 
00782     if ( hdoc->body() && d->m_bLoadEventEmitted ) {
00783       hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false );
00784       if ( d->m_doc )
00785         d->m_doc->updateRendering();
00786       d->m_bLoadEventEmitted = false;
00787     }
00788   }
00789 
00790   d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
00791   d->m_bLoadEventEmitted = true; // don't want that one either
00792   d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
00793 
00794   disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
00795 
00796   KHTMLPageCache::self()->cancelFetch(this);
00797   if ( d->m_doc && d->m_doc->parsing() )
00798   {
00799     kdDebug( 6050 ) << " was still parsing... calling end " << endl;
00800     slotFinishedParsing();
00801     d->m_doc->setParsing(false);
00802   }
00803 
00804   if ( !d->m_workingURL.isEmpty() )
00805   {
00806     // Aborted before starting to render
00807     kdDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << m_url.prettyURL() << endl;
00808     emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
00809   }
00810 
00811   d->m_workingURL = KURL();
00812 
00813   if ( d->m_doc && d->m_doc->docLoader() )
00814     khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() );
00815 
00816   // tell all subframes to stop as well
00817   {
00818     ConstFrameIt it = d->m_frames.begin();
00819     const ConstFrameIt end = d->m_frames.end();
00820     for (; it != end; ++it )
00821     {
00822       if ( (*it)->m_run )
00823         (*it)->m_run->abort();
00824       if ( !( *it )->m_part.isNull() )
00825         ( *it )->m_part->closeURL();
00826     }
00827   }
00828   // tell all objects to stop as well
00829   {
00830     ConstFrameIt it = d->m_objects.begin();
00831     const ConstFrameIt end = d->m_objects.end();
00832     for (; it != end; ++it)
00833     {
00834       if ( !( *it )->m_part.isNull() )
00835         ( *it )->m_part->closeURL();
00836     }
00837   }
00838   // Stop any started redirections as well!! (DA)
00839   if ( d && d->m_redirectionTimer.isActive() )
00840     d->m_redirectionTimer.stop();
00841 
00842   // null node activated.
00843   emit nodeActivated(Node());
00844 
00845   // make sure before clear() runs, we pop out of a dialog's message loop
00846   if ( d->m_view )
00847     d->m_view->closeChildDialogs();
00848 
00849   return true;
00850 }
00851 
00852 DOM::HTMLDocument KHTMLPart::htmlDocument() const
00853 {
00854   if (d->m_doc && d->m_doc->isHTMLDocument())
00855     return static_cast<HTMLDocumentImpl*>(d->m_doc);
00856   else
00857     return static_cast<HTMLDocumentImpl*>(0);
00858 }
00859 
00860 DOM::Document KHTMLPart::document() const
00861 {
00862     return d->m_doc;
00863 }
00864 
00865 QString KHTMLPart::documentSource() const
00866 {
00867   QString sourceStr;
00868   if ( !( m_url.isLocalFile() ) && KHTMLPageCache::self()->isComplete( d->m_cacheId ) )
00869   {
00870      QByteArray sourceArray;
00871      QDataStream dataStream( sourceArray, IO_WriteOnly );
00872      KHTMLPageCache::self()->saveData( d->m_cacheId, &dataStream );
00873      QTextStream stream( sourceArray, IO_ReadOnly );
00874      stream.setCodec( QTextCodec::codecForName( encoding().latin1() ) );
00875      sourceStr = stream.read();
00876   } else
00877   {
00878     QString tmpFile;
00879     if( KIO::NetAccess::download( m_url, tmpFile, NULL ) )
00880     {
00881