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)
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       QFile f( tmpFile );
00882       if ( f.open( IO_ReadOnly ) )
00883       {
00884         QTextStream stream( &f );
00885         stream.setCodec( QTextCodec::codecForName( encoding().latin1() ) );
00886     sourceStr = stream.read();
00887         f.close();
00888       }
00889       KIO::NetAccess::removeTempFile( tmpFile );
00890     }
00891   }
00892 
00893   return sourceStr;
00894 }
00895 
00896 
00897 KParts::BrowserExtension *KHTMLPart::browserExtension() const
00898 {
00899   return d->m_extension;
00900 }
00901 
00902 KParts::BrowserHostExtension *KHTMLPart::browserHostExtension() const
00903 {
00904   return d->m_hostExtension;
00905 }
00906 
00907 KHTMLView *KHTMLPart::view() const
00908 {
00909   return d->m_view;
00910 }
00911 
00912 void KHTMLPart::setStatusMessagesEnabled( bool enable )
00913 {
00914   d->m_statusMessagesEnabled = enable;
00915 }
00916 
00917 KJS::Interpreter *KHTMLPart::jScriptInterpreter()
00918 {
00919   KJSProxy *proxy = jScript();
00920   if (!proxy || proxy->paused())
00921     return 0;
00922 
00923   return proxy->interpreter();
00924 }
00925 
00926 bool KHTMLPart::statusMessagesEnabled() const
00927 {
00928   return d->m_statusMessagesEnabled;
00929 }
00930 
00931 void KHTMLPart::setJScriptEnabled( bool enable )
00932 {
00933   if ( !enable && jScriptEnabled() && d->m_frame && d->m_frame->m_jscript ) {
00934     d->m_frame->m_jscript->clear();
00935   }
00936   d->m_bJScriptForce = enable;
00937   d->m_bJScriptOverride = true;
00938 }
00939 
00940 bool KHTMLPart::jScriptEnabled() const
00941 {
00942   if(onlyLocalReferences()) return false;
00943 
00944   if ( d->m_bJScriptOverride )
00945       return d->m_bJScriptForce;
00946   return d->m_bJScriptEnabled;
00947 }
00948 
00949 void KHTMLPart::setMetaRefreshEnabled( bool enable )
00950 {
00951   d->m_metaRefreshEnabled = enable;
00952 }
00953 
00954 bool KHTMLPart::metaRefreshEnabled() const
00955 {
00956   return d->m_metaRefreshEnabled;
00957 }
00958 
00959 // Define this to disable dlopening kjs_html, when directly linking to it.
00960 // You need to edit khtml/Makefile.am to add ./ecma/libkjs_html.la to LIBADD
00961 // and to edit khtml/ecma/Makefile.am to s/kjs_html/libkjs_html/, remove libkhtml from LIBADD,
00962 //        remove LDFLAGS line, and replace kde_module with either lib (shared) or noinst (static)
00963 //        Also, change the order of "ecma" and "." in khtml's SUBDIRS line.
00964 // OK - that's the default now, use the opposite of the above instructions to go back
00965 // to "dlopening it" - but it breaks exception catching in kjs_binding.cpp
00966 #define DIRECT_LINKAGE_TO_ECMA
00967 
00968 #ifdef DIRECT_LINKAGE_TO_ECMA
00969 extern "C" { KJSProxy *kjs_html_init(khtml::ChildFrame * childframe); }
00970 #endif
00971 
00972 static bool createJScript(khtml::ChildFrame *frame)
00973 {
00974 #ifndef DIRECT_LINKAGE_TO_ECMA
00975   KLibrary *lib = KLibLoader::self()->library("kjs_html");
00976   if ( !lib ) {
00977     setJScriptEnabled( false );
00978     return false;
00979   }
00980   // look for plain C init function
00981   void *sym = lib->symbol("kjs_html_init");
00982   if ( !sym ) {
00983     lib->unload();
00984     setJScriptEnabled( false );
00985     return false;
00986   }
00987   typedef KJSProxy* (*initFunction)(khtml::ChildFrame *);
00988   initFunction initSym = (initFunction) sym;
00989   frame->m_jscript = (*initSym)(d->m_frame);
00990   frame->m_kjs_lib = lib;
00991 #else
00992   frame->m_jscript = kjs_html_init(frame);
00993   // frame->m_kjs_lib remains 0L.
00994 #endif
00995   return true;
00996 }
00997 
00998 KJSProxy *KHTMLPart::jScript()
00999 {
01000   if (!jScriptEnabled()) return 0;
01001 
01002   if ( !d->m_frame ) {
01003       KHTMLPart * p = parentPart();
01004       if (!p) {
01005           d->m_frame = new khtml::ChildFrame;
01006           d->m_frame->m_part = this;
01007       } else {
01008           ConstFrameIt it = p->d->m_frames.begin();
01009           const ConstFrameIt end = p->d->m_frames.end();
01010           for (; it != end; ++it)
01011               if ((*it)->m_part.operator->() == this) {
01012                   d->m_frame = *it;
01013                   break;
01014               }
01015       }
01016       if ( !d->m_frame )
01017         return 0;
01018   }
01019   if ( !d->m_frame->m_jscript )
01020     if (!createJScript(d->m_frame))
01021       return 0;
01022   if (d->m_bJScriptDebugEnabled)
01023     d->m_frame->m_jscript->setDebugEnabled(true);
01024 
01025   return d->m_frame->m_jscript;
01026 }
01027 
01028 QVariant KHTMLPart::crossFrameExecuteScript(const QString& target,  const QString& script)
01029 {
01030   KHTMLPart* destpart = this;
01031 
01032   QString trg = target.lower();
01033 
01034   if (target == "_top") {
01035     while (destpart->parentPart())
01036       destpart = destpart->parentPart();
01037   }
01038   else if (target == "_parent") {
01039     if (parentPart())
01040       destpart = parentPart();
01041   }
01042   else if (target == "_self" || target == "_blank")  {
01043     // we always allow these
01044   }
01045   else {
01046     destpart = findFrame(target);
01047     if (!destpart)
01048        destpart = this;
01049   }
01050 
01051   // easy way out?
01052   if (destpart == this)
01053     return executeScript(DOM::Node(), script);
01054 
01055   // now compare the domains
01056   if (destpart->checkFrameAccess(this))
01057     return destpart->executeScript(DOM::Node(), script);
01058 
01059   // eww, something went wrong. better execute it in our frame
01060   return executeScript(DOM::Node(), script);
01061 }
01062 
01063 //Enable this to see all JS scripts being executed
01064 //#define KJS_VERBOSE
01065 
01066 KJSErrorDlg *KHTMLPart::jsErrorExtension() {
01067   if (!d->m_settings->jsErrorsEnabled()) {
01068     return 0L;
01069   }
01070 
01071   if (parentPart()) {
01072     return parentPart()->jsErrorExtension();
01073   }
01074 
01075   if (!d->m_statusBarJSErrorLabel) {
01076     d->m_statusBarJSErrorLabel = new KURLLabel(d->m_statusBarExtension->statusBar());
01077     d->m_statusBarJSErrorLabel->setFixedHeight(instance()->iconLoader()->currentSize(KIcon::Small));
01078     d->m_statusBarJSErrorLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
01079     d->m_statusBarJSErrorLabel->setUseCursor(false);
01080     d->m_statusBarExtension->addStatusBarItem(d->m_statusBarJSErrorLabel, 0, false);
01081     QToolTip::add(d->m_statusBarJSErrorLabel, i18n("This web page contains coding errors."));
01082     d->m_statusBarJSErrorLabel->setPixmap(SmallIcon("bug", instance()));
01083     connect(d->m_statusBarJSErrorLabel, SIGNAL(leftClickedURL()), SLOT(launchJSErrorDialog()));
01084     connect(d->m_statusBarJSErrorLabel, SIGNAL(rightClickedURL()), SLOT(jsErrorDialogContextMenu()));
01085   }
01086   if (!d->m_jsedlg) {
01087     d->m_jsedlg = new KJSErrorDlg;
01088     d->m_jsedlg->setURL(m_url.prettyURL());
01089     if (KGlobalSettings::showIconsOnPushButtons()) {
01090       d->m_jsedlg->_clear->setIconSet(SmallIconSet("locationbar_erase"));
01091       d->m_jsedlg->_close->setIconSet(SmallIconSet("fileclose"));
01092     }
01093   }
01094   return d->m_jsedlg;
01095 }
01096 
01097 void KHTMLPart::removeJSErrorExtension() {
01098   if (parentPart()) {
01099     parentPart()->removeJSErrorExtension();
01100     return;
01101   }
01102   if (d->m_statusBarJSErrorLabel != 0) {
01103     d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarJSErrorLabel );
01104     delete d->m_statusBarJSErrorLabel;
01105     d->m_statusBarJSErrorLabel = 0;
01106   }
01107   delete d->m_jsedlg;
01108   d->m_jsedlg = 0;
01109 }
01110 
01111 void KHTMLPart::disableJSErrorExtension() {
01112   removeJSErrorExtension();
01113   // These two lines are really kind of hacky, and it sucks to do this inside
01114   // KHTML but I don't know of anything that's reasonably easy as an alternative
01115   // right now.  It makes me wonder if there should be a more clean way to
01116   // contact all running "KHTML" instance as opposed to Konqueror instances too.
01117   d->m_settings->setJSErrorsEnabled(false);
01118   DCOPClient::mainClient()->send("konqueror*", "KonquerorIface", "reparseConfiguration()", QByteArray());
01119 }
01120 
01121 void KHTMLPart::jsErrorDialogContextMenu() {
01122   KPopupMenu *m = new KPopupMenu(0L);
01123   m->insertItem(i18n("&Hide Errors"), this, SLOT(removeJSErrorExtension()));
01124   m->insertItem(i18n("&Disable Error Reporting"), this, SLOT(disableJSErrorExtension()));
01125   m->popup(QCursor::pos());
01126 }
01127 
01128 void KHTMLPart::launchJSErrorDialog() {
01129   KJSErrorDlg *dlg = jsErrorExtension();
01130   if (dlg) {
01131     dlg->show();
01132     dlg->raise();
01133   }
01134 }
01135 
01136 void KHTMLPart::launchJSConfigDialog() {
01137   QStringList args;
01138   args << "khtml_java_js";
01139   KApplication::kdeinitExec( "kcmshell", args );
01140 }
01141 
01142 QVariant KHTMLPart::executeScript(const QString& filename, int baseLine, const DOM::Node& n, const QString& script)
01143 {
01144 #ifdef KJS_VERBOSE
01145   // The script is now printed by KJS's Parser::parse
01146   kdDebug(6070) << "executeScript: caller='" << name() << "' filename=" << filename << " baseLine=" << baseLine /*<< " script=" << script*/ << endl;
01147 #endif
01148   KJSProxy *proxy = jScript();
01149 
01150   if (!proxy || proxy->paused())
01151     return QVariant();
01152 
01153   KJS::Completion comp;
01154 
01155   QVariant ret = proxy->evaluate(filename, baseLine, script, n, &comp);
01156 
01157   /*
01158    *  Error handling
01159    */
01160   if (comp.complType() == KJS::Throw && !comp.value().isNull()) {
01161     KJSErrorDlg *dlg = jsErrorExtension();
01162     if (dlg) {
01163       KJS::UString msg = comp.value().toString(proxy->interpreter()->globalExec());
01164       dlg->addError(i18n("<b>Error</b>: %1: %2").arg(filename, msg.qstring()));
01165     }
01166   }
01167 
01168   // Handle immediate redirects now (e.g. location='foo')
01169   if ( !d->m_redirectURL.isEmpty() && d->m_delayRedirect == -1 )
01170   {
01171     kdDebug(6070) << "executeScript done, handling immediate redirection NOW" << endl;
01172     // Must abort tokenizer, no further script must execute.
01173     khtml::Tokenizer* t = d->m_doc->tokenizer();
01174     if(t)
01175       t->abort();
01176     d->m_redirectionTimer.start( 0, true );
01177   }
01178 
01179   return ret;
01180 }
01181 
01182 QVariant KHTMLPart::executeScript( const QString &script )
01183 {
01184     return executeScript( DOM::Node(), script );
01185 }
01186 
01187 QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script )
01188 {
01189 #ifdef KJS_VERBOSE
01190   kdDebug(6070) << "KHTMLPart::executeScript caller='" << name() << "' node=" << n.nodeName().string().latin1() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " /* << script */ << endl;
01191 #endif
01192   KJSProxy *proxy = jScript();
01193 
01194   if (!proxy || proxy->paused())
01195     return QVariant();
01196   ++(d->m_runningScripts);
01197   KJS::Completion comp;
01198   const QVariant ret = proxy->evaluate( QString::null, 1, script, n, &comp );
01199   --(d->m_runningScripts);
01200 
01201   /*
01202    *  Error handling
01203    */
01204   if (comp.complType() == KJS::Throw && !comp.value().isNull()) {
01205     KJSErrorDlg *dlg = jsErrorExtension();
01206     if (dlg) {
01207       KJS::UString msg = comp.value().toString(proxy->interpreter()->globalExec());
01208       dlg->addError(i18n("<b>Error</b>: node %1: %2").arg(n.nodeName().string()).arg(msg.qstring()));
01209     }
01210   }
01211 
01212   if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
01213       submitFormAgain();
01214 
01215 #ifdef KJS_VERBOSE
01216   kdDebug(6070) << "KHTMLPart::executeScript - done" << endl;
01217 #endif
01218   return ret;
01219 }
01220 
01221 bool KHTMLPart::scheduleScript(const DOM::Node &n, const QString& script)
01222 {
01223     //kdDebug(6050) << "KHTMLPart::scheduleScript "<< script << endl;
01224 
01225     d->scheduledScript = script;
01226     d->scheduledScriptNode = n;
01227 
01228     return true;
01229 }
01230 
01231 QVariant KHTMLPart::executeScheduledScript()
01232 {
01233   if( d->scheduledScript.isEmpty() )
01234     return QVariant();
01235 
01236   //kdDebug(6050) << "executing delayed " << d->scheduledScript << endl;
01237 
01238   QVariant ret = executeScript( d->scheduledScriptNode, d->scheduledScript );
01239   d->scheduledScript = QString();
01240   d->scheduledScriptNode = DOM::Node();
01241 
01242   return ret;
01243 }
01244 
01245 void KHTMLPart::setJavaEnabled( bool enable )
01246 {
01247   d->m_bJavaForce = enable;
01248   d->m_bJavaOverride = true;
01249 }
01250 
01251 bool KHTMLPart::javaEnabled() const
01252 {
01253   if (onlyLocalReferences()) return false;
01254 
01255 #ifndef Q_WS_QWS
01256   if( d->m_bJavaOverride )
01257       return d->m_bJavaForce;
01258   return d->m_bJavaEnabled;
01259 #else
01260   return false;
01261 #endif
01262 }
01263 
01264 KJavaAppletContext *KHTMLPart::javaContext()
01265 {
01266   return 0;
01267 }
01268 
01269 KJavaAppletContext *KHTMLPart::createJavaContext()
01270 {
01271   return 0;
01272 }
01273 
01274 void KHTMLPart::setPluginsEnabled( bool enable )
01275 {
01276   d->m_bPluginsForce = enable;
01277   d->m_bPluginsOverride = true;
01278 }
01279 
01280 bool KHTMLPart::pluginsEnabled() const
01281 {
01282   if (onlyLocalReferences()) return false;
01283 
01284   if ( d->m_bPluginsOverride )
01285       return d->m_bPluginsForce;
01286   return d->m_bPluginsEnabled;
01287 }
01288 
01289 static int s_DOMTreeIndentLevel = 0;
01290 
01291 void KHTMLPart::slotDebugDOMTree()
01292 {
01293   if ( d->m_doc && d->m_doc->firstChild() )
01294     qDebug("%s", d->m_doc->firstChild()->toString().string().latin1());
01295 
01296   // Now print the contents of the frames that contain HTML
01297 
01298   const int indentLevel = s_DOMTreeIndentLevel++;
01299 
01300   ConstFrameIt it = d->m_frames.begin();
01301   const ConstFrameIt end = d->m_frames.end();
01302   for (; it != end; ++it )
01303     if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
01304       KParts::ReadOnlyPart* const p = ( *it )->m_part;
01305       kdDebug(6050) << QString().leftJustify(s_DOMTreeIndentLevel*4,' ') << "FRAME " << p->name() << " " << endl;
01306       static_cast<KHTMLPart*>( p )->slotDebugDOMTree();
01307     }
01308   s_DOMTreeIndentLevel = indentLevel;
01309 }
01310 
01311 void KHTMLPart::slotDebugScript()
01312 {
01313   if (jScript())
01314     jScript()->showDebugWindow();
01315 }
01316 
01317 void KHTMLPart::slotDebugRenderTree()
01318 {
01319 #ifndef NDEBUG
01320   if ( d->m_doc ) {
01321     d->m_doc->renderer()->printTree();
01322     // dump out the contents of the rendering & DOM trees
01323 //    QString dumps;
01324 //    QTextStream outputStream(dumps,IO_WriteOnly);
01325 //    d->m_doc->renderer()->layer()->dump( outputStream );
01326 //    kdDebug() << "dump output:" << "\n" + dumps;
01327   }
01328 #endif
01329 }
01330 
01331 void KHTMLPart::slotStopAnimations()
01332 {
01333   stopAnimations();
01334 }
01335 
01336 void KHTMLPart::setAutoloadImages( bool enable )
01337 {
01338   if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
01339     return;
01340 
01341   if ( d->m_doc )
01342     d->m_doc->docLoader()->setAutoloadImages( enable );
01343 
01344   unplugActionList( "loadImages" );
01345 
01346   if ( enable ) {
01347     delete d->m_paLoadImages;
01348     d->m_paLoadImages = 0;
01349   }
01350   else if ( !d->m_paLoadImages )
01351     d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), "images_display", 0, this, SLOT( slotLoadImages() ), actionCollection(), "loadImages" );
01352 
01353   if ( d->m_paLoadImages ) {
01354     QPtrList<KAction> lst;
01355     lst.append( d->m_paLoadImages );
01356     plugActionList( "loadImages", lst );
01357   }
01358 }
01359 
01360 bool KHTMLPart::autoloadImages() const
01361 {
01362   if ( d->m_doc )
01363     return d->m_doc->docLoader()->autoloadImages();
01364 
01365   return true;
01366 }
01367 
01368 void KHTMLPart::clear()
01369 {
01370   if ( d->m_bCleared )
01371     return;
01372 
01373   d->m_bCleared = true;
01374 
01375   d->m_bClearing = true;
01376 
01377   {
01378     ConstFrameIt it = d->m_frames.begin();
01379     const ConstFrameIt end = d->m_frames.end();
01380     for(; it != end; ++it )
01381     {
01382       // Stop HTMLRun jobs for frames
01383       if ( (*it)->m_run )
01384         (*it)->m_run->abort();
01385     }
01386   }
01387 
01388   {
01389     ConstFrameIt it = d->m_objects.begin();
01390     const ConstFrameIt end = d->m_objects.end();
01391     for(; it != end; ++it )
01392     {
01393       // Stop HTMLRun jobs for objects
01394       if ( (*it)->m_run )
01395         (*it)->m_run->abort();
01396     }
01397   }
01398 
01399 
01400   findTextBegin(); // resets d->m_findNode and d->m_findPos
01401   d->m_mousePressNode = DOM::Node();
01402 
01403 
01404   if ( d->m_doc )
01405   {
01406     if (d->m_doc->attached()) //the view may have detached it already
01407     d->m_doc->detach();
01408   }
01409 
01410   // Moving past doc so that onUnload works.
01411   if ( d->m_frame && d->m_frame->m_jscript )
01412     d->m_frame->m_jscript->clear();
01413 
01414   // stopping marquees
01415   if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->layer())
01416       d->m_doc->renderer()->layer()->suspendMarquees();
01417 
01418   if ( d->m_view )
01419     d->m_view->clear();
01420 
01421   // do not dereference the document before the jscript and view are cleared, as some destructors
01422   // might still try to access the document.
01423   if ( d->m_doc ) {
01424     d->m_doc->deref();
01425   }
01426   d->m_doc = 0;
01427 
01428   delete d->m_decoder;
01429   d->m_decoder = 0;
01430 
01431   // We don't want to change between parts if we are going to delete all of them anyway
01432   disconnect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ),
01433                this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
01434 
01435   if (d->m_frames.count())
01436   {
01437     KHTMLFrameList frames = d->m_frames;
01438     d->m_frames.clear();
01439     ConstFrameIt it = frames.begin();
01440     const ConstFrameIt end = frames.end();
01441     for(; it != end; ++it )
01442     {
01443       if ( (*it)->m_part )
01444       {
01445         partManager()->removePart( (*it)->m_part );
01446         delete (KParts::ReadOnlyPart *)(*it)->m_part;
01447       }
01448       delete *it;
01449     }
01450   }
01451   d->m_suppressedPopupOriginParts.clear();
01452 
01453   if (d->m_objects.count())
01454   {
01455     KHTMLFrameList objects = d->m_objects;
01456     d->m_objects.clear();
01457     ConstFrameIt oi = objects.begin();
01458     const ConstFrameIt oiEnd = objects.end();
01459 
01460     for (; oi != oiEnd; ++oi )
01461       delete *oi;
01462   }
01463 
01464   // Listen to part changes again
01465   connect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ),
01466              this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
01467 
01468   d->m_delayRedirect = 0;
01469   d->m_redirectURL = QString::null;
01470   d->m_redirectionTimer.stop();
01471   d->m_redirectLockHistory = true;
01472   d->m_bClearing = false;
01473   d->m_frameNameId = 1;
01474   d->m_bFirstData = true;
01475 
01476   d->m_bMousePressed = false;
01477 
01478   d->m_selectionStart = DOM::Node();
01479   d->m_selectionEnd = DOM::Node();
01480   d->m_startOffset = 0;
01481   d->m_endOffset = 0;
01482 #ifndef QT_NO_CLIPBOARD
01483   connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
01484 #endif
01485 
01486   d->m_jobPercent = 0;
01487 
01488   if ( !d->m_haveEncoding )
01489     d->m_encoding = QString::null;
01490 #ifdef SPEED_DEBUG
01491   d->m_parsetime.restart();
01492 #endif
01493 }
01494 
01495 bool KHTMLPart::openFile()
01496 {
01497   return true;
01498 }
01499 
01500 DOM::HTMLDocumentImpl *KHTMLPart::docImpl() const
01501 {
01502     if ( d && d->m_doc && d->m_doc->isHTMLDocument() )
01503         return static_cast<HTMLDocumentImpl*>(d->m_doc);
01504     return 0;
01505 }
01506 
01507 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
01508 {
01509     if ( d )
01510         return d->m_doc;
01511     return 0;
01512 }
01513 
01514 void KHTMLPart::slotInfoMessage(KIO::Job* kio_job, const QString& msg)
01515 {
01516   assert(d->m_job == kio_job);
01517 
01518   if (!parentPart())
01519     setStatusBarText(msg, BarDefaultText);
01520 }
01521 
01522 void KHTMLPart::setPageSecurity( PageSecurity sec )
01523 {
01524   emit d->m_extension->setPageSecurity( sec );
01525   if ( sec != NotCrypted && !d->m_statusBarIconLabel && !parentPart() ) {
01526     d->m_statusBarIconLabel = new KURLLabel( d->m_statusBarExtension->statusBar() );
01527     d->m_statusBarIconLabel->setFixedHeight( instance()->iconLoader()->currentSize(KIcon::Small) );
01528     d->m_statusBarIconLabel->setSizePolicy(QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ));
01529     d->m_statusBarIconLabel->setUseCursor( false );
01530     d->m_statusBarExtension->addStatusBarItem( d->m_statusBarIconLabel, 0, false );
01531     connect( d->m_statusBarIconLabel, SIGNAL( leftClickedURL() ), SLOT( slotSecurity() ) );
01532   } else if (d->m_statusBarIconLabel) {
01533     QToolTip::remove(d->m_statusBarIconLabel);
01534   }
01535 
01536   if (d->m_statusBarIconLabel) {
01537     if (d->m_ssl_in_use)
01538       QToolTip::add(d->m_statusBarIconLabel,
01539             i18n("Session is secured with %1 bit %2.").arg(d->m_ssl_cipher_used_bits).arg(d->m_ssl_cipher));
01540     else QToolTip::add(d->m_statusBarIconLabel, i18n("Session is not secured."));
01541   }
01542 
01543   QString iconName;
01544   switch (sec)  {
01545   case NotCrypted:
01546     iconName = "decrypted";
01547     if ( d->m_statusBarIconLabel )  {
01548       d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarIconLabel );
01549       delete d->m_statusBarIconLabel;
01550       d->m_statusBarIconLabel = 0L;
01551     }
01552     break;
01553   case Encrypted:
01554     iconName = "encrypted";
01555     break;
01556   case Mixed:
01557     iconName = "halfencrypted";
01558     break;
01559   }
01560   d->m_paSecurity->setIcon( iconName );
01561   if ( d->m_statusBarIconLabel )
01562     d->m_statusBarIconLabel->setPixmap( SmallIcon( iconName, instance() ) );
01563 }
01564 
01565 void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
01566 {
01567   assert ( d->m_job == kio_job );
01568 
01569   //kdDebug( 6050 ) << "slotData: " << data.size() << endl;
01570   // The first data ?
01571   if ( !d->m_workingURL.isEmpty() )
01572   {
01573       //kdDebug( 6050 ) << "begin!" << endl;
01574 
01575     // We must suspend KIO while we're inside begin() because it can cause
01576     // crashes if a window (such as kjsdebugger) goes back into the event loop,
01577     // more data arrives, and begin() gets called again (re-entered).
01578     d->m_job->suspend();
01579     begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
01580     d->m_job->resume();
01581 
01582     if (d->m_cachePolicy == KIO::CC_Refresh)
01583       d->m_doc->docLoader()->setCachePolicy(KIO::CC_Verify);
01584     else
01585       d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
01586 
01587     d->m_workingURL = KURL();
01588 
01589     d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
01590 
01591     // When the first data arrives, the metadata has just been made available
01592     d->m_httpHeaders = d->m_job->queryMetaData("HTTP-Headers");
01593     time_t cacheCreationDate =  d->m_job->queryMetaData("cache-creation-date").toLong();
01594     d->m_doc->docLoader()->setCacheCreationDate(cacheCreationDate);
01595 
01596     d->m_pageServices = d->m_job->queryMetaData("PageServices");
01597     d->m_pageReferrer = d->m_job->queryMetaData("referrer");
01598 
01599     d->m_bSecurityInQuestion = false;
01600     d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
01601 
01602     {
01603     KHTMLPart *p = parentPart();
01604     if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
01605     while (p->parentPart()) p = p->parentPart();
01606 
01607         p->setPageSecurity( Mixed );
01608         p->d->m_bSecurityInQuestion = true;
01609     }
01610     }
01611 
01612     setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
01613 
01614     // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
01615     d->m_ssl_parent_ip = d->m_job->queryMetaData("ssl_parent_ip");
01616     d->m_ssl_parent_cert = d->m_job->queryMetaData("ssl_parent_cert");
01617     d->m_ssl_peer_certificate = d->m_job->queryMetaData("ssl_peer_certificate");
01618     d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
01619     d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
01620     d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
01621     d->m_ssl_cipher_desc = d->m_job->queryMetaData("ssl_cipher_desc");
01622     d->m_ssl_cipher_version = d->m_job->queryMetaData("ssl_cipher_version");
01623     d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
01624     d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
01625     d->m_ssl_cert_state = d->m_job->queryMetaData("ssl_cert_state");
01626 
01627     if (d->m_statusBarIconLabel) {
01628       QToolTip::remove(d->m_statusBarIconLabel);
01629       if (d->m_ssl_in_use) {
01630         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));
01631       } else {
01632         QToolTip::add(d->m_statusBarIconLabel, i18n("Session is not secured."));
01633       }
01634     }
01635 
01636     // Check for charset meta-data
01637     QString qData = d->m_job->queryMetaData("charset");
01638     if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
01639        d->m_encoding = qData;
01640 
01641     // Support for http-refresh
01642     qData = d->m_job->queryMetaData("http-refresh");
01643     if( !qData.isEmpty())
01644       d->m_doc->processHttpEquiv("refresh", qData);
01645 
01646     // DISABLED: Support Content-Location per section 14.14 of RFC 2616.
01647     // See BR# 51185,BR# 82747
01648     /*
01649     QString baseURL = d->m_job->queryMetaData ("content-location");
01650     if (!baseURL.isEmpty())
01651       d->m_doc->setBaseURL(KURL( d->m_doc->completeURL(baseURL) ));
01652     */
01653 
01654     if ( !m_url.isLocalFile() ) {
01655         // Support for http last-modified
01656         d->m_lastModified = d->m_job->queryMetaData("modified");
01657     } else
01658         d->m_lastModified = QString::null; // done on-demand by lastModified()
01659   }
01660 
01661   KHTMLPageCache::self()->addData(d->m_cacheId, data);
01662   write( data.data(), data.size() );
01663   if (d->m_frame && d->m_frame->m_jscript)
01664     d->m_frame->m_jscript->dataReceived();
01665 }
01666 
01667 void KHTMLPart::slotRestoreData(const QByteArray &data )
01668 {
01669   // The first data ?
01670   if ( !d->m_workingURL.isEmpty() )
01671   {
01672      long saveCacheId = d->m_cacheId;
01673      QString savePageReferrer = d->m_pageReferrer;
01674      QString saveEncoding     = d->m_encoding;
01675      begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
01676      d->m_encoding     = saveEncoding;
01677      d->m_pageReferrer = savePageReferrer;
01678      d->m_cacheId = saveCacheId;
01679      d->m_workingURL = KURL();
01680   }
01681 
01682   //kdDebug( 6050 ) << "slotRestoreData: " << data.size() << endl;
01683   write( data.data(), data.size() );
01684 
01685   if (data.size() == 0)
01686   {
01687       //kdDebug( 6050 ) << "slotRestoreData: <<end of data>>" << endl;
01688      // End of data.
01689     if (d->m_doc && d->m_doc->parsing())
01690         end(); //will emit completed()
01691   }
01692 }
01693 
01694 void KHTMLPart::showError( KIO::Job* job )
01695 {
01696   kdDebug(6050) << "KHTMLPart::showError d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
01697                 << " d->m_bCleared=" << d->m_bCleared << endl;
01698 
01699   if (job->error() == KIO::ERR_NO_CONTENT)
01700     return;
01701 
01702   if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
01703     job->showErrorDialog( /*d->m_view*/ );
01704   else
01705   {
01706     htmlError( job->error(), job->errorText(), d->m_workingURL );
01707   }
01708 }
01709 
01710 // This is a protected method, placed here because of it's relevance to showError
01711 void KHTMLPart::htmlError( int errorCode, const QString& text, const KURL& reqUrl )
01712 {
01713   kdDebug(6050) << "KHTMLPart::htmlError errorCode=" << errorCode << " text=" << text << endl;
01714   // make sure we're not executing any embedded JS
01715   bool bJSFO = d->m_bJScriptForce;
01716   bool bJSOO = d->m_bJScriptOverride;
01717   d->m_bJScriptForce = false;
01718   d->m_bJScriptOverride = true;
01719   begin();
01720   QString errText = QString::fromLatin1( "<HTML dir=%1><HEAD><TITLE>" )
01721                            .arg(QApplication::reverseLayout() ? "rtl" : "ltr");
01722   errText += i18n( "Error while loading %1" ).arg( reqUrl.htmlURL() );
01723   errText += QString::fromLatin1( "</TITLE></HEAD><BODY><P>" );
01724   errText += i18n( "An error occurred while loading <B>%1</B>:" ).arg( reqUrl.htmlURL() );
01725   errText += QString::fromLatin1( "</P>" );
01726   errText += QStyleSheet::convertFromPlainText( KIO::buildErrorString( errorCode, text ) );
01727   errText += QString::fromLatin1( "</BODY></HTML>" );
01728   write(errText);
01729   end();
01730 
01731   d->m_bJScriptForce = bJSFO;
01732   d->m_bJScriptOverride = bJSOO;
01733 
01734   // make the working url the current url, so that reload works and
01735   // emit the progress signals to advance one step in the history
01736   // (so that 'back' works)
01737   m_url = reqUrl; // same as d->m_workingURL
01738   d->m_workingURL = KURL();
01739   emit started( 0 );
01740   emit completed();
01741   return;
01742   // following disabled until 3.1
01743 
01744   QString errorName, techName, description;
01745   QStringList causes, solutions;
01746 
01747   QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
01748   QDataStream stream(raw, IO_ReadOnly);
01749 
01750   stream >> errorName >> techName >> description >> causes >> solutions;
01751 
01752   QString url, protocol, datetime;
01753   url = reqUrl.prettyURL();
01754   protocol = reqUrl.protocol();
01755   datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
01756                                                 false );
01757 
01758   QString doc = QString::fromLatin1( "<html><head><title>" );
01759   doc += i18n( "Error: " );
01760   doc += errorName;
01761   doc += QString::fromLatin1( " - %1</title></head><body><h1>" ).arg( url );
01762   doc += i18n( "The requested operation could not be completed" );
01763   doc += QString::fromLatin1( "</h1><h2>" );
01764   doc += errorName;
01765   doc += QString::fromLatin1( "</h2>" );
01766   if ( !techName.isNull() ) {
01767     doc += QString::fromLatin1( "<h2>" );
01768     doc += i18n( "Technical Reason: " );
01769     doc += techName;
01770     doc += QString::fromLatin1( "</h2>" );
01771   }
01772   doc += QString::fromLatin1( "<h3>" );
01773   doc += i18n( "Details of the Request:" );
01774   doc += QString::fromLatin1( "</h3><ul><li>" );
01775   doc += i18n( "URL: %1" ).arg( url );
01776   doc += QString::fromLatin1( "</li><li>" );
01777   if ( !protocol.isNull() ) {
01778     // uncomment for 3.1... i18n change
01779     // doc += i18n( "Protocol: %1" ).arg( protocol ).arg( protocol );
01780     doc += QString::fromLatin1( "</li><li>" );
01781   }
01782   doc += i18n( "Date and Time: %1" ).arg( datetime );
01783   doc += QString::fromLatin1( "</li><li>" );
01784   doc += i18n( "Additional Information: %1" ).arg( text );
01785   doc += QString::fromLatin1( "</li></ul><h3>" );
01786   doc += i18n( "Description:" );
01787   doc += QString::fromLatin1( "</h3><p>" );
01788   doc += description;
01789   doc += QString::fromLatin1( "</p>" );
01790   if ( causes.count() ) {
01791     doc += QString::fromLatin1( "<h3>" );
01792     doc += i18n( "Possible Causes:" );
01793     doc += QString::fromLatin1( "</h3><ul><li>" );
01794     doc += causes.join( "</li><li>" );
01795     doc += QString::fromLatin1( "</li></ul>" );
01796   }
01797   if ( solutions.count() ) {
01798     doc += QString::fromLatin1( "<h3>" );
01799     doc += i18n( "Possible Solutions:" );
01800     doc += QString::fromLatin1( "</h3><ul><li>" );
01801     doc += solutions.join( "</li><li>" );
01802     doc += QString::fromLatin1( "</li></ul>" );
01803   }
01804   doc += QString::fromLatin1( "</body></html>" );
01805 
01806   write( doc );
01807   end();
01808 }
01809 
01810 void KHTMLPart::slotFinished( KIO::Job * job )
01811 {
01812   d->m_job = 0L;
01813   d->m_jobspeed = 0L;
01814 
01815   if (job->error())
01816   {
01817     KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
01818 
01819     // The following catches errors that occur as a result of HTTP
01820     // to FTP redirections where the FTP URL is a directory. Since
01821     // KIO cannot change a redirection request from GET to LISTDIR,
01822     // we have to take care of it here once we know for sure it is
01823     // a directory...
01824     if (job->error() == KIO::ERR_IS_DIRECTORY)
01825     {
01826       KParts::URLArgs args;
01827       emit d->m_extension->openURLRequest( d->m_workingURL, args );
01828     }
01829     else
01830     {
01831       emit canceled( job->errorString() );
01832       // TODO: what else ?
01833       checkCompleted();
01834       showError( job );
01835     }
01836 
01837     return;
01838   }
01839   KIO::TransferJob *tjob = ::qt_cast<KIO::TransferJob*>(job);
01840   if (tjob && tjob->isErrorPage()) {
01841     khtml::RenderPart *renderPart = d->m_frame->m_frame;
01842     if (renderPart) {
01843       HTMLObjectElementImpl* elt = static_cast<HTMLObjectElementImpl *>(renderPart->element());
01844       if (!elt)
01845         return;
01846       elt->renderAlternative();
01847       checkCompleted();
01848      }
01849      if (d->m_bComplete) return;
01850   }
01851 
01852   //kdDebug( 6050 ) << "slotFinished" << endl;
01853 
01854   KHTMLPageCache::self()->endData(d->m_cacheId);
01855   if (d->m_frame && d->m_frame->m_jscript)
01856     d->m_frame->m_jscript->dataReceived();
01857 
01858   if ( d->m_doc && d->m_doc->docLoader()->expireDate() && m_url.protocol().lower().startsWith("http"))
01859       KIO::http_update_cache(m_url, false, d->m_doc->docLoader()->expireDate());
01860 
01861   d->m_workingURL = KURL();
01862 
01863   if ( d->m_doc && d->m_doc->parsing())
01864     end(); //will emit completed()
01865 }
01866 
01867 void KHTMLPart::begin( const KURL &url, int xOffset, int yOffset )
01868 {
01869   // No need to show this for a new page until an error is triggered
01870   if (!parentPart()) {
01871     removeJSErrorExtension();
01872     setSuppressedPopupIndicator( false );
01873     d->m_openableSuppressedPopups = 0;
01874     for ( KHTMLPart* part = d->m_suppressedPopupOriginParts.first(); part; part = d->m_suppressedPopupOriginParts.next() ) {
01875        KJS::Window *w = KJS::Window::retrieveWindow( part );
01876        if (w)
01877            w->forgetSuppressedWindows();
01878     }
01879   }
01880 
01881   clear();
01882   d->m_bCleared = false;
01883   d->m_cacheId = 0;
01884   d->m_bComplete = false;
01885   d->m_bLoadEventEmitted = false;
01886 
01887   if(url.isValid()) {
01888       QString urlString = url.url();
01889       KHTMLFactory::vLinks()->insert( urlString );
01890       QString urlString2 = url.prettyURL();
01891       if ( urlString != urlString2 ) {
01892           KHTMLFactory::vLinks()->insert( urlString2 );
01893       }
01894   }
01895 
01896 
01897   // ###
01898   //stopParser();
01899 
01900   KParts::URLArgs args( d->m_extension->urlArgs() );
01901   args.xOffset = xOffset;
01902   args.yOffset = yOffset;
01903   d->m_extension->setURLArgs( args );
01904 
01905   d->m_pageReferrer = QString::null;
01906 
01907   KURL ref(url);
01908   d->m_referrer = ref.protocol().startsWith("http") ? ref.url() : "";
01909 
01910   m_url = url;
01911 
01912   bool servedAsXHTML = args.serviceType == "application/xhtml+xml";
01913   bool servedAsXML = KMimeType::mimeType(args.serviceType)->is( "text/xml" );
01914   // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl
01915   if ( servedAsXML && !servedAsXHTML ) { // any XML derivative, except XHTML
01916     d->m_doc = DOMImplementationImpl::instance()->createDocument( d->m_view );
01917   } else {
01918     d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
01919     // HTML or XHTML? (#86446)
01920     static_cast<HTMLDocumentImpl *>(d->m_doc)->setHTMLRequested( !servedAsXHTML );
01921   }
01922 #ifndef KHTML_NO_CARET
01923 //  d->m_view->initCaret();
01924 #endif
01925 
01926   d->m_doc->ref();
01927   d->m_doc->setURL( m_url.url() );
01928   if (!d->m_doc->attached())
01929     d->m_doc->attach( );
01930   d->m_doc->setBaseURL( KURL() );
01931   d->m_doc->docLoader()->setShowAnimations( KHTMLFactory::defaultHTMLSettings()->showAnimations() );
01932   emit docCreated();
01933 
01934   d->m_paUseStylesheet->setItems(QStringList());
01935   d->m_paUseStylesheet->setEnabled( false );
01936 
01937   setAutoloadImages( KHTMLFactory::defaultHTMLSettings()->autoLoadImages() );
01938   QString userStyleSheet = KHTMLFactory::defaultHTMLSettings()->userStyleSheet();
01939   if ( !userStyleSheet.isEmpty() )
01940     setUserStyleSheet( KURL( userStyleSheet ) );
01941 
01942   d->m_doc->setRestoreState(args.docState);
01943   d->m_doc->open();
01944   connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
01945 
01946   emit d->m_extension->enableAction( "print", true );
01947 
01948   d->m_doc->setParsing(true);
01949 }
01950 
01951 void KHTMLPart::write( const char *str, int len )
01952 {
01953   if ( !d->m_decoder )
01954     d->m_decoder = createDecoder();
01955 
01956   if ( len == -1 )
01957     len = strlen( str );
01958 
01959   if ( len == 0 )
01960     return;
01961 
01962   QString decoded = d->m_decoder->decode( str, len );
01963 
01964   if(decoded.isEmpty()) return;
01965 
01966   if(d->m_bFirstData) {
01967       // determine the parse mode
01968       d->m_doc->determineParseMode( decoded );
01969       d->m_bFirstData = false;
01970 
01971   //kdDebug(6050) << "KHTMLPart::write haveEnc = " << d->m_haveEncoding << endl;
01972       // ### this is still quite hacky, but should work a lot better than the old solution
01973       if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
01974       d->m_doc->setDecoderCodec(d->m_decoder->codec());
01975       d->m_doc->recalcStyle( NodeImpl::Force );
01976   }
01977 
01978   khtml::Tokenizer* t = d->m_doc->tokenizer();
01979   if(t)
01980     t->write( decoded, true );
01981 }
01982 
01983 void KHTMLPart::write( const QString &str )
01984 {
01985   if ( str.isNull() )
01986     return;
01987 
01988   if(d->m_bFirstData) {
01989       // determine the parse mode
01990       d->m_doc->setParseMode( DocumentImpl::Strict );
01991       d->m_bFirstData = false;
01992   }
01993   khtml::Tokenizer* t = d->m_doc->tokenizer();
01994   if(t)
01995     t->write( str, true );
01996 }
01997 
01998 void KHTMLPart::end()
01999 {
02000     // make sure nothing's left in there...
02001     if(d->m_decoder)
02002         write(d->m_decoder->flush());
02003     if (d->m_doc)
02004         d->m_doc->finishParsing();
02005 }
02006 
02007 bool KHTMLPart::doOpenStream( const QString& mimeType )
02008 {
02009     KMimeType::Ptr mime = KMimeType::mimeType(mimeType);
02010     if ( mime->is( "text/html" ) || mime->is( "text/xml" ) )
02011     {
02012         begin( url() );
02013         return true;
02014     }
02015     return false;
02016 }
02017 
02018 bool KHTMLPart::doWriteStream( const QByteArray& data )
02019 {
02020     write( data.data(), data.size() );
02021     return true;
02022 }
02023 
02024 bool KHTMLPart::doCloseStream()
02025 {
02026     end();
02027     return true;
02028 }
02029 
02030 
02031 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
02032 {
02033     if (!d->m_view) return;
02034     d->m_view->paint(p, rc, yOff, more);
02035 }
02036 
02037 void KHTMLPart::stopAnimations()
02038 {
02039   if ( d->m_doc )
02040     d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
02041 
02042   ConstFrameIt it = d->m_frames.begin();
02043   const ConstFrameIt end = d->m_frames.end();
02044   for (; it != end; ++it )
02045     if ( !(*it)->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
02046       KParts::ReadOnlyPart* const p = ( *it )->m_part;
02047       static_cast<KHTMLPart*>( p )->stopAnimations();
02048     }
02049 }
02050 
02051 void KHTMLPart::resetFromScript()
02052 {
02053     closeURL();
02054     d->m_bComplete = false;
02055     d->m_bLoadEventEmitted = false;
02056     disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
02057     connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
02058     d->m_doc->setParsing(true);
02059 
02060     emit started( 0L );
02061 }
02062 
02063 void KHTMLPart::slotFinishedParsing()
02064 {
02065   d->m_doc->setParsing(false);
02066   checkEmitLoadEvent();
02067   disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
02068 
02069   if (!d->m_view)
02070     return; // We are probably being destructed.
02071 
02072   checkCompleted();
02073 }
02074 
02075 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
02076 {
02077   if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
02078     KHTMLPart* p = this;
02079     while ( p ) {
02080       KHTMLPart* const op = p;
02081       ++(p->d->m_totalObjectCount);
02082       p = p->parentPart();
02083       if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount
02084         && !op->d->m_progressUpdateTimer.isActive())
02085     op->d->m_progressUpdateTimer.start( 200, true );
02086     }
02087   }
02088 }
02089 
02090 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
02091 {
02092   if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
02093     KHTMLPart* p = this;
02094     while ( p ) {
02095       KHTMLPart* const op = p;
02096       ++(p->d->m_loadedObjects);
02097       p = p->parentPart();
02098       if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount && op->d->m_jobPercent <= 100
02099         && !op->d->m_progressUpdateTimer.isActive())
02100     op->d->m_progressUpdateTimer.start( 200, true );
02101     }
02102   }
02103 
02104   checkCompleted();
02105 }
02106 
02107 void KHTMLPart::slotProgressUpdate()
02108 {
02109   int percent;
02110   if ( d->m_loadedObjects < d->m_totalObjectCount )
02111     percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
02112   else
02113     percent = d->m_jobPercent;
02114 
02115   if( d->m_bComplete )
02116     percent = 100;
02117 
02118   if (d->m_statusMessagesEnabled) {
02119     if( d->m_bComplete )
02120       emit d->m_extension->infoMessage( i18n( "Page loaded." ));
02121     else if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
02122       emit d->m_extension->infoMessage( i18n( "%n Image of %1 loaded.", "%n Images of %1 loaded.", d->m_loadedObjects).arg(d->m_totalObjectCount) );
02123   }
02124 
02125   emit d->m_extension->loadingProgress( percent );
02126 }
02127 
02128 void KHTMLPart::slotJobSpeed( KIO::Job* /*job*/, unsigned long speed )
02129 {
02130   d->m_jobspeed = speed;
02131   if (!parentPart())
02132     setStatusBarText(jsStatusBarText(), BarOverrideText);
02133 }
02134 
02135 void KHTMLPart::slotJobPercent( KIO::Job* /*job*/, unsigned long percent )
02136 {
02137   d->m_jobPercent = percent;
02138 
02139   if ( !parentPart() )
02140     d->m_progressUpdateTimer.start( 0, true );
02141 }
02142 
02143 void KHTMLPart::slotJobDone( KIO::Job* /*job*/ )
02144 {
02145   d->m_jobPercent = 100;
02146 
02147   if ( !parentPart() )
02148     d->m_progressUpdateTimer.start( 0, true );
02149 }
02150 
02151 void KHTMLPart::slotUserSheetStatDone( KIO::Job *_job )
02152 {
02153   using namespace KIO;
02154 
02155   if ( _job->error() ) {
02156     showError( _job );
02157     return;
02158   }
02159 
02160   const UDSEntry entry = dynamic_cast<KIO::StatJob *>( _job )->statResult();
02161   UDSEntry::ConstIterator it = entry.begin();
02162   const UDSEntry::ConstIterator end = entry.end();
02163   for ( ; it != end; ++it ) {
02164     if ( ( *it ).m_uds == UDS_MODIFICATION_TIME ) {
02165      break;
02166     }
02167   }
02168 
02169   // If the filesystem supports modification times, only reload the
02170   // user-defined stylesheet if necessary - otherwise always reload.
02171   if ( it != end ) {
02172     const time_t lastModified = static_cast<time_t>( ( *it ).m_long );
02173     if ( d->m_userStyleSheetLastModified >= lastModified ) {
02174       return;
02175     }
02176     d->m_userStyleSheetLastModified = lastModified;
02177   }
02178 
02179   setUserStyleSheet( KURL( settings()->userStyleSheet() ) );
02180 }
02181 
02182 void KHTMLPart::checkCompleted()
02183 {
02184 //   kdDebug( 6050 ) << "KHTMLPart::checkCompleted() " << this << " " << name() << endl;
02185 //   kdDebug( 6050 ) << "                           parsing: " << (d->m_doc && d->m_doc->parsing()) << endl;
02186 //   kdDebug( 6050 ) << "                           complete: " << d->m_bComplete << endl;
02187 
02188   // restore the cursor position
02189   if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
02190   {
02191       if (d->m_focusNodeNumber >= 0)
02192           d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
02193 
02194       d->m_focusNodeRestored = true;
02195   }
02196 
02197   bool bPendingChildRedirection = false;
02198   // Any frame that hasn't completed yet ?
02199   ConstFrameIt it = d->m_frames.begin();
02200   const ConstFrameIt end = d->m_frames.end();
02201   for (; it != end; ++it ) {
02202     if ( !(*it)->m_bCompleted )
02203     {
02204       //kdDebug( 6050 ) << this << " is waiting for " << (*it)->m_part << endl;
02205       return;
02206     }
02207     // Check for frames with pending redirections
02208     if ( (*it)->m_bPendingRedirection )
02209       bPendingChildRedirection = true;
02210   }
02211 
02212   // Any object that hasn't completed yet ?
02213   {
02214     ConstFrameIt oi = d->m_objects.begin();
02215     const ConstFrameIt oiEnd = d->m_objects.end();
02216 
02217     for (; oi != oiEnd; ++oi )
02218       if ( !(*oi)->m_bCompleted )
02219         return;
02220   }
02221   // Are we still parsing - or have we done the completed stuff already ?
02222   if ( d->m_bComplete || (d->m_doc && d->m_doc->parsing()) )
02223     return;
02224 
02225   // Still waiting for images/scripts from the loader ?
02226   int requests = 0;
02227   if ( d->m_doc && d->m_doc->docLoader() )
02228     requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
02229 
02230   if ( requests > 0 )
02231   {
02232     //kdDebug(6050) << "still waiting for images/scripts from the loader - requests:" << requests << endl;
02233     return;
02234   }
02235 
02236   // OK, completed.
02237   // Now do what should be done when we are really completed.
02238   d->m_bComplete = true;
02239   d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
02240   d->m_totalObjectCount = 0;
02241   d->m_loadedObjects = 0;
02242 
02243   KHTMLPart* p = this;
02244   while ( p ) {
02245     KHTMLPart* op = p;
02246     p = p->parentPart();
02247     if ( !p && !op->d->m_progressUpdateTimer.isActive())
02248       op->d->m_progressUpdateTimer.start( 0, true );
02249   }
02250 
02251   checkEmitLoadEvent(); // if we didn't do it before
02252 
02253   bool pendingAction = false;
02254 
02255   if ( !d->m_redirectURL.isEmpty() )
02256   {
02257     // DA: Do not start redirection for frames here! That action is
02258     // deferred until the parent emits a completed signal.
02259     if ( parentPart() == 0 ) {
02260       //kdDebug(6050) << this << " starting redirection timer" << endl;
02261       d->m_redirectionTimer.start( 1000 * d->m_delayRedirect, true );
02262     } else {
02263       //kdDebug(6050) << this << " not toplevel -> not starting redirection timer. Waiting for slotParentCompleted." << endl;
02264     }
02265 
02266     pendingAction = true;
02267   }
02268   else if ( bPendingChildRedirection )
02269   {
02270     pendingAction = true;
02271   }
02272 
02273   // the view will emit completed on our behalf,
02274   // either now or at next repaint if one is pending
02275 
02276   //kdDebug(6050) << this << " asks the view to emit completed. pendingAction=" << pendingAction << endl;
02277   d->m_view->complete( pendingAction );
02278 
02279   // find the alternate stylesheets
02280   QStringList sheets;
02281   if (d->m_doc)
02282      sheets = d->m_doc->availableStyleSheets();
02283   sheets.prepend( i18n( "Automatic Detection" ) );
02284   d->m_paUseStylesheet->setItems( sheets );
02285 
02286   d->m_paUseStylesheet->setEnabled( sheets.count() > 2);
02287   if (sheets.count() > 2)
02288   {
02289     d->m_paUseStylesheet->setCurrentItem(kMax(sheets.findIndex(d->m_sheetUsed), 0));
02290     slotUseStylesheet();
02291   }
02292 
02293   setJSDefaultStatusBarText(QString::null);
02294 
02295 #ifdef SPEED_DEBUG
02296   kdDebug(6050) << "DONE: " <<d->m_parsetime.elapsed() << endl;
02297 #endif
02298 }
02299 
02300 void KHTMLPart::checkEmitLoadEvent()
02301 {
02302   if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
02303 
02304   ConstFrameIt it = d->m_frames.begin();
02305   const ConstFrameIt end = d->m_frames.end();
02306   for (; it != end; ++it )
02307     if ( !(*it)->m_bCompleted ) // still got a frame running -> too early
02308       return;
02309 
02310   ConstFrameIt oi = d->m_objects.begin();
02311   const ConstFrameIt oiEnd = d->m_objects.end();
02312 
02313   for (; oi != oiEnd; ++oi )
02314     if ( !(*oi)->m_bCompleted ) // still got a object running -> too early
02315       return;
02316 
02317   // Still waiting for images/scripts from the loader ?
02318   // (onload must happen afterwards, #45607)
02319   // ## This makes this method very similar to checkCompleted. A brave soul should try merging them.
02320   int requests = 0;
02321   if ( d->m_doc && d->m_doc->docLoader() )
02322     requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
02323 
02324   if ( requests > 0 )
02325     return;
02326 
02327   d->m_bLoadEventEmitted = true;
02328   if (d->m_doc)
02329     d->m_doc->close();
02330 }
02331 
02332 const KHTMLSettings *KHTMLPart::settings() const
02333 {
02334   return d->m_settings;
02335 }
02336 
02337 #ifndef KDE_NO_COMPAT
02338 KURL KHTMLPart::baseURL() const
02339 {
02340   if ( !d->m_doc ) return KURL();
02341 
02342   return d->m_doc->baseURL();
02343 }
02344 
02345 QString KHTMLPart::baseTarget() const
02346 {
02347   if ( !d->m_doc ) return QString::null;
02348 
02349   return d->m_doc->baseTarget();
02350 }
02351 #endif
02352 
02353 KURL KHTMLPart::completeURL( const QString &url )
02354 {
02355   if ( !d->m_doc ) return KURL( url );
02356 
02357   if (d->m_decoder)
02358     return KURL(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
02359 
02360   return KURL( d->m_doc->completeURL( url ) );
02361 }
02362 
02363 // Called by ecma/kjs_window in case of redirections from Javascript,
02364 // and by xml/dom_docimpl.cpp in case of http-equiv meta refresh.
02365 void KHTMLPart::scheduleRedirection( int delay, const QString &url, bool doLockHistory )
02366 {
02367   kdDebug(6050) << "KHTMLPart::scheduleRedirection delay=" << delay << " url=" << url << endl;
02368   kdDebug(6050) << "current redirectURL=" << d->m_redirectURL << " with delay " << d->m_delayRedirect <<  endl;
02369   if( delay < 24*60*60 &&
02370       ( d->m_redirectURL.isEmpty() || delay <= d->m_delayRedirect) ) {
02371     d->m_delayRedirect = delay;
02372     d->m_redirectURL = url;
02373     d->m_redirectLockHistory = doLockHistory;
02374     kdDebug(6050) << " d->m_bComplete=" << d->m_bComplete << endl;
02375     if ( d->m_bComplete ) {
02376       d->m_redirectionTimer.stop();
02377       d->m_redirectionTimer.start( kMax(0, 1000 * d->m_delayRedirect), true );
02378     }
02379   }
02380 }
02381 
02382 void KHTMLPart::slotRedirect()
02383 {
02384   kdDebug(6050) << this << " slotRedirect()" << endl;
02385   QString u = d->m_redirectURL;
02386   d->m_delayRedirect = 0;
02387   d->m_redirectURL = QString::null;
02388 
02389   // SYNC check with ecma/kjs_window.cpp::goURL !
02390   if ( u.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
02391   {
02392     QString script = KURL::decode_string( u.right( u.length() - 11 ) );
02393     kdDebug( 6050 ) << "KHTMLPart::slotRedirect script=" << script << endl;
02394     QVariant res = executeScript( DOM::Node(), script );
02395     if ( res.type() == QVariant::String ) {
02396       begin( url() );
02397       write( res.asString() );
02398       end();
02399     }
02400     emit completed();
02401     return;
02402   }
02403   KParts::URLArgs args;
02404   KURL cUrl( m_url );
02405   KURL url( u );
02406 
02407   // handle windows opened by JS
02408   if ( openedByJS() && d->m_opener )
02409       cUrl = d->m_opener->url();
02410 
02411   if (!kapp || !kapp->authorizeURLAction("redirect", cUrl, url))
02412   {
02413     kdWarning(6050) << "KHTMLPart::scheduleRedirection: Redirection from " << cUrl << " to " << url << " REJECTED!" << endl;
02414     emit completed();
02415     return;
02416   }
02417 
02418   if ( urlcmp( u, m_url.url(), true, true ) )
02419   {
02420     args.metaData().insert("referrer", d->m_pageReferrer);
02421   }
02422 
02423   // For javascript and META-tag based redirections:
02424   //   - We don't take cross-domain-ness in consideration if we are the
02425   //   toplevel frame because the new URL may be in a different domain as the current URL
02426   //   but that's ok.
02427   //   - If we are not the toplevel frame then we check against the toplevelURL()
02428   if (parentPart())
02429       args.metaData().insert("cross-domain", toplevelURL().url());
02430 
02431   args.setLockHistory( d->m_redirectLockHistory );
02432   // _self: make sure we don't use any <base target=>'s
02433 
02434   d->m_urlSelectedOpenedURL = true; // In case overriden, default to success
02435   urlSelected( u, 0, 0, "_self", args );
02436 
02437   if ( !d->m_urlSelectedOpenedURL ) // urlSelected didn't open a url, so emit completed ourselves
02438     emit completed();
02439 }
02440 
02441 void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url)
02442 {
02443   // the slave told us that we got redirected
02444   //kdDebug( 6050 ) << "redirection by KIO to " << url.url() << endl;
02445   emit d->m_extension->setLocationBarURL( url.prettyURL() );
02446   d->m_workingURL = url;
02447 }
02448 
02449 bool KHTMLPart::setEncoding( const QString &name, bool override )
02450 {
02451     d->m_encoding = name;
02452     d->m_haveEncoding = override;
02453 
02454     if( !m_url.isEmpty() ) {
02455         // reload document
02456         closeURL();
02457         KURL url = m_url;
02458         m_url = 0;
02459         d->m_restored = true;
02460         openURL(url);
02461         d->m_restored = false;
02462     }
02463 
02464     return true;
02465 }
02466 
02467 QString KHTMLPart::encoding() const
02468 {
02469     if(d->m_haveEncoding && !d->m_encoding.isEmpty())
02470         return d->m_encoding;
02471 
02472     if(d->m_decoder && d->m_decoder->encoding())
02473         return QString(d->m_decoder->encoding());
02474 
02475     return defaultEncoding();
02476 }
02477 
02478 QString KHTMLPart::defaultEncoding() const
02479 {
02480   QString encoding = settings()->encoding();
02481   if ( !encoding.isEmpty() )
02482     return encoding;
02483   // HTTP requires the default encoding to be latin1, when neither
02484   // the user nor the page requested a particular encoding.
02485   if ( url().protocol().startsWith( "http" ) )
02486     return "iso-8859-1";
02487   else
02488     return KGlobal::locale()->encoding();
02489 }
02490 
02491 void KHTMLPart::setUserStyleSheet(const KURL &url)
02492 {
02493   if ( d->m_doc && d->m_doc->docLoader() )
02494     (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
02495 }
02496 
02497 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
02498 {
02499   if ( d->m_doc )
02500     d->m_doc->setUserStyleSheet( styleSheet );
02501 }
02502 
02503 bool KHTMLPart::gotoAnchor( const QString &name )
02504 {
02505   if (!d->m_doc)
02506     return false;
02507 
02508   HTMLCollectionImpl *anchors =
02509       new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
02510   anchors->ref();
02511   NodeImpl *n = anchors->namedItem(name);
02512   anchors->deref();
02513 
02514   if(!n) {
02515       n = d->m_doc->getElementById( name );
02516   }
02517 
02518   d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
02519 
02520   // Implement the rule that "" and "top" both mean top of page as in other browsers.
02521   bool quirkyName = !n && !d->m_doc->inStrictMode() && (name.isEmpty() || name.lower() == "top");
02522 
02523   if (quirkyName) {
02524       d->m_view->setContentsPos(0, 0);
02525       return true;
02526   } else if (!n) {
02527       kdDebug(6050) << "KHTMLPart::gotoAnchor node '" << name << "' not found" << endl;
02528       return false;
02529   }
02530 
02531   int x = 0, y = 0;
02532   int gox, dummy;
02533   HTMLElementImpl *a = static_cast<HTMLElementImpl *>(n);
02534 
02535   a->getUpperLeftCorner(x, y);
02536   if (x <= d->m_view->contentsX())
02537     gox = x - 10;
02538   else {
02539     gox = d->m_view->contentsX();
02540     if ( x + 10 > d->m_view->contentsX()+d->m_view->visibleWidth()) {
02541       a->getLowerRightCorner(x, dummy);
02542       gox = x - d->m_view->visibleWidth() + 10;
02543     }
02544   }
02545 
02546   d->m_view->setContentsPos(gox, y);
02547 
02548   return true;
02549 }
02550 
02551 bool KHTMLPart::nextAnchor()
02552 {
02553   if (!d->m_doc)
02554     return false;
02555   d->m_view->focusNextPrevNode ( true );
02556 
02557   return true;
02558 }
02559 
02560 bool KHTMLPart::prevAnchor()
02561 {
02562   if (!d->m_doc)
02563     return false;
02564   d->m_view->focusNextPrevNode ( false );
02565 
02566   return true;
02567 }
02568 
02569 void KHTMLPart::setStandardFont( const QString &name )
02570 {
02571     d->m_settings->setStdFontName(name);
02572 }
02573 
02574 void KHTMLPart::setFixedFont( const QString &name )
02575 {
02576     d->m_settings->setFixedFontName(name);
02577 }
02578 
02579 void KHTMLPart::setURLCursor( const QCursor &c )
02580 {
02581   d->m_linkCursor = c;
02582 }
02583 
02584 QCursor KHTMLPart::urlCursor() const
02585 {
02586   return d->m_linkCursor;
02587 }
02588 
02589 bool KHTMLPart::onlyLocalReferences() const
02590 {
02591   return d->m_onlyLocalReferences;
02592 }
02593 
02594 void KHTMLPart::setOnlyLocalReferences(bool enable)
02595 {
02596   d->m_onlyLocalReferences = enable;
02597 }
02598 
02599 void KHTMLPartPrivate::setFlagRecursively(
02600     bool KHTMLPartPrivate::*flag, bool value)
02601 {
02602   // first set it on the current one
02603   this->*flag = value;
02604 
02605   // descend into child frames recursively
02606   {
02607     QValueList<khtml::ChildFrame*>::Iterator it = m_frames.begin();
02608     const QValueList<khtml::ChildFrame*>::Iterator itEnd = m_frames.end();
02609     for (; it != itEnd; ++it) {
02610       KHTMLPart* const part = static_cast<KHTMLPart *>((KParts::ReadOnlyPart *)(*it)->m_part);
02611       if (part->inherits("KHTMLPart"))
02612         part->d->setFlagRecursively(flag, value);
02613     }/*next it*/
02614   }
02615   // do the same again for objects
02616   {
02617     QValueList<khtml::ChildFrame*>::Iterator it = m_objects.begin();
02618     const QValueList<khtml::ChildFrame*>::Iterator itEnd = m_objects.end();
02619     for (; it != itEnd; ++it) {
02620       KHTMLPart* const part = static_cast<KHTMLPart *>((KParts::ReadOnlyPart *)(*it)->m_part);
02621       if (part->inherits("KHTMLPart"))
02622         part->d->setFlagRecursively(flag, value);
02623     }/*next it*/
02624   }
02625 }
02626 
02627 void KHTMLPart::setCaretMode(bool enable)
02628 {
02629 #ifndef KHTML_NO_CARET
02630   kdDebug(6200) << "setCaretMode(" << enable << ")" << endl;
02631   if (isCaretMode() == enable) return;
02632   d->setFlagRecursively(&KHTMLPartPrivate::m_caretMode, enable);
02633   // FIXME: this won't work on frames as expected
02634   if (!isEditable()) {
02635     if (enable) {
02636       view()->initCaret(true);
02637       view()->ensureCaretVisible();
02638     } else
02639       view()->caretOff();
02640   }/*end if*/
02641 #endif // KHTML_NO_CARET
02642 }
02643 
02644 bool KHTMLPart::isCaretMode() const
02645 {
02646   return d->m_caretMode;
02647 }
02648 
02649 void KHTMLPart::setEditable(bool enable)
02650 {
02651 #ifndef KHTML_NO_CARET
02652   if (isEditable() == enable) return;
02653   d->setFlagRecursively(&KHTMLPartPrivate::m_designMode, enable);
02654   // FIXME: this won't work on frames as expected
02655   if (!isCaretMode()) {
02656     if (enable) {
02657       view()->initCaret(true);
02658       view()->ensureCaretVisible();
02659     } else
02660       view()->caretOff();
02661   }/*end if*/
02662 #endif // KHTML_NO_CARET
02663 }
02664 
02665 bool KHTMLPart::isEditable() const
02666 {
02667   return d->m_designMode;
02668 }
02669 
02670 void KHTMLPart::setCaretPosition(DOM::Node node, long offset, bool extendSelection)
02671 {
02672 #ifndef KHTML_NO_CARET
02673 #if 0
02674   kdDebug(6200) << k_funcinfo << "node: " << node.handle() << " nodeName: "
02675     << node.nodeName().string() << " offset: " << offset
02676     << " extendSelection " << extendSelection << endl;
02677 #endif
02678   if (view()->moveCaretTo(node.handle(), offset, !extendSelection))
02679     emitSelectionChanged();
02680   view()->ensureCaretVisible();
02681 #endif // KHTML_NO_CARET
02682 }
02683 
02684 KHTMLPart::CaretDisplayPolicy KHTMLPart::caretDisplayPolicyNonFocused() const
02685 {
02686 #ifndef KHTML_NO_CARET
02687   return (CaretDisplayPolicy)view()->caretDisplayPolicyNonFocused();
02688 #else // KHTML_NO_CARET
02689   return CaretInvisible;
02690 #endif // KHTML_NO_CARET
02691 }
02692 
02693 void KHTMLPart::setCaretDisplayPolicyNonFocused(CaretDisplayPolicy policy)
02694 {
02695 #ifndef KHTML_NO_CARET
02696   view()->setCaretDisplayPolicyNonFocused(policy);
02697 #endif // KHTML_NO_CARET
02698 }
02699 
02700 void KHTMLPart::setCaretVisible(bool show)
02701 {
02702 #ifndef KHTML_NO_CARET
02703   if (show) {
02704 
02705     NodeImpl *caretNode = xmlDocImpl()->focusNode();
02706     if (isCaretMode() || isEditable()
02707     || (caretNode && caretNode->contentEditable())) {
02708       view()->caretOn();
02709     }/*end if*/
02710 
02711   } else {
02712 
02713     view()->caretOff();
02714 
02715   }/*end if*/
02716 #endif // KHTML_NO_CARET
02717 }
02718 
02719 void KHTMLPart::findTextBegin()
02720 {
02721   d->m_findPos = -1;
02722   d->m_findNode = 0;
02723   d->m_findPosEnd = -1;
02724   d->m_findNodeEnd= 0;
02725   d->m_findPosStart = -1;
02726   d->m_findNodeStart = 0;
02727   d->m_findNodePrevious = 0;
02728   delete d->m_find;
02729   d->m_find = 0L;
02730 }
02731 
02732 bool KHTMLPart::initFindNode( bool selection, bool reverse, bool fromCursor )
02733 {
02734     if ( !d->m_doc )
02735         return false;
02736 
02737     DOM::NodeImpl* firstNode = 0L;
02738     if (d->m_doc->isHTMLDocument())
02739       firstNode = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
02740     else
02741       firstNode = d->m_doc;
02742 
02743     if ( !firstNode )
02744     {
02745       //kdDebug(6050) << k_funcinfo << "no first node (body or doc) -> return false" << endl;
02746       return false;
02747     }
02748     if ( firstNode->id() == ID_FRAMESET )
02749     {
02750       //kdDebug(6050) << k_funcinfo << "FRAMESET -> return false" << endl;
02751       return false;
02752     }
02753 
02754     if ( selection && hasSelection() )
02755     {
02756       //kdDebug(6050) << k_funcinfo << "using selection" << endl;
02757       if ( !fromCursor )
02758       {
02759         d->m_findNode = reverse ? d->m_selectionEnd.handle() : d->m_selectionStart.handle();
02760         d->m_findPos = reverse ? d->m_endOffset : d->m_startOffset;
02761       }
02762       d->m_findNodeEnd = reverse ? d->m_selectionStart.handle() : d->m_selectionEnd.handle();
02763       d->m_findPosEnd = reverse ? d->m_startOffset : d->m_endOffset;
02764       d->m_findNodeStart = !reverse ? d->m_selectionStart.handle() : d->m_selectionEnd.handle();
02765       d->m_findPosStart = !reverse ? d->m_startOffset : d->m_endOffset;
02766       d->m_findNodePrevious = d->m_findNodeStart;
02767     }
02768     else // whole document
02769     {
02770       //kdDebug(6050) << k_funcinfo << "whole doc" << endl;
02771       if ( !fromCursor )
02772       {
02773         d->m_findNode = firstNode;
02774         d->m_findPos = reverse ? -1 : 0;
02775       }
02776       d->m_findNodeEnd = reverse ? firstNode : 0;
02777       d->m_findPosEnd = reverse ? 0 : -1;
02778       d->m_findNodeStart = !reverse ? firstNode : 0;
02779       d->m_findPosStart = !reverse ? 0 : -1;
02780       d->m_findNodePrevious = d->m_findNodeStart;
02781       if ( reverse )
02782       {
02783         // Need to find out the really last object, to start from it
02784         khtml::RenderObject* obj = d->m_findNode ? d->m_findNode->renderer() : 0;
02785         if ( obj )
02786         {
02787           // find the last object in the render tree
02788           while ( obj->lastChild() )
02789           {
02790               obj = obj->lastChild();
02791           }
02792           // now get the last object with a NodeImpl associated
02793           while ( !obj->element() && obj->objectAbove() )
02794           {
02795              obj = obj->objectAbove();
02796           }
02797           d->m_findNode = obj->element();
02798         }
02799       }
02800     }
02801     return true;
02802 }
02803 
02804 // Old method (its API limits the available features - remove in KDE-4)
02805 bool KHTMLPart::findTextNext( const QString &str, bool forward, bool caseSensitive, bool isRegExp )
02806 {
02807     if ( !initFindNode( false, !forward, d->m_findNode ) )
02808       return false;
02809     while(1)
02810     {
02811         if( (d->m_findNode->nodeType() == Node::TEXT_NODE || d->m_findNode->nodeType() == Node::CDATA_SECTION_NODE) && d->m_findNode->renderer() )
02812         {
02813             DOMString nodeText = d->m_findNode->nodeValue();
02814             DOMStringImpl *t = nodeText.implementation();
02815             QConstString s(t->s, t->l);
02816 
02817             int matchLen = 0;
02818             if ( isRegExp ) {
02819               QRegExp matcher( str );
02820               matcher.setCaseSensitive( caseSensitive );
02821               d->m_findPos = matcher.search(s.string(), d->m_findPos+1);
02822               if ( d->m_findPos != -1 )
02823                 matchLen = matcher.matchedLength();
02824             }
02825             else {
02826               d->m_findPos = s.string().find(str, d->m_findPos+1, caseSensitive);
02827               matchLen = str.length();
02828             }
02829 
02830             if(d->m_findPos != -1)
02831             {
02832                 int x = 0, y = 0;
02833                 if(static_cast<khtml::RenderText *>(d->m_findNode->renderer())
02834                   ->posOfChar(d->m_findPos, x, y))
02835                     d->m_view->setContentsPos(x-50, y-50);
02836 
02837                 d->m_selectionStart = d->m_findNode;
02838                 d->m_startOffset = d->m_findPos;
02839                 d->m_selectionEnd = d->m_findNode;
02840                 d->m_endOffset = d->m_findPos + matchLen;
02841                 d->m_startBeforeEnd = true;
02842 
02843                 d->m_doc->setSelection( d->m_selectionStart.handle(), d->m_startOffset,
02844                                         d->m_selectionEnd.handle(), d->m_endOffset );
02845                 emitSelectionChanged();
02846                 return true;
02847             }
02848         }
02849         d->m_findPos = -1;
02850 
02851         NodeImpl *next;
02852 
02853         if ( forward )
02854         {
02855           next = d->m_findNode->firstChild();
02856 
02857           if(!next) next = d->m_findNode->nextSibling();
02858           while(d->m_findNode && !next) {
02859               d->m_findNode = d->m_findNode->parentNode();
02860               if( d->m_findNode ) {
02861                   next = d->m_findNode->nextSibling();
02862               }
02863           }
02864         }
02865         else
02866         {
02867           next = d->m_findNode->lastChild();
02868 
02869           if (!next ) next = d->m_findNode->previousSibling();
02870           while ( d->m_findNode && !next )
02871           {
02872             d->m_findNode = d->m_findNode->parentNode();
02873             if( d->m_findNode )
02874             {
02875               next = d->m_findNode->previousSibling();
02876             }
02877           }
02878         }
02879 
02880         d->m_findNode = next;
02881         if(!d->m_findNode) return false;
02882     }
02883 }
02884 
02885 
02886 void KHTMLPart::slotFind()
02887 {
02888   KParts::ReadOnlyPart *part = currentFrame();
02889   if (!part)
02890     return;
02891   if (!part->inherits("KHTMLPart") )
02892   {
02893       kdError(6000) << "slotFind: part is a " << part->className() << ", can't do a search into it" << endl;
02894       return;
02895   }
02896   static_cast<KHTMLPart *>( part )->findText();
02897 }
02898 
02899 void KHTMLPart::slotFindNext()
02900 {
02901   KParts::ReadOnlyPart *part = currentFrame();
02902   if (!part)
02903     return;
02904   if (!part->inherits("KHTMLPart") )
02905   {
02906       kdError(6000) << "slotFindNext: part is a " << part->className() << ", can't do a search into it" << endl;
02907       return;
02908   }
02909   static_cast<KHTMLPart *>( part )->findTextNext();
02910 }
02911 
02912 void KHTMLPart::slotFindPrev()
02913 {
02914   KParts::ReadOnlyPart *part = currentFrame();
02915   if (!part)
02916     return;
02917   if (!part->inherits("KHTMLPart") )
02918   {
02919       kdError(6000) << "slotFindNext: part is a " << part->className() << ", can't do a search into it" << endl;
02920       return;
02921   }
02922   static_cast<KHTMLPart *>( part )->findTextNext( true ); // reverse
02923 }
02924 
02925 void KHTMLPart::slotFindDone()
02926 {
02927   // ### remove me
02928 }
02929 
02930 void KHTMLPart::slotFindAheadText()
02931 {
02932 #ifndef KHTML_NO_TYPE_AHEAD_FIND
02933   KParts::ReadOnlyPart *part = currentFrame();
02934   if (!part)
02935     return;
02936   if (!part->inherits("KHTMLPart") )
02937   {
02938       kdError(6000) << "slotFindNext: part is a " << part->className() << ", can't do a search into it" << endl;
02939       return;
02940   }
02941   static_cast<KHTMLPart *>( part )->view()->startFindAhead( false );
02942 #endif // KHTML_NO_TYPE_AHEAD_FIND
02943 }
02944 
02945 void KHTMLPart::slotFindAheadLink()
02946 {
02947 #ifndef KHTML_NO_TYPE_AHEAD_FIND
02948   KParts::ReadOnlyPart *part = currentFrame();
02949   if (!part)
02950     return;
02951   if (!part->inherits("KHTMLPart") )
02952   {
02953       kdError(6000) << "slotFindNext: part is a " << part->className() << ", can't do a search into it" << endl;
02954       return;
02955   }
02956   static_cast<KHTMLPart *>( part )->view()->startFindAhead( true );
02957 #endif // KHTML_NO_TYPE_AHEAD_FIND
02958 }
02959 
02960 void KHTMLPart::enableFindAheadActions( bool enable )
02961 {
02962   // only the topmost one has shortcuts
02963   KHTMLPart* p = this;
02964   while( p->parentPart())
02965     p = p->parentPart();
02966   p->d->m_paFindAheadText->setEnabled( enable );
02967   p->d->m_paFindAheadLinks->setEnabled( enable );
02968 }
02969 
02970 void KHTMLPart::slotFindDialogDestroyed()
02971 {
02972   d->m_lastFindState.options = d->m_findDialog->options();
02973   d->m_lastFindState.history = d->m_findDialog->findHistory();
02974   d->m_findDialog->deleteLater();
02975   d->m_findDialog = 0L;
02976 }
02977 
02978 void KHTMLPart::findText()
02979 {
02980   // First do some init to make sure we can search in this frame
02981   if ( !d->m_doc )
02982     return;
02983 
02984   // Raise if already opened
02985   if ( d->m_findDialog )
02986   {
02987     KWin::activateWindow( d->m_findDialog->winId() );
02988     return;
02989   }
02990 
02991   // The lineedit of the dialog would make khtml lose its selection, otherwise
02992 #ifndef QT_NO_CLIPBOARD
02993   disconnect( kapp->clipboard(), SIGNAL(selectionChanged()), this, SLOT(slotClearSelection()) );
02994 #endif
02995 
02996   // Now show the dialog in which the user can choose options.
02997   d->m_findDialog = new KFindDialog( false /*non-modal*/, widget(), "khtmlfind" );
02998   d->m_findDialog->setHasSelection( hasSelection() );
02999   d->m_findDialog->setHasCursor( d->m_findNode != 0 );
03000   if ( d->m_findNode ) // has a cursor -> default to 'FromCursor'
03001     d->m_lastFindState.options |= KFindDialog::FromCursor;
03002 
03003   // TODO? optionsDialog.setPattern( d->m_lastFindState.text );
03004   d->m_findDialog->setFindHistory( d->m_lastFindState.history );
03005   d->m_findDialog->setOptions( d->m_lastFindState.options );
03006 
03007   d->m_lastFindState.options = -1; // force update in findTextNext
03008   d->m_lastFindState.last_dir = -1;
03009 
03010   d->m_findDialog->show();
03011   connect( d->m_findDialog, SIGNAL(okClicked()), this, SLOT(slotFindNext()) );
03012   connect( d->m_findDialog, SIGNAL(finished()), this, SLOT(slotFindDialogDestroyed()) );
03013 
03014   findText( d->m_findDialog->pattern(), 0 /*options*/, widget(), d->m_findDialog );
03015 }
03016 
03017 void KHTMLPart::findText( const QString &str, long options, QWidget *parent, KFindDialog *findDialog )
03018 {
03019   // First do some init to make sure we can search in this frame
03020   if ( !d->m_doc )
03021     return;
03022 
03023 #ifndef QT_NO_CLIPBOARD
03024   connect( kapp->clipboard(), SIGNAL(selectionChanged()), SLOT(slotClearSelection()) );
03025 #endif
03026 
03027   // Create the KFind object
03028   delete d->m_find;
03029   d->m_find = new KFind( str, options, parent, findDialog );
03030   d->m_find->closeFindNextDialog(); // we use KFindDialog non-modal, so we don't want other dlg popping up
03031   connect( d->m_find, SIGNAL( highlight( const QString &, int, int ) ),
03032            this, SLOT( slotHighlight( const QString &, int, int ) ) );
03033   //connect(d->m_find, SIGNAL( findNext() ),
03034   //        this, SLOT( slotFindNext() ) );
03035 
03036   if ( !findDialog )
03037   {
03038     d->m_lastFindState.options = options;
03039     initFindNode( options & KFindDialog::SelectedText,
03040                   options & KFindDialog::FindBackwards,
03041                   options & KFindDialog::FromCursor );
03042   }
03043 }
03044 
03045 bool KHTMLPart::findTextNext()
03046 {
03047   return findTextNext( false );
03048 }
03049 
03050 // New method
03051 bool KHTMLPart::findTextNext( bool reverse )
03052 {
03053   if (!d->m_find)
03054   {
03055     // We didn't show the find dialog yet, let's do it then (#49442)
03056     findText();
03057     return false;
03058   }
03059 
03060   view()->updateFindAheadTimeout();
03061   long options = 0;
03062   if ( d->m_findDialog ) // 0 when we close the dialog
03063   {
03064     if ( d->m_find->pattern() != d->m_findDialog->pattern() ) {
03065       d->m_find->setPattern( d->m_findDialog->pattern() );
03066       d->m_find->resetCounts();
03067     }
03068     options = d->m_findDialog->options();
03069     if ( d->m_lastFindState.options != options )
03070     {
03071       d->m_find->setOptions( options );
03072 
03073       if ( options & KFindDialog::SelectedText )
03074         Q_ASSERT( hasSelection() );
03075 
03076       long difference = d->m_lastFindState.options ^ options;
03077       if ( difference & (KFindDialog::SelectedText | KFindDialog::FromCursor ) )
03078       {
03079           // Important options changed -> reset search range
03080         (void) initFindNode( options & KFindDialog::SelectedText,
03081                              options & KFindDialog::FindBackwards,
03082                              options & KFindDialog::FromCursor );
03083       }
03084       d->m_lastFindState.options = options;
03085     }
03086   } else
03087     options = d->m_lastFindState.options;
03088   if( reverse )
03089     options = options ^ KFindDialog::FindBackwards;
03090   if( d->m_find->options() != options )
03091     d->m_find->setOptions( options );
03092 
03093   // Changing find direction. Start and end nodes must be switched.
03094   // Additionally since d->m_findNode points after the last node
03095   // that was searched, it needs to be "after" it in the opposite direction.
03096   if( d->m_lastFindState.last_dir != -1
03097       && bool( d->m_lastFindState.last_dir ) != bool( options & KFindDialog::FindBackwards ))
03098   {
03099     qSwap( d->m_findNodeEnd, d->m_findNodeStart );
03100     qSwap( d->m_findPosEnd, d->m_findPosStart );
03101     qSwap( d->m_findNode, d->m_findNodePrevious );
03102     // d->m_findNode now point at the end of the last searched line - advance one node
03103     khtml::RenderObject* obj = d->m_findNode ? d->m_findNode->renderer() : 0;
03104     khtml::RenderObject* end = d->m_findNodeEnd ? d->m_findNodeEnd->renderer() : 0;
03105     if ( obj == end )
03106       obj = 0L;
03107     else
03108     {
03109       do {
03110         obj = (options & KFindDialog::FindBackwards) ? obj->objectAbove() : obj->objectBelow();
03111       } while ( obj && ( !obj->element() || obj->isInlineContinuation() ) );
03112     }
03113     if ( obj )
03114       d->m_findNode = obj->element();
03115     else
03116       d->m_findNode = 0;
03117   }
03118   d->m_lastFindState.last_dir = ( options & KFindDialog::FindBackwards ) ? 1 : 0;
03119 
03120   KFind::Result res = KFind::NoMatch;
03121   khtml::RenderObject* obj = d->m_findNode ? d->m_findNode->renderer() : 0;
03122   khtml::RenderObject* end = d->m_findNodeEnd ? d->m_findNodeEnd->renderer() : 0;
03123   khtml::RenderTextArea *tmpTextArea=0L;
03124   //kdDebug(6050) << k_funcinfo << "obj=" << obj << " end=" << end << endl;
03125   while( res == KFind::NoMatch )
03126   {
03127     if ( d->m_find->needData() )
03128     {
03129       if ( !obj ) {
03130         //kdDebug(6050) << k_funcinfo << "obj=0 -> done" << endl;
03131         break; // we're done
03132       }
03133       //kdDebug(6050) << k_funcinfo << " gathering data" << endl;
03134       // First make up the QString for the current 'line' (i.e. up to \n)
03135       // We also want to remember the DOMNode for every portion of the string.
03136       // We store this in an index->node list.
03137 
03138       d->m_stringPortions.clear();
03139       bool newLine = false;
03140       QString str;
03141       DOM::NodeImpl* lastNode = d->m_findNode;
03142       while ( obj && !newLine )
03143       {
03144         // Grab text from render object
03145         QString s;
03146         bool renderAreaText = obj->parent() && (QCString(obj->parent()->renderName())== "RenderTextArea");
03147         bool renderLineText = (QCString(obj->renderName())== "RenderLineEdit");
03148         if ( renderAreaText )
03149         {
03150           khtml::RenderTextArea *parent= static_cast<khtml::RenderTextArea *>(obj->parent());
03151           s = parent->text();
03152           s = s.replace(0xa0, ' ');
03153           tmpTextArea = parent;
03154         }
03155         else if ( renderLineText )
03156         {
03157           khtml::RenderLineEdit *parentLine= static_cast<khtml::RenderLineEdit *>(obj);
03158           s = parentLine->widget()->text();
03159           s = s.replace(0xa0, ' ');
03160         }
03161         else if ( obj->isText() )
03162         {
03163           bool isLink = false;
03164 
03165           // checks whether the node has a <A> parent
03166           if ( options & FindLinksOnly )
03167           {
03168             DOM::NodeImpl *parent = obj->element();
03169             while ( parent )
03170             {
03171               if ( parent->nodeType() == Node::ELEMENT_NODE && parent->id() == ID_A )
03172               {
03173                 isLink = true;
03174                 break;
03175               }
03176               parent = parent->parentNode();
03177             }
03178           }
03179           else
03180           {
03181             isLink = true;
03182           }
03183 
03184           if ( isLink && obj->parent()!=tmpTextArea )
03185           {
03186             s = static_cast<khtml::RenderText *>(obj)->data().string();
03187             s = s.replace(0xa0, ' ');
03188           }
03189         }
03190         else if ( obj->isBR() )
03191           s = '\n';
03192         else if ( !obj->isInline() && !str.isEmpty() )
03193           s = '\n';
03194 
03195         if ( lastNode == d->m_findNodeEnd )
03196           s.truncate( d->m_findPosEnd );
03197         if ( !s.isEmpty() )
03198         {
03199           newLine = s.find( '\n' ) != -1; // did we just get a newline?
03200           if( !( options & KFindDialog::FindBackwards ))
03201           {
03202             //kdDebug(6050) << "StringPortion: " << index << "-" << index+s.length()-1 << " -> " << lastNode << endl;
03203             d->m_stringPortions.append( KHTMLPartPrivate::StringPortion( str.length(), lastNode ) );
03204             str += s;
03205           }
03206           else // KFind itself can search backwards, so str must not be built backwards
03207           {
03208             for( QValueList<KHTMLPartPrivate::StringPortion>::Iterator it = d->m_stringPortions.begin();
03209                  it != d->m_stringPortions.end();
03210                  ++it )
03211                 (*it).index += s.length();
03212             d->m_stringPortions.prepend( KHTMLPartPrivate::StringPortion( 0, lastNode ) );
03213             str.prepend( s );
03214           }
03215         }
03216         // Compare obj and end _after_ we processed the 'end' node itself
03217         if ( obj == end )
03218           obj = 0L;
03219         else
03220         {
03221           // Move on to next object (note: if we found a \n already, then obj (and lastNode)
03222           // will point to the _next_ object, i.e. they are in advance.
03223           do {
03224             // We advance until the next RenderObject that has a NodeImpl as its element().
03225             // Otherwise (if we keep the 'last node', and it has a '\n') we might be stuck
03226             // on that object forever...
03227             obj = (options & KFindDialog::FindBackwards) ? obj->objectAbove() : obj->objectBelow();
03228           } while ( obj && ( !obj->element() || obj->isInlineContinuation() ) );
03229         }
03230         if ( obj )
03231           lastNode = obj->element();
03232         else
03233           lastNode = 0;
03234       } // end while
03235       //kdDebug()<<" str : "<<str<<endl;
03236       if ( !str.isEmpty() )
03237       {
03238         d->m_find->setData( str, d->m_findPos );
03239       }
03240 
03241       d->m_findPos = -1; // not used during the findnext loops. Only during init.
03242       d->m_findNodePrevious = d->m_findNode;
03243       d->m_findNode = lastNode;
03244     }
03245     if ( !d->m_find->needData() ) // happens if str was empty
03246     {
03247       // Let KFind inspect the text fragment, and emit highlighted if a match is found
03248       res = d->m_find->find();
03249     }
03250   } // end while
03251 
03252   if ( res == KFind::NoMatch ) // i.e. we're done
03253   {
03254     kdDebug() << "No more matches." << endl;
03255     if ( !(options & FindNoPopups) && d->m_find->shouldRestart() )
03256     {
03257       //kdDebug(6050) << "Restarting" << endl;
03258       initFindNode( false, options & KFindDialog::FindBackwards, false );
03259       findTextNext( reverse );
03260     }
03261     else // really done
03262     {
03263       //kdDebug(6050) << "Finishing" << endl;
03264       //delete d->m_find;
03265       //d->m_find = 0L;
03266       initFindNode( false, options & KFindDialog::FindBackwards, false );
03267       d->m_find->resetCounts();
03268       slotClearSelection();
03269     }
03270     kdDebug() << "Dialog closed." << endl;
03271   }
03272 
03273   return res == KFind::Match;
03274 }
03275 
03276 void KHTMLPart::slotHighlight( const QString& /*text*/, int index, int length )
03277 {
03278   //kdDebug(6050) << "slotHighlight index=" << index << " length=" << length << endl;
03279   QValueList<KHTMLPartPrivate::StringPortion>::Iterator it = d->m_stringPortions.begin();
03280   const QValueList<KHTMLPartPrivate::StringPortion>::Iterator itEnd = d->m_stringPortions.end();
03281   QValueList<KHTMLPartPrivate::StringPortion>::Iterator prev = it;
03282   // We stop at the first portion whose index is 'greater than', and then use the previous one
03283   while ( it != itEnd && (*it).index <= index )
03284   {
03285     prev = it;
03286     ++it;
03287   }
03288   Q_ASSERT ( prev != itEnd );
03289   DOM::NodeImpl* node = (*prev).node;
03290   Q_ASSERT( node );
03291 
03292   d->m_selectionStart = node;
03293   d->m_startOffset = index - (*prev).index;
03294 
03295   khtml::RenderObject* obj = node->renderer();
03296   khtml::RenderTextArea *parent = 0L;
03297   khtml::RenderLineEdit *parentLine = 0L;
03298   bool renderLineText =false;
03299 
03300   QRect highlightedRect;
03301   bool renderAreaText =false;
03302   Q_ASSERT( obj );
03303   if ( obj )
03304   {
03305     int x = 0, y = 0;
03306     renderAreaText = (QCString(obj->parent()->renderName())== "RenderTextArea");
03307     renderLineText = (QCString(obj->renderName())== "RenderLineEdit");
03308 
03309 
03310     if( renderAreaText )
03311       parent= static_cast<khtml::RenderTextArea *>(obj->parent());
03312     if ( renderLineText )
03313       parentLine= static_cast<khtml::RenderLineEdit *>(obj);
03314     if ( !renderLineText )
03315       //if (static_cast<khtml::RenderText *>(node->renderer())
03316       //    ->posOfChar(d->m_startOffset, x, y))
03317       {
03318         int dummy;
03319         static_cast<khtml::RenderText *>(node->renderer())
03320           ->caretPos( d->m_startOffset, false, x, y, dummy, dummy ); // more precise than posOfChar
03321         //kdDebug(6050) << "topleft: " << x << "," << y << endl;
03322         if ( x != -1 || y != -1 )
03323         {
03324           int gox = d->m_view->contentsX();
03325           if (x+50 > d->m_view->contentsX() + d->m_view->visibleWidth())
03326               gox = x - d->m_view->visibleWidth() + 50;
03327           if (x-10 < d->m_view->contentsX())
03328               gox = x - d->m_view->visibleWidth() - 10;
03329           if (gox < 0) gox = 0;
03330           d->m_view->setContentsPos(gox, y-50);
03331           highlightedRect.setTopLeft( d->m_view->mapToGlobal(QPoint(x, y)) );
03332         }
03333       }
03334   }
03335   // Now look for end node
03336   it = prev; // no need to start from beginning again
03337   while ( it != itEnd && (*it).index < index + length )
03338   {
03339     prev = it;
03340     ++it;
03341   }
03342   Q_ASSERT ( prev != itEnd );
03343 
03344   d->m_selectionEnd = (*prev).node;
03345   d->m_endOffset = index + length - (*prev).index;
03346   d->m_startBeforeEnd = true;
03347 
03348   // if the selection is limited to a single link, that link gets focus
03349   if(d->m_selectionStart == d->m_selectionEnd)
03350   {
03351     bool isLink = false;
03352 
03353     // checks whether the node has a <A> parent
03354     DOM::NodeImpl *parent = d->m_selectionStart.handle();
03355     while ( parent )
03356     {
03357       if ( parent->nodeType() == Node::ELEMENT_NODE && parent->id() == ID_A )
03358       {
03359         isLink = true;
03360         break;
03361       }
03362       parent = parent->parentNode();
03363     }
03364 
03365     if(isLink == true)
03366     {
03367       d->m_doc->setFocusNode( parent );
03368     }
03369   }
03370 
03371 #if 0
03372   kdDebug(6050) << "slotHighlight: " << d->m_selectionStart.handle() << "," << d->m_startOffset << " - " <<
03373     d->m_selectionEnd.handle() << "," << d->m_endOffset << endl;
03374   it = d->m_stringPortions.begin();
03375   for ( ; it != d->m_stringPortions.end() ; ++it )
03376     kdDebug(6050) << "  StringPortion: from index=" << (*it).index << " -> node=" << (*it).node << endl;
03377 #endif
03378   if( renderAreaText )
03379   {
03380     if( parent )
03381       parent->highLightWord( length, d->m_endOffset-length );
03382   }
03383   else if ( renderLineText )
03384   {
03385     if( parentLine )
03386       parentLine->highLightWord( length, d->m_endOffset-length );
03387   }
03388   else
03389   {
03390     d->m_doc->setSelection( d->m_selectionStart.handle(), d->m_startOffset,
03391                             d->m_selectionEnd.handle(), d->m_endOffset );
03392     if (d->m_selectionEnd.handle()->renderer() )
03393     {
03394       int x, y, height, dummy;
03395       static_cast<khtml::RenderText *>(d->m_selectionEnd.handle()->renderer())
03396           ->caretPos( d->m_endOffset, false, x, y, dummy, height ); // more precise than posOfChar
03397       //kdDebug(6050) << "bottomright: " << x << "," << y+height << endl;
03398       if ( x != -1 || y != -1 )
03399       {
03400         // if ( static_cast<khtml::RenderText *>(d->m_selectionEnd.handle()->renderer())
03401         //  ->posOfChar(d->m_endOffset-1, x, y))
03402         highlightedRect.setBottomRight( d->m_view->mapToGlobal( QPoint(x, y+height) ) );
03403       }
03404     }
03405   }
03406   emitSelectionChanged();
03407 
03408   // make the finddialog move away from the selected area
03409   if ( d->m_findDialog && !highlightedRect.isNull() )
03410   {
03411     highlightedRect.moveBy( -d->m_view->contentsX(), -d->m_view->contentsY() );
03412     //kdDebug(6050) << "avoiding " << highlightedRect << endl;
03413     KDialog::avoidArea( d->m_findDialog, highlightedRect );
03414   }
03415 }
03416 
03417 QString KHTMLPart::selectedTextAsHTML() const
03418 {
03419   if(!hasSelection()) {
03420     kdDebug() << "selectedTextAsHTML(): selection is not valid.  Returning empty selection" << endl;
03421     return QString::null;
03422   }
03423   if(d->m_startOffset < 0 || d->m_endOffset <0) {
03424     kdDebug() << "invalid values for end/startOffset " << d->m_startOffset << " " << d->m_endOffset << endl;
03425     return QString::null;
03426   }
03427   DOM::Range r = selection();
03428   if(r.isNull() || r.isDetached())
03429     return QString::null;
03430   int exceptioncode = 0; //ignore the result
03431   return r.handle()->toHTML(exceptioncode).string();
03432 }
03433 
03434 QString KHTMLPart::selectedText() const
03435 {
03436   bool hasNewLine = true;
03437   bool seenTDTag = false;
03438   QString text;
03439   DOM::Node n = d->m_selectionStart;
03440   while(!n.isNull()) {
03441       if(n.nodeType() == DOM::Node::TEXT_NODE && n.handle()->renderer()) {
03442         DOM::DOMStringImpl *dstr = static_cast<DOM::TextImpl*>(n.handle())->renderString();
03443         QString str(dstr->s, dstr->l);
03444     if(!str.isEmpty()) {
03445           if(seenTDTag) {
03446         text += "  ";
03447         seenTDTag = false;
03448       }
03449           hasNewLine = false;
03450           if(n == d->m_selectionStart && n == d->m_selectionEnd)
03451             text = str.mid(d->m_startOffset, d->m_endOffset - d->m_startOffset);
03452           else if(n == d->m_selectionStart)
03453             text = str.mid(d->m_startOffset);
03454           else if(n == d->m_selectionEnd)
03455             text += str.left(d->m_endOffset);
03456           else
03457             text += str;
03458     }
03459       }
03460       else {
03461         // This is our simple HTML -> ASCII transformation:
03462         unsigned short id = n.elementId();
03463         switch(id) {
03464       case ID_TEXTAREA:
03465         text += static_cast<HTMLTextAreaElementImpl*>(n.handle())->value().string();
03466         break;
03467       case ID_INPUT:
03468         text += static_cast<HTMLInputElementImpl*>(n.handle())->value().string();
03469         break;
03470       case ID_SELECT:
03471         text += static_cast<HTMLSelectElementImpl*>(n.handle())->value().string();
03472         break;
03473           case ID_BR:
03474             text += "\n";
03475             hasNewLine = true;
03476             break;
03477           case ID_IMG:
03478         text += static_cast<HTMLImageElementImpl*>(n.handle())->altText().string();
03479         break;
03480           case ID_TD:
03481         break;
03482           case ID_TH:
03483           case ID_HR:
03484           case ID_OL:
03485           case ID_UL:
03486           case ID_LI:
03487           case ID_DD:
03488           case ID_DL:
03489           case ID_DT:
03490           case ID_PRE:
03491           case ID_BLOCKQUOTE:
03492           case ID_DIV:
03493             if (!hasNewLine)
03494                text += "\n";
03495             hasNewLine = true;
03496             break;
03497           case ID_P:
03498           case ID_TR:
03499           case ID_H1:
03500           case ID_H2:
03501           case ID_H3:
03502           case ID_H4:
03503           case ID_H5:
03504           case ID_H6:
03505             if (!hasNewLine)
03506                text += "\n";
03507 //            text += "\n";
03508             hasNewLine = true;
03509             break;
03510         }
03511       }
03512       if(n == d->m_selectionEnd) break;
03513       DOM::Node next = n.firstChild();
03514       if(next.isNull()) next = n.nextSibling();
03515       while( next.isNull() && !n.parentNode().isNull() ) {
03516         n = n.parentNode();
03517         next = n.nextSibling();
03518         unsigned short id = n.elementId();
03519         switch(id) {
03520           case ID_TD:
03521         seenTDTag = true; //Add two spaces after a td if then followed by text.
03522         break;
03523           case ID_TH:
03524           case ID_HR:
03525           case ID_OL:
03526           case ID_UL:
03527           case ID_LI:
03528           case ID_DD:
03529           case ID_DL:
03530           case ID_DT:
03531           case ID_PRE:
03532           case ID_BLOCKQUOTE:
03533           case ID_DIV:
03534         seenTDTag = false;
03535             if (!hasNewLine)
03536                text += "\n";
03537             hasNewLine = true;
03538             break;
03539           case ID_P:
03540           case ID_TR:
03541           case ID_H1:
03542           case ID_H2:
03543           case ID_H3:
03544           case ID_H4:
03545           case ID_H5:
03546           case ID_H6:
03547             if (!hasNewLine)
03548                text += "\n";
03549 //            text += "\n";
03550             hasNewLine = true;
03551             break;
03552         }
03553       }
03554 
03555       n = next;
03556     }
03557 
03558     if(text.isEmpty())
03559         return QString::null;
03560 
03561     int start = 0;
03562     int end = text.length();
03563 
03564     // Strip leading LFs
03565     while ((start < end) && (text[start] == '\n'))
03566        ++start;
03567 
03568     // Strip excessive trailing LFs
03569     while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n'))
03570        --end;
03571 
03572     return text.mid(start, end-start);
03573 }
03574 
03575 bool KHTMLPart::hasSelection() const
03576 {
03577   if ( d->m_selectionStart.isNull() || d->m_selectionEnd.isNull() )
03578       return false;
03579   if ( d->m_selectionStart == d->m_selectionEnd &&
03580        d->m_startOffset == d->m_endOffset )
03581       return false; // empty
03582   return true;
03583 }
03584 
03585 DOM::Range KHTMLPart::selection() const
03586 {
03587     if( d->m_selectionStart.isNull() || d->m_selectionEnd.isNull() )
03588         return DOM::Range();
03589     DOM::Range r = document().createRange();
03590     RangeImpl *rng = r.handle();
03591     int exception = 0;
03592     NodeImpl *n = d->m_selectionStart.handle();
03593     if(!n->parentNode() ||
03594        !n->renderer() ||
03595        (!n->renderer()->isReplaced() && !n->renderer()->isBR())) {
03596         rng->setStart( n, d->m_startOffset, exception );
03597     if(exception) {
03598         kdDebug(6000) << "1 -selection() threw the exception " << exception << ".  Returning empty range." << endl;
03599         return DOM::Range();
03600     }
03601     } else {
03602         int o_start = 0;
03603         while ((n = n->previousSibling()))
03604             o_start++;
03605     rng->setStart( d->m_selectionStart.parentNode().handle(), o_start + d->m_startOffset, exception );
03606     if(exception) {
03607         kdDebug(6000) << "2 - selection() threw the exception " << exception << ".  Returning empty range." << endl;
03608         return DOM::Range();
03609     }
03610 
03611     }
03612 
03613     n = d->m_selectionEnd.handle();
03614     if(!n->parentNode() ||
03615        !n->renderer() ||
03616        (!n->renderer()->isReplaced() && !n->renderer()->isBR())) {
03617 
03618     rng->setEnd( n, d->m_endOffset, exception );
03619     if(exception) {
03620         kdDebug(6000) << "3 - selection() threw the exception " << exception << ".  Returning empty range." << endl;
03621         return DOM::Range();
03622     }
03623 
03624     } else {
03625         int o_end = 0;
03626         while ((n = n->previousSibling()))
03627             o_end++;
03628     rng->setEnd( d->m_selectionEnd.parentNode().handle(), o_end + d->m_endOffset, exception);
03629     if(exception) {
03630         kdDebug(6000) << "4 - selection() threw the exception " << exception << ".  Returning empty range." << endl;
03631         return DOM::Range();
03632     }
03633 
03634     }
03635 
03636     return r;
03637 }
03638 
03639 void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const
03640 {
03641     s = d->m_selectionStart;
03642     so = d->m_startOffset;
03643     e = d->m_selectionEnd;
03644     eo = d->m_endOffset;
03645 }
03646 
03647 void KHTMLPart::setSelection( const DOM::Range &r )
03648 {
03649     // Quick-fix: a collapsed range shouldn't select the whole node.
03650     // The real problem is in RenderCanvas::setSelection though (when index==0 the whole node is selected).
03651     if ( r.collapsed() )
03652         slotClearSelection();
03653     else {
03654         d->m_selectionStart = r.startContainer();
03655         d->m_startOffset = r.startOffset();
03656         d->m_selectionEnd = r.endContainer();
03657         d->m_endOffset = r.endOffset();
03658         d->m_doc->setSelection(d->m_selectionStart.handle(),d->m_startOffset,
03659                                d->m_selectionEnd.handle(),d->m_endOffset);
03660 #ifndef KHTML_NO_CARET
03661         bool v = d->m_view->placeCaret();
03662         emitCaretPositionChanged(v ? d->caretNode() : 0, d->caretOffset());
03663 #endif
03664     }
03665 }
03666 
03667 void KHTMLPart::slotClearSelection()
03668 {
03669     bool hadSelection = hasSelection();
03670 #ifndef KHTML_NO_CARET
03671     //kdDebug(6000) << "d->m_selectionStart " << d->m_selectionStart.handle()
03672     //      << " d->m_selectionEnd " << d->m_selectionEnd.handle() << endl;
03673     // nothing, leave selection parameters as is
03674 #else
03675     d->m_selectionStart = 0;
03676     d->m_startOffset = 0;
03677     d->m_selectionEnd = 0;
03678     d->m_endOffset = 0;
03679 #endif
03680     if ( d->m_doc ) d->m_doc->clearSelection();
03681     if ( hadSelection )
03682       emitSelectionChanged();
03683 #ifndef KHTML_NO_CARET
03684     bool v = d->m_view->placeCaret();
03685     emitCaretPositionChanged(v ? d->caretNode() : 0, d->caretOffset());
03686 #endif
03687 }
03688 
03689 void KHTMLPart::resetHoverText()
03690 {
03691    if( !d->m_overURL.isEmpty() ) // Only if we were showing a link
03692    {
03693      d->m_overURL = d->m_overURLTarget = QString::null;
03694      emit onURL( QString::null );
03695      // revert to default statusbar text
03696      setStatusBarText(QString::null, BarHoverText);
03697      emit d->m_extension->mouseOverInfo(0);
03698   }
03699 }
03700 
03701 void KHTMLPart::overURL( const QString &url, const QString &target, bool /*shiftPressed*/ )
03702 {
03703   KURL u = completeURL(url);
03704 
03705   // special case for <a href="">
03706   if ( url.isEmpty() )
03707     u.setFileName( url );
03708 
03709   emit onURL( url );
03710 
03711   if ( url.isEmpty() ) {
03712     setStatusBarText(u.htmlURL(), BarHoverText);
03713     return;
03714   }
03715 
03716   if (url.find( QString::fromLatin1( "javascript:" ),0, false ) == 0 ) {
03717     QString jscode = KURL::decode_string( url.mid( url.find( "javascript:", 0, false ) ) );
03718     jscode = KStringHandler::rsqueeze( jscode, 80 ); // truncate if too long
03719     if (url.startsWith("javascript:window.open"))
03720       jscode += i18n(" (In new window)");
03721     setStatusBarText( QStyleSheet::escape( jscode ), BarHoverText );
03722     return;
03723   }
03724 
03725   KFileItem item(u, QString::null, KFileItem::Unknown);
03726   emit d->m_extension->mouseOverInfo(&item);
03727 
03728   QString com;
03729 
03730   KMimeType::Ptr typ = KMimeType::findByURL( u );
03731 
03732   if ( typ )
03733     com = typ->comment( u, false );
03734 
03735   if ( !u.isValid() ) {
03736     setStatusBarText(u.htmlURL(), BarHoverText);
03737     return;
03738   }
03739 
03740   if ( u.isLocalFile() )
03741   {
03742     // TODO : use KIO::stat() and create a KFileItem out of its result,
03743     // to use KFileItem::statusBarText()
03744     QCString path = QFile::encodeName( u.path() );
03745 
03746     struct stat buff;
03747     bool ok = !stat( path.data(), &buff );
03748 
03749     struct stat lbuff;
03750     if (ok) ok = !lstat( path.data(), &lbuff );
03751 
03752     QString text = u.htmlURL();
03753     QString text2 = text;
03754 
03755     if (ok && S_ISLNK( lbuff.st_mode ) )
03756     {
03757       QString tmp;
03758       if ( com.isNull() )
03759         tmp = i18n( "Symbolic Link");
03760       else
03761         tmp = i18n("%1 (Link)").arg(com);
03762       char buff_two[1024];
03763       text += " -> ";
03764       int n = readlink ( path.data(), buff_two, 1022);
03765       if (n == -1)
03766       {
03767         text2 += "  ";
03768         text2 += tmp;
03769         setStatusBarText(text2, BarHoverText);
03770         return;
03771       }
03772       buff_two[n] = 0;
03773 
03774       text += buff_two;
03775       text += "  ";
03776       text += tmp;
03777     }
03778     else if ( ok && S_ISREG( buff.st_mode ) )
03779     {
03780       if (buff.st_size < 1024)
03781         text = i18n("%2 (%1 bytes)").arg((long) buff.st_size).arg(text2); // always put the URL last, in case it contains '%'
03782       else
03783       {
03784         float d = (float) buff.st_size/1024.0;
03785         text = i18n("%2 (%1 K)").arg(KGlobal::locale()->formatNumber(d, 2)).arg(text2); // was %.2f
03786       }
03787       text += "  ";
03788       text += com;
03789     }
03790     else if ( ok && S_ISDIR( buff.st_mode ) )
03791     {
03792       text += "  ";
03793       text += com;
03794     }
03795     else
03796     {
03797       text += "  ";
03798       text += com;
03799     }
03800     setStatusBarText(text, BarHoverText);
03801   }
03802   else
03803   {
03804     QString extra;
03805     if (target.lower() == "_blank")
03806     {
03807       extra = i18n(" (In new window)");
03808     }
03809     else if (!target.isEmpty() &&
03810              (target.lower() != "_top") &&
03811              (target.lower() != "_self") &&
03812              (target.lower() != "_parent"))
03813     {
03814       KHTMLPart *p = this;
03815       while (p->parentPart())
03816           p = p->parentPart();
03817       if (!p->frameExists(target))
03818         extra = i18n(" (In new window)");
03819       else
03820         extra = i18n(" (In other frame)");
03821     }
03822 
03823     if (u.protocol() == QString::fromLatin1("mailto")) {
03824       QString mailtoMsg /* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
03825       mailtoMsg += i18n("Email to: ") + KURL::decode_string(u.path());
03826       QStringList queries = QStringList::split('&', u.query().mid(1));
03827       QStringList::Iterator it = queries.begin();
03828       const QStringList::Iterator itEnd = queries.end();
03829       for (; it != itEnd; ++it)
03830         if ((*it).startsWith(QString::fromLatin1("subject=")))
03831           mailtoMsg += i18n(" - Subject: ") + KURL::decode_string((*it).mid(8));
03832         else if ((*it).startsWith(QString::fromLatin1("cc=")))
03833           mailtoMsg += i18n(" - CC: ") + KURL::decode_string((*it).mid(3));
03834         else if ((*it).startsWith(QString::fromLatin1("bcc=")))
03835           mailtoMsg += i18n(" - BCC: ") + KURL::decode_string((*it).mid(4));
03836       mailtoMsg = QStyleSheet::escape(mailtoMsg);
03837       mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), QString::null);
03838       setStatusBarText("<qt>"+mailtoMsg, BarHoverText);
03839       return;
03840     }
03841    // Is this check necessary at all? (Frerich)
03842 #if 0
03843     else if (u.protocol() == QString::fromLatin1("http")) {
03844         DOM::Node hrefNode = nodeUnderMouse().parentNode();
03845         while (hrefNode.nodeName().string() != QString::fromLatin1("A") && !hrefNode.isNull())
03846           hrefNode = hrefNode.parentNode();
03847 
03848         if (!hrefNode.isNull()) {
03849           DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
03850           if (!hreflangNode.isNull()) {
03851             QString countryCode = hreflangNode.nodeValue().string().lower();
03852             // Map the language code to an appropriate country code.
03853             if (countryCode == QString::fromLatin1("en"))
03854               countryCode = QString::fromLatin1("gb");
03855             QString flagImg = QString::fromLatin1("<img src=%1>").arg(
03856                 locate("locale", QString::fromLatin1("l10n/")
03857                 + countryCode
03858                 + QString::fromLatin1("/flag.png")));
03859             emit setStatusBarText(flagImg + u.prettyURL() + extra);
03860           }
03861         }
03862       }
03863 #endif
03864     setStatusBarText(u.htmlURL() + extra, BarHoverText);
03865   }
03866 }
03867 
03868 //
03869 // This executes in the active part on a click or other url selection action in
03870 // that active part.
03871 //
03872 void KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target, KParts::URLArgs args )
03873 {
03874   // The member var is so that slotRedirection still calls the virtual urlSelected
03875   // but is able to know if is opened a url. KDE4: just make urlSelected return a bool
03876   // and move the urlSelectedIntern code back here.
03877   d->m_urlSelectedOpenedURL = urlSelectedIntern( url, button, state, _target, args );
03878 }
03879 
03880 // Return value: true if an url was opened, false if not (e.g. error, or jumping to anchor)
03881 bool KHTMLPart::urlSelectedIntern( const QString &url, int button, int state, const QString &_target, KParts::URLArgs args )
03882 {
03883   bool hasTarget = false;
03884 
03885   QString target = _target;
03886   if ( target.isEmpty() && d->m_doc )
03887     target = d->m_doc->baseTarget();
03888   if ( !target.isEmpty() )
03889       hasTarget = true;
03890 
03891   if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
03892   {
03893     crossFrameExecuteScript( target, KURL::decode_string( url.mid( 11 ) ) );
03894     return false;
03895   }
03896 
03897   KURL cURL = completeURL(url);
03898   // special case for <a href="">  (IE removes filename, mozilla doesn't)
03899   if ( url.isEmpty() )
03900     cURL.setFileName( url ); // removes filename
03901 
03902   if ( !cURL.isValid() )
03903     // ### ERROR HANDLING
03904     return false;
03905 
03906   kdDebug(6050) << this << " urlSelected: complete URL:" << cURL.url() << " target=" << target << endl;
03907 
03908   if ( state & ControlButton )
03909   {
03910     args.setNewTab(true);
03911     emit d->m_extension->createNewWindow( cURL, args );
03912     return true;
03913   }
03914 
03915   if ( button == LeftButton && ( state & ShiftButton ) )
03916   {
03917     KIO::MetaData metaData;
03918     metaData["referrer"] = d->m_referrer;
03919     KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), cURL, metaData );
03920     return false;
03921   }
03922 
03923   if (!checkLinkSecurity(cURL,
03924              i18n( "<qt>This untrusted page links to<BR><B>%1</B>.<BR>Do you want to follow the link?" ),
03925              i18n( "Follow" )))
03926     return false;
03927 
03928   args.frameName = target;
03929 
03930   args.metaData().insert("main_frame_request",
03931                          parentPart() == 0 ? "TRUE":"FALSE");
03932   args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
03933   args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
03934   args.metaData().insert("PropagateHttpHeader", "true");
03935   args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
03936   args.metaData().insert("ssl_activate_warnings", "TRUE");
03937 
03938   if ( hasTarget && target != "_self" && target != "_top" && target != "_blank" && target != "_parent" )
03939   {
03940     // unknown frame names should open in a new window.
03941     khtml::ChildFrame *frame = recursiveFrameRequest( this, cURL, args, false );
03942     if ( frame )
03943     {
03944       args.metaData()["referrer"] = d->m_referrer;
03945       requestObject( frame, cURL, args );
03946       return true;
03947     }
03948   }
03949 
03950   if (!d->m_referrer.isEmpty() && !args.metaData().contains("referrer"))
03951     args.metaData()["referrer"] = d->m_referrer;
03952 
03953 
03954   if ( button == NoButton && (state & ShiftButton) && (state & ControlButton) )
03955   {
03956     emit d->m_extension->createNewWindow( cURL, args );
03957     return true;
03958   }
03959 
03960   if ( state & ShiftButton)
03961   {
03962     KParts::WindowArgs winArgs;
03963     winArgs.lowerWindow = true;
03964     KParts::ReadOnlyPart *newPart = 0;
03965     emit d->m_extension->createNewWindow( cURL, args, winArgs, newPart );
03966     return true;
03967   }
03968 
03969   //If we're asked to open up an anchor in the current URL, in current window, 
03970   //merely gotoanchor, and do not reload the new page. Note that this does 
03971   //not apply if the URL is the same page, but without a ref
03972   if (cURL.hasRef() && (!hasTarget || target == "_self")) 
03973   {
03974     KURL curUrl = this->url();
03975     if (urlcmp(cURL.url(), curUrl.url(),
03976               false,  // ignore trailing / diff, IE does, even if FFox doesn't
03977               true))  // don't care if the ref changes!
03978     {
03979       m_url = cURL;
03980       emit d->m_extension->openURLNotify();      
03981       if ( !gotoAnchor( m_url.encodedHtmlRef()) )
03982         gotoAnchor( m_url.htmlRef() );
03983       emit d->m_extension->setLocationBarURL( m_url.prettyURL() );
03984       return false; // we jumped, but we didn't open a URL
03985     }
03986   }
03987 
03988   if ( !d->m_bComplete && !hasTarget )
03989     closeURL();
03990 
03991   view()->viewport()->unsetCursor();
03992   emit d->m_extension->openURLRequest( cURL, args );
03993   return true;
03994 }
03995 
03996 void KHTMLPart::slotViewDocumentSource()
03997 {
03998   KURL url(m_url);
03999   bool isTempFile = false;
04000   if (!(url.isLocalFile()) && KHTMLPageCache::self()->isComplete(d->m_cacheId))
04001   {
04002      KTempFile sourceFile(QString::null, defaultExtension());
04003      if (sourceFile.status() == 0)
04004      {
04005         KHTMLPageCache::self()->saveData(d->m_cacheId, sourceFile.dataStream());
04006         url = KURL();
04007         url.setPath(sourceFile.name());
04008         isTempFile = true;
04009      }
04010   }
04011 
04012   (void) KRun::runURL( url, QString::fromLatin1("text/plain"), isTempFile );
04013 }
04014 
04015 void KHTMLPart::slotViewPageInfo()
04016 {
04017   KHTMLInfoDlg *dlg = new KHTMLInfoDlg(NULL, "KHTML Page Info Dialog", false, WDestructiveClose);
04018   dlg->_close->setGuiItem(KStdGuiItem::close());
04019 
04020   if (d->m_doc)
04021      dlg->_title->setText(d->m_doc->title().string());
04022 
04023   // If it's a frame, set the caption to "Frame Information"
04024   if ( parentPart() && d->m_doc && d->m_doc->isHTMLDocument() ) {
04025      dlg->setCaption(i18n("Frame Information"));
04026   }
04027 
04028   QString editStr = QString::null;
04029 
04030   if (!d->m_pageServices.isEmpty())
04031     editStr = i18n("   <a href=\"%1\">[Properties]</a>").arg(d->m_pageServices);
04032 
04033   QString squeezedURL = KStringHandler::csqueeze( url().prettyURL(), 80 );
04034   dlg->_url->setText("<a href=\"" + url().url() + "\">" + squeezedURL + "</a>" + editStr);
04035   if (lastModified().isEmpty())
04036   {
04037     dlg->_lastModified->hide();
04038     dlg->_lmLabel->hide();
04039   }
04040   else
04041     dlg->_lastModified->setText(lastModified());
04042 
04043   const QString& enc = encoding();
04044   if (enc.isEmpty()) {
04045     dlg->_eLabel->hide();
04046     dlg->_encoding->hide();
04047   } else {
04048     dlg->_encoding->setText(enc);
04049   }
04050   /* populate the list view now */
04051   const QStringList headers = QStringList::split("\n", d->m_httpHeaders);
04052 
04053   QStringList::ConstIterator it = headers.begin();
04054   const QStringList::ConstIterator itEnd = headers.end();
04055 
04056   for (; it != itEnd; ++it) {
04057     const QStringList header = QStringList::split(QRegExp(":[ ]+"), *it);
04058     if (header.count() != 2)
04059        continue;
04060     new QListViewItem(dlg->_headers, header[0], header[1]);
04061   }
04062 
04063   dlg->show();
04064   /* put no code here */
04065 }
04066 
04067 
04068 void KHTMLPart::slotViewFrameSource()
04069 {
04070   KParts::ReadOnlyPart *frame = currentFrame();
04071   if ( !frame )
04072     return;
04073 
04074   KURL url = frame->url();
04075   bool isTempFile = false;
04076   if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
04077   {
04078        long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
04079 
04080        if (KHTMLPageCache::self()->isComplete(cacheId))
04081        {
04082            KTempFile sourceFile(QString::null, defaultExtension());
04083            if (sourceFile.status() == 0)
04084            {
04085                KHTMLPageCache::self()->saveData(cacheId, sourceFile.dataStream());
04086                url = KURL();
04087                url.setPath(sourceFile.name());
04088                isTempFile = true;
04089            }
04090      }
04091   }
04092 
04093   (void) KRun::runURL( url, QString::fromLatin1("text/plain"), isTempFile );
04094 }
04095 
04096 KURL KHTMLPart::backgroundURL() const
04097 {
04098   // ### what about XML documents? get from CSS?
04099   if (!d->m_doc || !d->m_doc->isHTMLDocument())
04100     return KURL();
04101 
04102   QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
04103 
04104   return KURL( m_url, relURL );
04105 }
04106 
04107 void KHTMLPart::slotSaveBackground()
04108 {
04109   KIO::MetaData metaData;
04110   metaData["referrer"] = d->m_referrer;
04111   KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save Background Image As"), backgroundURL(), metaData );
04112 }
04113 
04114 void KHTMLPart::slotSaveDocument()
04115 {
04116   KURL srcURL( m_url );
04117 
04118   if ( srcURL.fileName(false).isEmpty() )
04119     srcURL.setFileName( "index" + defaultExtension() );
04120 
04121   KIO::MetaData metaData;
04122   // Referre unknown?
04123   KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, "text/html", d->m_cacheId );
04124 }
04125 
04126 void KHTMLPart::slotSecurity()
04127 {
04128 //   kdDebug( 6050 ) << "Meta Data:" << endl
04129 //                   << d->m_ssl_peer_cert_subject
04130 //                   << endl
04131 //                   << d->m_ssl_peer_cert_issuer
04132 //                   << endl
04133 //                   << d->m_ssl_cipher
04134 //                   << endl
04135 //                   << d->m_ssl_cipher_desc
04136 //                   << endl
04137 //                   << d->m_ssl_cipher_version
04138 //                   << endl
04139 //                   << d->m_ssl_good_from
04140 //                   << endl
04141 //                   << d->m_ssl_good_until
04142 //                   << endl
04143 //                   << d->m_ssl_cert_state
04144 //                   << endl;
04145 
04146   KSSLInfoDlg *kid = new KSSLInfoDlg(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
04147 
04148   if (d->m_bSecurityInQuestion)
04149       kid->setSecurityInQuestion(true);
04150 
04151   if (d->m_ssl_in_use) {
04152     KSSLCertificate *x = KSSLCertificate::fromString(d->m_ssl_peer_certificate.local8Bit());
04153     if (x) {
04154        // Set the chain back onto the certificate
04155        const QStringList cl = QStringList::split(QString("\n"), d->m_ssl_peer_chain);
04156        QPtrList<KSSLCertificate> ncl;
04157 
04158        ncl.setAutoDelete(true);
04159        QStringList::ConstIterator it = cl.begin();
04160        const QStringList::ConstIterator itEnd = cl.end();
04161        for (; it != itEnd; ++it) {
04162           KSSLCertificate* const y = KSSLCertificate::fromString((*it).local8Bit());
04163           if (y) ncl.append(y);
04164        }
04165 
04166        if (ncl.count() > 0)
04167           x->chain().setChain(ncl);
04168 
04169        kid->setup(x,
04170                   d->m_ssl_peer_ip,
04171                   m_url.url(),
04172                   d->m_ssl_cipher,
04173                   d->m_ssl_cipher_desc,
04174                   d->m_ssl_cipher_version,
04175                   d->m_ssl_cipher_used_bits.toInt(),
04176                   d->m_ssl_cipher_bits.toInt(),
04177                   (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt()
04178                   );
04179         kid->exec();
04180         delete x;
04181      } else kid->exec();
04182   } else kid->exec();
04183 }
04184 
04185 void KHTMLPart::slotSaveFrame()
04186 {
04187     KParts::ReadOnlyPart *frame = currentFrame();
04188     if ( !frame )
04189         return;
04190 
04191     KURL srcURL( frame->url() );
04192 
04193     if ( srcURL.fileName(false).isEmpty() )
04194         srcURL.setFileName( "index" + defaultExtension() );
04195 
04196     KIO::MetaData metaData;
04197     // Referrer unknown?
04198     KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save Frame As" ), srcURL, metaData, "text/html" );
04199 }
04200 
04201 void KHTMLPart::slotSetEncoding()
04202 {
04203   d->m_automaticDetection->setItemChecked( int( d->m_autoDetectLanguage ), false );
04204   d->m_paSetEncoding->popupMenu()->setItemChecked( 0, false );
04205   d->m_paSetEncoding->popupMenu()->setItemChecked( d->m_paSetEncoding->popupMenu()->idAt( 2 ), true );
04206 
04207   QString enc = KGlobal::charsets()->encodingForName( d->m_manualDetection->currentText() );
04208   setEncoding( enc, true );
04209 }
04210 
04211 void KHTMLPart::slotUseStylesheet()
04212 {
04213   if (d->m_doc)
04214   {
04215     bool autoselect = (d->m_paUseStylesheet->currentItem() == 0);
04216     d->m_sheetUsed = autoselect ? QString() : d->m_paUseStylesheet->currentText();
04217     d->m_doc->updateStyleSelector();
04218   }
04219 }
04220 
04221 void KHTMLPart::updateActions()
04222 {
04223   bool frames = false;
04224 
04225   QValueList<khtml::ChildFrame*>::ConstIterator it = d->m_frames.begin();
04226   const QValueList<khtml::ChildFrame*>::ConstIterator end = d->m_frames.end();
04227   for (; it != end; ++it )
04228       if ( (*it)->m_type == khtml::ChildFrame::Frame )
04229       {
04230           frames = true;
04231           break;
04232       }
04233 
04234   d->m_paViewFrame->setEnabled( frames );
04235   d->m_paSaveFrame->setEnabled( frames );
04236 
04237   if ( frames )
04238     d->m_paFind->setText( i18n( "&Find in Frame..." ) );
04239   else
04240     d->m_paFind->setText( i18n( "&Find..." ) );
04241 
04242   KParts::Part *frame = 0;
04243 
04244   if ( frames )
04245     frame = currentFrame();
04246 
04247   bool enableFindAndSelectAll = true;
04248 
04249   if ( frame )
04250     enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
04251 
04252   d->m_paFind->setEnabled( enableFindAndSelectAll );
04253   d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
04254 
04255   bool enablePrintFrame = false;
04256 
04257   if ( frame )
04258   {
04259     QObject *ext = KParts::BrowserExtension::childObject( frame );
04260     if ( ext )
04261       enablePrintFrame = ext->metaObject()->slotNames().contains( "print()" );
04262   }
04263 
04264   d->m_paPrintFrame->setEnabled( enablePrintFrame );
04265 
04266   QString bgURL;
04267 
04268   // ### frames
04269   if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
04270     bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
04271 
04272   d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
04273 
04274   if ( d->m_paDebugScript )
04275     d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
04276 }
04277 
04278 KParts::LiveConnectExtension *KHTMLPart::liveConnectExtension( const khtml::RenderPart *frame) const {
04279     const ConstFrameIt end = d->m_objects.end();
04280     for(ConstFrameIt it = d->m_objects.begin(); it != end; ++it )
04281         if ((*it)->m_frame == frame)
04282             return (*it)->m_liveconnect;
04283     return 0L;
04284 }
04285 
04286 bool KHTMLPart::requestFrame( khtml::RenderPart *frame, const QString &url, const QString &frameName,
04287                               const QStringList &params, bool isIFrame )
04288 {
04289   //kdDebug( 6050 ) << this << " requestFrame( ..., " << url << ", " << frameName << " )" << endl;
04290   FrameIt it = d->m_frames.find( frameName );
04291   if ( it == d->m_frames.end() )
04292   {
04293     khtml::ChildFrame * child = new khtml::ChildFrame;
04294     //kdDebug( 6050 ) << "inserting new frame into frame map " << frameName << endl;
04295     child->m_name = frameName;
04296     it = d->m_frames.append( child );
04297   }
04298 
04299   (*it)->m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
04300   (*it)->m_frame = frame;
04301   (*it)->m_params = params;
04302 
04303   // Support for <frame src="javascript:string">
04304   if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
04305   {
04306       QVariant res = executeScript( DOM::Node(frame->element()), KURL::decode_string( url.right( url.length() - 11) ) );
04307       KURL myurl;
04308       myurl.setProtocol("javascript");
04309       if ( res.type() == QVariant::String )
04310     myurl.setPath(res.asString());
04311       return processObjectRequest(*it, myurl, QString("text/html") );
04312   }
04313   KURL u = url.isEmpty() ? KURL() : completeURL( url );
04314   return requestObject( *it, u );
04315 }
04316 
04317 QString KHTMLPart::requestFrameName()
04318 {
04319    return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
04320 }
04321 
04322 bool KHTMLPart::requestObject( khtml::RenderPart *frame, const QString &url, const QString &serviceType,
04323                                const QStringList &params )
04324 {
04325   //kdDebug( 6005 ) << "KHTMLPart::requestObject " << this << " frame=" << frame << endl;
04326   khtml::ChildFrame *child = new khtml::ChildFrame;
04327   FrameIt it = d->m_objects.append( child );
04328   (*it)->m_frame = frame;
04329   (*it)->m_type = khtml::ChildFrame::Object;
04330   (*it)->m_params = params;
04331 
04332   KParts::URLArgs args;
04333   args.serviceType = serviceType;
04334   if (!requestObject( *it, completeURL( url ), args ) && !(*it)->m_run) {
04335       (*it)->m_bCompleted = true;
04336       return false;
04337   }
04338   return true;
04339 }
04340 
04341 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KURL &url, const KParts::URLArgs &_args )
04342 {
04343   if (!checkLinkSecurity(url))
04344   {
04345     kdDebug(6005) << this << " KHTMLPart::requestObject checkLinkSecurity refused" << endl;
04346     return false;
04347   }
04348   if ( child->m_bPreloaded )
04349   {
04350     kdDebug(6005) << "KHTMLPart::requestObject preload" << endl;
04351     if ( child->m_frame && child->m_part )
04352       child->m_frame->setWidget( child->m_part->widget() );
04353 
04354     child->m_bPreloaded = false;
04355     return true;
04356   }
04357 
04358   //kdDebug(6005) << "KHTMLPart::requestObject child=" << child << " child->m_part=" << child->m_part << endl;
04359 
04360   KParts::URLArgs args( _args );
04361 
04362   if ( child->m_run )
04363     child->m_run->abort();
04364 
04365   if ( child->m_part && !args.reload && urlcmp( child->m_part->url().url(), url.url(), true, true ) )
04366     args.serviceType = child->m_serviceType;
04367 
04368   child->m_args = args;
04369   child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload);
04370   child->m_serviceName = QString::null;
04371   if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
04372     child->m_args.metaData()["referrer"] = d->m_referrer;
04373 
04374   child->m_args.metaData().insert("PropagateHttpHeader", "true");
04375   child->m_args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
04376   child->m_args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
04377   child->m_args.metaData().insert("main_frame_request",
04378                                   parentPart() == 0 ? "TRUE":"FALSE");
04379   child->m_args.metaData().insert("ssl_was_in_use",
04380                                   d->m_ssl_in_use ? "TRUE":"FALSE");
04381   child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
04382   child->m_args.metaData().insert("cross-domain", toplevelURL().url());
04383 
04384   // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
04385   if ((url.isEmpty() || url.url() == "about:blank") && args.serviceType.isEmpty())
04386     args.serviceType = QString::fromLatin1( "text/html" );
04387 
04388   if ( args.serviceType.isEmpty() ) {
04389     kdDebug(6050) << "Running new KHTMLRun for " << this << " and child=" << child << endl;
04390     child->m_run = new KHTMLRun( this, child, url, child->m_args, true );
04391     d->m_bComplete = false; // ensures we stop it in checkCompleted...
04392     return false;
04393   } else {
04394     return processObjectRequest( child, url, args.serviceType );
04395   }
04396 }
04397 
04398 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KURL &_url, const QString &mimetype )
04399 {
04400   //kdDebug( 6050 ) << "KHTMLPart::processObjectRequest trying to create part for " << mimetype << endl;
04401 
04402   // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
04403   // by an emitting frame part (emit openURLRequest( blahurl, ... ) . A few lines below we delete the part
04404   // though -> the reference becomes invalid -> crash is likely
04405   KURL url( _url );
04406 
04407   // khtmlrun called us this way to indicate a loading error
04408   if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
04409   {
04410       child->m_bCompleted = true;
04411       checkCompleted();
04412       return true;
04413   }
04414 
04415   if (child->m_bNotify)
04416   {
04417       child->m_bNotify = false;
04418       if ( !child->m_args.lockHistory() )
04419           emit d->m_extension->openURLNotify();
04420   }
04421 
04422   if ( child->m_serviceType != mimetype || !child->m_part )
04423   {
04424     // Before attempting to load a part, check if the user wants that.
04425     // Many don't like getting ZIP files embedded.
04426     // However we don't want to ask for flash and other plugin things..
04427     if ( child->m_type != khtml::ChildFrame::Object )
04428     {
04429       QString suggestedFilename;
04430       if ( child->m_run )
04431         suggestedFilename = child->m_run->suggestedFilename();
04432 
04433       KParts::BrowserRun::AskSaveResult res = KParts::BrowserRun::askEmbedOrSave(
04434         url, mimetype, suggestedFilename  );
04435       switch( res ) {
04436       case KParts::BrowserRun::Save:
04437         KHTMLPopupGUIClient::saveURL( widget(), i18n( "Save As" ), url, child->m_args.metaData(), QString::null, 0, suggestedFilename);
04438         // fall-through
04439       case KParts::BrowserRun::Cancel:
04440         child->m_bCompleted = true;
04441         checkCompleted();
04442         return true; // done
04443       default: // Open
04444         break;
04445       }
04446     }
04447 
04448     QStringList dummy; // the list of servicetypes handled by the part is now unused.
04449     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 );
04450 
04451     if ( !part )
04452     {
04453         if ( child->m_frame )
04454           if (child->m_frame->partLoadingErrorNotify( child, url, mimetype ))
04455             return true; // we succeeded after all (a fallback was used)
04456 
04457         checkEmitLoadEvent();
04458         return false;
04459     }
04460 
04461     //CRITICAL STUFF
04462     if ( child->m_part )
04463     {
04464       if (!::qt_cast<KHTMLPart*>(child->m_part) && child->m_jscript)
04465           child->m_jscript->clear();
04466       partManager()->removePart( (KParts::ReadOnlyPart *)child->m_part );
04467       delete (KParts::ReadOnlyPart *)child->m_part;
04468       if (child->m_liveconnect) {
04469         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 &)));
04470         child->m_liveconnect = 0L;
04471       }
04472     }
04473 
04474     child->m_serviceType = mimetype;
04475     if ( child->m_frame )
04476       child->m_frame->setWidget( part->widget() );
04477 
04478     if ( child->m_type != khtml::ChildFrame::Object )
04479       partManager()->addPart( part, false );
04480 //  else
04481 //      kdDebug(6005) << "AH! NO FRAME!!!!!" << endl;
04482 
04483     child->m_part = part;
04484 
04485     if (::qt_cast<KHTMLPart*>(part)) {
04486       static_cast<KHTMLPart*>(part)->d->m_frame = child;
04487     } else if (child->m_frame) {
04488       child->m_liveconnect = KParts::LiveConnectExtension::childObject(part);
04489       if (child->m_liveconnect)
04490         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 &)));
04491     }
04492     KParts::StatusBarExtension *sb = KParts::StatusBarExtension::childObject(part);
04493     if (sb)
04494       sb->setStatusBar( d->m_statusBarExtension->statusBar() );
04495 
04496     connect( part, SIGNAL( started( KIO::Job *) ),
04497              this, SLOT( slotChildStarted( KIO::Job *) ) );
04498     connect( part, SIGNAL( completed() ),
04499              this, SLOT( slotChildCompleted() ) );
04500     connect( part, SIGNAL( completed(bool) ),
04501              this, SLOT( slotChildCompleted(bool) ) );
04502     connect( part, SIGNAL( setStatusBarText( const QString & ) ),
04503                 this, SIGNAL( setStatusBarText( const QString & ) ) );
04504     if ( part->inherits( "KHTMLPart" ) )
04505     {
04506       connect( this, SIGNAL( completed() ),
04507                part, SLOT( slotParentCompleted() ) );
04508       connect( this, SIGNAL( completed(bool) ),
04509                part, SLOT( slotParentCompleted() ) );
04510       // As soon as the child's document is created, we need to set its domain
04511       // (but we do so only once, so it can't be simply done in the child)
04512       connect( part, SIGNAL( docCreated() ),
04513                this, SLOT( slotChildDocCreated() ) );
04514     }
04515 
04516     child->m_extension = KParts::BrowserExtension::childObject( part );
04517 
04518     if ( child->m_extension )
04519     {
04520       connect( child->m_extension, SIGNAL( openURLNotify() ),
04521                d->m_extension, SIGNAL( openURLNotify() ) );
04522 
04523       connect( child->m_extension, SIGNAL( openURLRequestDelayed( const KURL &, const KParts::URLArgs & ) ),
04524                this, SLOT( slotChildURLRequest( const KURL &, const KParts::URLArgs & ) ) );
04525 
04526       connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ),
04527                d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & ) ) );
04528       connect( child->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs &, const KParts::WindowArgs &, KParts::ReadOnlyPart *& ) ),
04529                d->m_extension, SIGNAL( createNewWindow( const KURL &, const KParts::URLArgs & , const KParts::WindowArgs &, KParts::ReadOnlyPart *&) ) );
04530 
04531       connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ),
04532                d->m_extension, SIGNAL( popupMenu( const QPoint &, const KFileItemList & ) ) );
04533       connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ),
04534                d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList & ) ) );
04535       connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList &, const KParts::URLArgs &, KParts::BrowserExtension::PopupFlags ) ),
04536                d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KFileItemList &, const KParts::URLArgs &, KParts::BrowserExtension::PopupFlags ) ) );
04537       connect( child->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ),
04538                d->m_extension, SIGNAL( popupMenu( const QPoint &, const KURL &, const QString &, mode_t ) ) );
04539       connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ),
04540                d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const QString &, mode_t ) ) );
04541       connect( child->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const KParts::URLArgs &, KParts::BrowserExtension::PopupFlags, mode_t ) ),
04542                d->m_extension, SIGNAL( popupMenu( KXMLGUIClient *, const QPoint &, const KURL &, const KParts::URLArgs &, KParts::BrowserExtension::PopupFlags, mode_t ) ) );
04543 
04544       connect( child->m_extension, SIGNAL( infoMessage( const QString & ) ),
04545                d->m_extension, SIGNAL( infoMessage( const QString & ) ) );
04546 
04547       connect( child->m_extension, SIGNAL( requestFocus( KParts::ReadOnlyPart * ) ),
04548                this, SLOT( slotRequestFocus( KParts::ReadOnlyPart * ) ) );
04549 
04550       child->m_extension->setBrowserInterface( d->m_extension->browserInterface() );
04551     }
04552   }
04553   else if ( child->m_frame && child->m_part &&
04554             child->m_frame->widget() != child->m_part->widget() )
04555     child->m_frame->setWidget( child->m_part->widget() );
04556 
04557   checkEmitLoadEvent();
04558   // Some JS code in the load event may have destroyed the part
04559   // In that case, abort
04560   if ( !child->m_part )
04561     return false;
04562 
04563   if ( child->m_bPreloaded )
04564   {
04565     if ( child->m_frame && child->m_part )
04566       child->m_frame->setWidget( child->m_part->widget() );
04567 
04568     child->m_bPreloaded = false;
04569     return true;
04570   }
04571 
04572   child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload);
04573 
04574   // make sure the part has a way to find out about the mimetype.
04575   // we actually set it in child->m_args in requestObject already,
04576   // but it's useless if we had to use a KHTMLRun instance, as the
04577   // point the run object is to find out exactly the mimetype.
04578   child->m_args.serviceType = mimetype;
04579 
04580   // if not a frame set child as completed
04581   child->m_bCompleted = child->m_type == khtml::ChildFrame::Object;
04582 
04583   if ( child->m_extension )
04584     child->m_extension->setURLArgs( child->m_args );
04585 
04586   if(url.protocol() == "javascript" || url.url() == "about:blank") {
04587       if (!child->m_part->inherits("KHTMLPart"))
04588           return false;
04589 
04590       KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(child->m_part));
04591 
04592       p->begin();
04593       if (d->m_doc && p->d->m_doc)
04594         p->d->m_doc->setBaseURL(d->m_doc->baseURL());
04595       if (!url.url().startsWith("about:")) {
04596         p->write(url.path());
04597       } else {
04598     p->m_url = url;
04599         // we need a body element. testcase: <iframe id="a"></iframe><script>alert(a.document.body);</script>
04600         p->write("<HTML><TITLE></TITLE><BODY></BODY></HTML>");
04601       }
04602       p->end();
04603       return true;
04604   }
04605   else if ( !url.isEmpty() )
04606   {
04607       //kdDebug( 6050 ) << "opening " << url.url() << " in frame " << child->m_part << endl;
04608       bool b = child->m_part->openURL( url );
04609       if (child->m_bCompleted)
04610           checkCompleted();
04611       return b;
04612   }
04613   else
04614   {
04615       child->m_bCompleted = true;
04616       checkCompleted();
04617       return true;
04618   }
04619 }
04620 
04621 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget, const char *widgetName,
04622                                              QObject *parent, const char *name, const QString &mimetype,
04623                                              QString &serviceName, QStringList &serviceTypes,
04624                                              const QStringList &params )
04625 {
04626   QString constr;
04627   if ( !serviceName.isEmpty() )
04628     constr.append( QString::fromLatin1( "Name == '%1'" ).arg( serviceName ) );
04629 
04630   KTrader::OfferList offers = KTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr, QString::null );
04631 
04632   if ( offers.isEmpty() ) {
04633     int pos = mimetype.find( "-plugin" );
04634     if (pos < 0)
04635         return 0L;
04636     QString stripped_mime = mimetype.left( pos );
04637     offers = KTrader::self()->query( stripped_mime, "KParts/ReadOnlyPart", constr, QString::null );
04638     if ( offers.isEmpty() )
04639         return 0L;
04640   }
04641 
04642   KTrader::OfferList::ConstIterator it = offers.begin();
04643   const KTrader::OfferList::ConstIterator itEnd = offers.end();
04644   for ( ; it != itEnd; ++it )
04645   {
04646     KService::Ptr service = (*it);
04647 
04648     KLibFactory* const factory = KLibLoader::self()->factory( QFile::encodeName(service->library()) );
04649     if ( factory ) {
04650       KParts::ReadOnlyPart *res = 0L;
04651 
04652       const char *className = "KParts::ReadOnlyPart";
04653       if ( service->serviceTypes().contains( "Browser/View" ) )
04654         className = "Browser/View";
04655 
04656       if ( factory->inherits( "KParts::Factory" ) )
04657         res = static_cast<KParts::ReadOnlyPart *>(static_cast<KParts::Factory *>( factory )->createPart( parentWidget, widgetName, parent, name, className, params ));
04658       else
04659         res = static_cast<KParts::ReadOnlyPart *>(factory->create( parentWidget, widgetName, className ));
04660 
04661       if ( res ) {
04662         serviceTypes = service->serviceTypes();
04663         serviceName = service->name();
04664         return res;
04665       }
04666     } else {
04667       // TODO KMessageBox::error and i18n, like in KonqFactory::createView?
04668       kdWarning() << QString("There was an error loading the module %1.\nThe diagnostics is:\n%2")
04669                       .arg(service->name()).arg(KLibLoader::self()->lastErrorMessage()) << endl;
04670     }
04671   }
04672   return 0;
04673 }
04674 
04675 KParts::PartManager *KHTMLPart::partManager()
04676 {
04677   if ( !d->m_manager && d->m_view )
04678   {
04679     d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this, "khtml part manager" );
04680     d->m_manager->setAllowNestedParts( true );
04681     connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ),
04682              this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) );
04683     connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ),
04684              this, SLOT( slotPartRemoved( KParts::Part * ) ) );
04685   }
04686 
04687   return d->m_manager;
04688 }
04689 
04690 void KHTMLPart::submitFormAgain()
04691 {
04692   disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
04693   if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
04694     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 );
04695 
04696   delete d->m_submitForm;
04697   d->m_submitForm = 0;
04698 }
04699 
04700 void KHTMLPart::submitFormProxy( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
04701 {
04702   submitForm(action, url, formData, _target, contentType, boundary);
04703 }
04704 
04705 void KHTMLPart::submitForm( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
04706 {
04707   kdDebug(6000) << this << ": KHTMLPart::submitForm target=" << _target << " url=" << url << endl;
04708   if (d->m_formNotification == KHTMLPart::Only) {
04709     emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
04710     return;
04711   } else if (d->m_formNotification == KHTMLPart::Before) {
04712     emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
04713   }
04714 
04715   KURL u = completeURL( url );
04716 
04717   if ( !u.isValid() )
04718   {
04719     // ### ERROR HANDLING!
04720     return;
04721   }
04722 
04723   // Form security checks
04724   //
04725   /*
04726    * If these form security checks are still in this place in a month or two
04727    * I'm going to simply delete them.
04728    */
04729 
04730   /* This is separate for a reason.  It has to be _before_ all script, etc,
04731    * AND I don't want to break anything that uses checkLinkSecurity() in
04732    * other places.
04733    */
04734 
04735   if (!d->m_submitForm) {
04736     if (u.protocol() != "https" && u.protocol() != "mailto") {
04737       if (d->m_ssl_in_use) {    // Going from SSL -> nonSSL
04738         int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning:  This is a secure form but it is attempting to send your data back unencrypted."
04739                                                                "\nA third party may be able to intercept and view this information."
04740                                                                "\nAre you sure you wish to continue?"),
04741                                                     i18n("Network Transmission"),KGuiItem(i18n("&Send Unencrypted")));
04742         if (rc == KMessageBox::Cancel)
04743           return;
04744       } else {                  // Going from nonSSL -> nonSSL
04745         KSSLSettings kss(true);
04746         if (kss.warnOnUnencrypted()) {
04747           int rc = KMessageBox::warningContinueCancel(NULL,
04748                                                       i18n("Warning: Your data is about to be transmitted across the network unencrypted."
04749                                                            "\nAre you sure you wish to continue?"),
04750                                                       i18n("Network Transmission"),
04751                                                       KGuiItem(i18n("&Send Unencrypted")),
04752                                                       "WarnOnUnencryptedForm");
04753           // Move this setting into KSSL instead
04754           KConfig *config = kapp->config();
04755           QString grpNotifMsgs = QString::fromLatin1("Notification Messages");
04756           KConfigGroupSaver saver( config, grpNotifMsgs );
04757 
04758           if (!config->readBoolEntry("WarnOnUnencryptedForm", true)) {
04759             config->deleteEntry("WarnOnUnencryptedForm");
04760             config->sync();
04761             kss.setWarnOnUnencrypted(false);
04762             kss.save();
04763           }
04764           if (rc == KMessageBox::Cancel)
04765             return;
04766         }
04767       }
04768     }
04769 
04770     if (u.protocol() == "mailto") {
04771       int rc = KMessageBox::warningContinueCancel(NULL,
04772                                                   i18n("This site is attempting to submit form data via email.\n"
04773                                                        "Do you want to continue?"),
04774                                                   i18n("Network Transmission"),
04775                                                   KGuiItem(i18n("&Send Email")),
04776                                                   "WarnTriedEmailSubmit");
04777 
04778       if (rc == KMessageBox::Cancel) {
04779         return;
04780       }
04781     }
04782   }
04783 
04784   // End form security checks
04785   //
04786 
04787   QString urlstring = u.url();
04788 
04789   if ( urlstring.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
04790     urlstring = KURL::decode_string(urlstring);
04791     crossFrameExecuteScript( _target, urlstring.right( urlstring.length() - 11) );
04792     return;
04793   }
04794 
04795   if (!checkLinkSecurity(u,
04796              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?" ),
04797              i18n( "Submit" )))
04798     return;
04799 
04800   KParts::URLArgs args;
04801 
04802   if (!d->m_referrer.isEmpty())
04803      args.metaData()["referrer"] = d->m_referrer;
04804 
04805   args.metaData().insert("PropagateHttpHeader", "true");
04806   args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
04807   args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
04808   args.metaData().insert("main_frame_request",
04809                          parentPart() == 0 ? "TRUE":"FALSE");
04810   args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
04811   args.metaData().insert("ssl_activate_warnings", "TRUE");
04812 //WABA: When we post a form we should treat it as the main url
04813 //the request should never be considered cross-domain
04814 //args.metaData().insert("cross-domain", toplevelURL().url());
04815   args.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
04816 
04817   // Handle mailto: forms
04818   if (u.protocol() == "mailto") {
04819       // 1)  Check for attach= and strip it
04820       QString q = u.query().mid(1);
04821       QStringList nvps = QStringList::split("&", q);
04822       bool triedToAttach = false;
04823 
04824       QStringList::Iterator nvp = nvps.begin();
04825       const QStringList::Iterator nvpEnd = nvps.end();
04826 
04827 // cannot be a for loop as if something is removed we don't want to do ++nvp, as
04828 // remove returns an iterator pointing to the next item
04829 
04830       while (nvp != nvpEnd) {
04831          const QStringList pair = QStringList::split("=", *nvp);
04832          if (pair.count() >= 2) {
04833             if (pair.first().lower() == "attach") {
04834                nvp = nvps.remove(nvp);
04835                triedToAttach = true;
04836             } else {
04837                ++nvp;
04838             }
04839          } else {
04840             ++nvp;
04841          }
04842       }
04843 
04844       if (triedToAttach)
04845          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");
04846 
04847       // 2)  Append body=
04848       QString bodyEnc;
04849       if (contentType.lower() == "multipart/form-data") {
04850          // FIXME: is this correct?  I suspect not
04851          bodyEnc = KURL::encode_string(QString::fromLatin1(formData.data(),
04852                                                            formData.size()));
04853       } else if (contentType.lower() == "text/plain") {
04854          // Convention seems to be to decode, and s/&/\n/
04855          QString tmpbody = QString::fromLatin1(formData.data(),
04856                                                formData.size());
04857          tmpbody.replace(QRegExp("[&]"), "\n");
04858          tmpbody.replace(QRegExp("[+]"), " ");
04859          tmpbody = KURL::decode_string(tmpbody);  // Decode the rest of it
04860          bodyEnc = KURL::encode_string(tmpbody);  // Recode for the URL
04861       } else {
04862          bodyEnc = KURL::encode_string(QString::fromLatin1(formData.data(),
04863                                                            formData.size()));
04864       }
04865 
04866       nvps.append(QString("body=%1").arg(bodyEnc));
04867       q = nvps.join("&");
04868       u.setQuery(q);
04869   }
04870 
04871   if ( strcmp( action, "get" ) == 0 ) {
04872     if (u.protocol() != "mailto")
04873        u.setQuery( QString::fromLatin1( formData.data(), formData.size() ) );
04874     args.setDoPost( false );
04875   }
04876   else {
04877     args.postData = formData;
04878     args.setDoPost( true );
04879 
04880     // construct some user headers if necessary
04881     if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
04882       args.setContentType( "Content-Type: application/x-www-form-urlencoded" );
04883     else // contentType must be "multipart/form-data"
04884       args.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
04885   }
04886 
04887   if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
04888     if( d->m_submitForm ) {
04889       kdDebug(6000) << "KHTMLPart::submitForm ABORTING!" << endl;
04890       return;
04891     }
04892     d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
04893     d->m_submitForm->submitAction = action;
04894     d->m_submitForm->submitUrl = url;
04895     d->m_submitForm->submitFormData = formData;
04896     d->m_submitForm->target = _target;
04897     d->m_submitForm->submitContentType = contentType;
04898     d->m_submitForm->submitBoundary = boundary;
04899     connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
04900   }
04901   else
04902   {
04903     emit d->m_extension->openURLRequest( u, args );
04904   }
04905 }
04906 
04907 void KHTMLPart::popupMenu( const QString &linkUrl )
04908 {
04909   KURL popupURL;
04910   KURL linkKURL;
04911   KParts::URLArgs args;
04912   QString referrer;
04913   KParts::BrowserExtension::PopupFlags itemflags=KParts::BrowserExtension::ShowBookmark | KParts::BrowserExtension::ShowReload;
04914 
04915   if ( linkUrl.isEmpty() ) { // click on background
04916     KHTMLPart* khtmlPart = this;
04917     while ( khtmlPart->parentPart() )
04918     {
04919       khtmlPart=khtmlPart->parentPart();
04920     }
04921     popupURL = khtmlPart->url();
04922     referrer = khtmlPart->pageReferrer();
04923     if (hasSelection())
04924       itemflags = KParts::BrowserExtension::ShowTextSelectionItems;
04925     else
04926       itemflags |= KParts::BrowserExtension::ShowNavigationItems;
04927   } else {               // click on link
04928     popupURL = completeURL( linkUrl );
04929     linkKURL = popupURL;
04930     referrer = this->referrer();
04931 
04932     if (!(d->m_strSelectedURLTarget).isEmpty() &&
04933            (d->m_strSelectedURLTarget.lower() != "_top") &&
04934            (d->m_strSelectedURLTarget.lower() != "_self") &&
04935        (d->m_strSelectedURLTarget.lower() != "_parent")) {
04936       if (d->m_strSelectedURLTarget.lower() == "_blank")
04937         args.setForcesNewWindow(true);
04938       else {
04939     KHTMLPart *p = this;
04940     while (p->parentPart())
04941       p = p->parentPart();
04942     if (!p->frameExists(d->m_strSelectedURLTarget))
04943           args.setForcesNewWindow(true);
04944       }
04945     }
04946   }
04947 
04948   // Danger, Will Robinson. The Popup might stay around for a much
04949   // longer time than KHTMLPart. Deal with it.
04950   KHTMLPopupGUIClient* client = new KHTMLPopupGUIClient( this, d->m_popupMenuXML, linkKURL );
04951   QGuardedPtr<QObject> guard( client );
04952 
04953   QString mimetype = QString::fromLatin1( "text/html" );
04954   args.metaData()["referrer"] = referrer;
04955 
04956   if (!linkUrl.isEmpty())               // over a link
04957   {
04958     if (popupURL.isLocalFile())             // safe to do this
04959     {
04960       mimetype = KMimeType::findByURL(popupURL,0,true,false)->name();
04961     }
04962     else                        // look at "extension" of link
04963     {
04964       const QString fname(popupURL.fileName(false));
04965       if (!fname.isEmpty() && !popupURL.hasRef() && popupURL.query().isEmpty())
04966       {
04967         KMimeType::Ptr pmt = KMimeType::findByPath(fname,0,true);
04968 
04969         // Further check for mime types guessed from the extension which,
04970         // on a web page, are more likely to be a script delivering content
04971         // of undecidable type. If the mime type from the extension is one
04972         // of these, don't use it.  Retain the original type 'text/html'.
04973         if (pmt->name() != KMimeType::defaultMimeType() &&
04974             !pmt->is("application/x-perl") &&
04975             !pmt->is("application/x-perl-module") &&
04976             !pmt->is("application/x-php") &&
04977             !pmt->is("application/x-python-bytecode") &&
04978             !pmt->is("application/x-python") &&
04979             !pmt->is("application/x-shellscript"))
04980           mimetype = pmt->name();
04981       }
04982     }
04983   }
04984 
04985   args.serviceType = mimetype;
04986 
04987   emit d->m_extension->popupMenu( client, QCursor::pos(), popupURL, args, itemflags, S_IFREG /*always a file*/);
04988 
04989   if ( !guard.isNull() ) {
04990      delete client;
04991      emit popupMenu(linkUrl, QCursor::pos());
04992      d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
04993   }
04994 }
04995 
04996 void KHTMLPart::slotParentCompleted()
04997 {
04998   //kdDebug(6050) << this << " slotParentCompleted()" << endl;
04999   if ( !d->m_redirectURL.isEmpty() && !d->m_redirectionTimer.isActive() )
05000   {
05001     //kdDebug(6050) << this << ": starting timer for child redirection -> " << d->m_redirectURL << endl;
05002     d->m_redirectionTimer.start( 1000 * d->m_delayRedirect, true );
05003   }
05004 }
05005 
05006 void KHTMLPart::slotChildStarted( KIO::Job *job )
05007 {
05008   khtml::ChildFrame *child = frame( sender() );
05009 
05010   assert( child );
05011 
05012   child->m_bCompleted = false;
05013 
05014   if ( d->m_bComplete )
05015   {
05016 #if 0
05017     // WABA: Looks like this belongs somewhere else
05018     if ( !parentPart() ) // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes
05019     {
05020       emit d->m_extension->openURLNotify();
05021     }
05022 #endif
05023     d->m_bComplete = false;
05024     emit started( job );
05025   }
05026 }
05027 
05028 void KHTMLPart::slotChildCompleted()
05029 {
05030   slotChildCompleted( false );
05031 }
05032 
05033 void KHTMLPart::slotChildCompleted( bool pendingAction )
05034 {
05035   khtml::ChildFrame *child = frame( sender() );
05036 
05037   if ( child ) {
05038     kdDebug(6050) << this << " slotChildCompleted child=" << child << " m_frame=" << child->m_frame << endl;
05039     child->m_bCompleted = true;
05040     child->m_bPendingRedirection = pendingAction;
05041     child->m_args = KParts::URLArgs();
05042   }
05043   checkCompleted();
05044 }
05045 
05046 void KHTMLPart::slotChildDocCreated()
05047 {
05048   const KHTMLPart* htmlFrame = static_cast<const KHTMLPart *>(sender());
05049   // Set domain to the frameset's domain
05050   // This must only be done when loading the frameset initially (#22039),
05051   // not when following a link in a frame (#44162).
05052   if ( d->m_doc && d->m_doc->isHTMLDocument() )
05053   {
05054     if ( sender()->inherits("KHTMLPart") )
05055     {
05056       DOMString domain = static_cast<HTMLDocumentImpl*>(d->m_doc)->domain();
05057       if (htmlFrame->d->m_doc && htmlFrame->d->m_doc->isHTMLDocument() )
05058         //kdDebug(6050) << "KHTMLPart::slotChildDocCreated: url: " << htmlFrame->m_url.url() << endl;
05059         static_cast<HTMLDocumentImpl*>(htmlFrame->d->m_doc)->setDomain( domain );
05060     }
05061   }
05062   // So it only happens once
05063   disconnect( htmlFrame, SIGNAL( docCreated() ), this, SLOT( slotChildDocCreated() ) );
05064 }
05065 
05066 void KHTMLPart::slotChildURLRequest( const KURL &url, const KParts::URLArgs &args )
05067 {
05068   khtml::ChildFrame *child = frame( sender()->parent() );
05069   KHTMLPart *callingHtmlPart = const_cast<KHTMLPart *>(dynamic_cast<const KHTMLPart *>(sender()->parent()));
05070 
05071   // TODO: handle child target correctly! currently the script are always executed fur the parent
05072   QString urlStr = url.url();
05073   if ( urlStr.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
05074       QString script = KURL::decode_string( urlStr.right( urlStr.length() - 11 ) );
05075       executeScript( DOM::Node(), script );
05076       return;
05077   }
05078 
05079   QString frameName = args.frameName.lower();
05080   if ( !frameName.isEmpty() ) {
05081     if ( frameName == QString::fromLatin1( "_top" ) )
05082     {
05083       emit d->m_extension->openURLRequest( url, args );
05084       return;
05085     }
05086     else if ( frameName == QString::fromLatin1( "_blank" ) )
05087     {
05088       emit d->m_extension->createNewWindow( url, args );
05089       return;
05090     }
05091     else if ( frameName == QString::fromLatin1( "_parent" ) )
05092     {
05093       KParts::URLArgs newArgs( args );
05094       newArgs.frameName = QString::null;
05095 
05096       emit d->m_extension->openURLRequest( url, newArgs );
05097       return;
05098     }
05099     else if ( frameName != QString::fromLatin1( "_self" ) )
05100     {
05101       khtml::ChildFrame *_frame = recursiveFrameRequest( callingHtmlPart, url, args );
05102 
05103       if ( !_frame )
05104       {
05105         emit d->m_extension->openURLRequest( url, args );
05106         return;
05107       }
05108 
05109       child = _frame;
05110     }
05111   }
05112 
05113   if ( child && child->m_type != khtml::ChildFrame::Object ) {
05114       // Inform someone that we are about to show something else.
05115       child->m_bNotify = true;
05116       requestObject( child, url, args );
05117   }  else if ( frameName== "_self" ) // this is for embedded objects (via <object>) which want to replace the current document
05118   {
05119       KParts::URLArgs newArgs( args );
05120       newArgs.frameName = QString::null;
05121       emit d->m_extension->openURLRequest( url, newArgs );
05122   }
05123 }
05124 
05125 void KHTMLPart::slotRequestFocus( KParts::ReadOnlyPart * )
05126 {
05127   emit d->m_extension->requestFocus(this);
05128 }
05129 
05130 khtml::ChildFrame *KHTMLPart::frame( const QObject *obj )
05131 {
05132     assert( obj->inherits( "KParts::ReadOnlyPart" ) );
05133     const KParts::ReadOnlyPart* const part = static_cast<const KParts::ReadOnlyPart *>( obj );
05134 
05135     FrameIt it = d->m_frames.begin();
05136     const FrameIt end = d->m_frames.end();
05137     for (; it != end; ++it )
05138       if ( (KParts::ReadOnlyPart *)(*it)->m_part == part )
05139         return *it;
05140 
05141     FrameIt oi = d->m_objects.begin();
05142     const FrameIt oiEnd = d->m_objects.end();
05143     for (; oi != oiEnd; ++oi )
05144       if ( (KParts::ReadOnlyPart *)(*oi)->m_part == part )
05145         return *oi;
05146 
05147     return 0L;
05148 }
05149 
05150 //#define DEBUG_FINDFRAME
05151 
05152 bool KHTMLPart::checkFrameAccess(KHTMLPart *callingHtmlPart)
05153 {
05154   if (callingHtmlPart == this)
05155     return true; // trivial
05156 
05157   if (htmlDocument().isNull()) {
05158 #ifdef DEBUG_FINDFRAME
05159     kdDebug(6050) << "KHTMLPart::checkFrameAccess: Empty part " << this << " URL = " << m_url << endl;
05160 #endif
05161     return false; // we are empty?
05162   }
05163 
05164   // now compare the domains
05165   if (callingHtmlPart && !callingHtmlPart->htmlDocument().isNull() &&
05166       !htmlDocument().isNull())  {
05167     DOM::DOMString actDomain = callingHtmlPart->htmlDocument().domain();
05168     DOM::DOMString destDomain = htmlDocument().domain();
05169 
05170 #ifdef DEBUG_FINDFRAME
05171     kdDebug(6050) << "KHTMLPart::checkFrameAccess: actDomain = '" << actDomain.string() << "' destDomain = '" << destDomain.string() << "'" << endl;
05172 #endif
05173 
05174     if (actDomain == destDomain)
05175       return true;
05176   }
05177 #ifdef DEBUG_FINDFRAME
05178   else
05179   {
05180     kdDebug(6050) << "KHTMLPart::checkFrameAccess: Unknown part/domain " << callingHtmlPart << " tries to access part " << this << endl;
05181   }
05182 #endif
05183   return false;
05184 }
05185 
05186 KHTMLPart *
05187 KHTMLPart::findFrameParent( KParts::ReadOnlyPart *callingPart, const QString &f, khtml::ChildFrame **childFrame )
05188 {
05189 #ifdef DEBUG_FINDFRAME
05190   kdDebug(6050) << "KHTMLPart::findFrameParent: this = " << this << " URL = " << m_url << " name = " << name() << " findFrameParent( " << f << " )" << endl;
05191 #endif
05192   // Check access
05193   KHTMLPart* const callingHtmlPart = dynamic_cast<KHTMLPart *>(callingPart);
05194 
05195   if (!checkFrameAccess(callingHtmlPart))
05196      return 0;
05197 
05198   if (!childFrame && !parentPart() && (name() == f))
05199      return this;
05200 
05201   FrameIt it = d->m_frames.find( f );
05202   const FrameIt end = d->m_frames.end();
05203   if ( it != end )
05204   {
05205 #ifdef DEBUG_FINDFRAME
05206      kdDebug(6050) << "KHTMLPart::findFrameParent: FOUND!" << endl;
05207 #endif
05208      if (childFrame)
05209         *childFrame = *it;
05210      return this;
05211   }
05212 
05213   it = d->m_frames.begin();
05214   for (; it != end; ++it )
05215   {
05216     KParts::ReadOnlyPart* const p = (*it)->m_part;
05217     if ( p && p->inherits( "KHTMLPart" ))
05218     {
05219       KHTMLPart* const frameParent = static_cast<KHTMLPart*>(p)->findFrameParent(callingPart, f, childFrame);
05220       if (frameParent)
05221          return frameParent;
05222     }
05223   }
05224   return 0;
05225 }
05226 
05227 
05228 KHTMLPart *KHTMLPart::findFrame( const QString &f )
05229 {
05230   khtml::ChildFrame *childFrame;
05231   KHTMLPart *parentFrame = findFrameParent(this, f, &childFrame);
05232   if (parentFrame)
05233   {
05234      KParts::ReadOnlyPart *p = childFrame->m_part;
05235      if ( p && p->inherits( "KHTMLPart" ))
05236         return static_cast<KHTMLPart *>(p);
05237   }
05238   return 0;
05239 }
05240 
05241 KParts::ReadOnlyPart *KHTMLPart::findFramePart(const QString &f)
05242 {
05243   khtml::ChildFrame *childFrame;
05244   return findFrameParent(this, f, &childFrame) ? static_cast<KParts::ReadOnlyPart *>(childFrame->m_part) : 0L;
05245 }
05246 
05247 KParts::ReadOnlyPart *KHTMLPart::currentFrame() const
05248 {
05249   KParts::ReadOnlyPart* part = (KParts::ReadOnlyPart*)(this);
05250   // Find active part in our frame manager, in case we are a frameset
05251   // and keep doing that (in case of nested framesets).
05252   // Just realized we could also do this recursively, calling part->currentFrame()...
05253   while ( part && part->inherits("KHTMLPart") &&
05254           static_cast<KHTMLPart *>(part)->d->m_frames.count() > 0 ) {
05255     KHTMLPart* frameset = static_cast<KHTMLPart *>(part);
05256     part = static_cast<KParts::ReadOnlyPart *>(frameset->partManager()->activePart());
05257     if ( !part ) return frameset;
05258   }
05259   return part;
05260 }
05261 
05262 bool KHTMLPart::frameExists( const QString &frameName )
05263 {
05264   ConstFrameIt it = d->m_frames.find( frameName );
05265   if ( it == d->m_frames.end() )
05266     return false;
05267 
05268   // WABA: We only return true if the child actually has a frame
05269   // set. Otherwise we might find our preloaded-selve.
05270   // This happens when we restore the frameset.
05271   return (!(*it)->m_frame.isNull());
05272 }
05273 
05274 KJSProxy *KHTMLPart::framejScript(KParts::ReadOnlyPart *framePart)
05275 {
05276   KHTMLPart* const kp = ::qt_cast<KHTMLPart*>(framePart);
05277   if (kp)
05278     return kp->jScript();
05279 
05280   FrameIt it = d->m_frames.begin();
05281   const FrameIt itEnd = d->m_frames.end();
05282 
05283   for (; it != itEnd; ++it)
05284     if (framePart == (*it)->m_part) {
05285       if (!(*it)->m_jscript)
05286         createJScript(*it);
05287       return (*it)->m_jscript;
05288     }
05289   return 0L;
05290 }
05291 
05292 KHTMLPart *KHTMLPart::parentPart()
05293 {
05294   return ::qt_cast<KHTMLPart *>( parent() );
05295 }
05296 
05297 khtml::ChildFrame *KHTMLPart::recursiveFrameRequest( KHTMLPart *callingHtmlPart, const KURL &url,
05298                                                      const KParts::URLArgs &args, bool callParent )
05299 {
05300 #ifdef DEBUG_FINDFRAME
05301   kdDebug( 6050 ) << "KHTMLPart::recursiveFrameRequest this = " << this << ", frame = " << args.frameName << ", url = " << url << endl;
05302 #endif
05303   khtml::ChildFrame *childFrame;
05304   KHTMLPart *childPart = findFrameParent(callingHtmlPart, args.frameName, &childFrame);
05305   if (childPart)
05306   {
05307      if (childPart == this)
05308         return childFrame;
05309 
05310      childPart->requestObject( childFrame, url, args );
05311      return 0;
05312   }
05313 
05314   if ( parentPart() && callParent )
05315   {
05316      khtml::ChildFrame *res = parentPart()->recursiveFrameRequest( callingHtmlPart, url, args, callParent );
05317 
05318      if ( res )
05319        parentPart()->requestObject( res, url, args );
05320   }
05321 
05322   return 0L;
05323 }
05324 
05325 #ifndef NDEBUG
05326 static int s_saveStateIndentLevel = 0;
05327 #endif
05328 
05329 void KHTMLPart::saveState( QDataStream &stream )
05330 {
05331 #ifndef NDEBUG
05332   QString indent = QString().leftJustify( s_saveStateIndentLevel * 4, ' ' );
05333   const int indentLevel = s_saveStateIndentLevel++;
05334   kdDebug( 6050 ) << indent << "saveState this=" << this << " '" << name() << "' saving URL " << m_url.url() << endl;
05335 #endif
05336 
05337   stream << m_url << (Q_INT32)d->m_view->contentsX() << (Q_INT32)d->m_view->contentsY()
05338          << (Q_INT32) d->m_view->contentsWidth() << (Q_INT32) d->m_view->contentsHeight() << (Q_INT32) d->m_view->marginWidth() << (Q_INT32) d->m_view->marginHeight();
05339 
05340   // save link cursor position
05341   int focusNodeNumber;
05342   if (!d->m_focusNodeRestored)
05343       focusNodeNumber = d->m_focusNodeNumber;
05344   else if (d->m_doc && d->m_doc->focusNode())
05345       focusNodeNumber = d->m_doc->nodeAbsIndex(d->m_doc->focusNode());
05346   else
05347       focusNodeNumber = -1;
05348   stream << focusNodeNumber;
05349 
05350   // Save the doc's cache id.
05351   stream << d->m_cacheId;
05352 
05353   // Save the state of the document (Most notably the state of any forms)
05354   QStringList docState;
05355   if (d->m_doc)
05356   {
05357      docState = d->m_doc->docState();
05358   }
05359   stream << d->m_encoding << d->m_sheetUsed << docState;
05360 
05361   stream << d->m_zoomFactor;
05362 
05363   stream << d->m_httpHeaders;
05364   stream << d->m_pageServices;
05365   stream << d->m_pageReferrer;
05366 
05367   // Save ssl data
05368   stream << d->m_ssl_in_use
05369          << d->m_ssl_peer_certificate
05370          << d->m_ssl_peer_chain
05371          << d->m_ssl_peer_ip
05372          << d->m_ssl_cipher
05373          << d->m_ssl_cipher_desc
05374          << d->m_ssl_cipher_version
05375          << d->m_ssl_cipher_used_bits
05376          << d->m_ssl_cipher_bits
05377          << d->m_ssl_cert_state
05378          << d->m_ssl_parent_ip
05379          << d->m_ssl_parent_cert;
05380 
05381 
05382   QStringList frameNameLst, frameServiceTypeLst, frameServiceNameLst;
05383   KURL::List frameURLLst;
05384   QValueList<QByteArray> frameStateBufferLst;
05385 
05386   ConstFrameIt it = d->m_frames.begin();
05387   const ConstFrameIt end = d->m_frames.end();
05388   for (; it != end; ++it )
05389   {
05390     if ( !(*it)->m_part )
05391        continue;
05392 
05393     frameNameLst << (*it)->m_name;
05394     frameServiceTypeLst << (*it)->m_serviceType;
05395     frameServiceNameLst << (*it)->m_serviceName;
05396     frameURLLst << (*it)->m_part->url();
05397 
05398     QByteArray state;
05399     QDataStream frameStream( state, IO_WriteOnly );
05400 
05401     if ( (*it)->m_extension )
05402       (*it)->m_extension->saveState( frameStream );
05403 
05404     frameStateBufferLst << state;
05405   }
05406 
05407   // Save frame data
05408   stream << (Q_UINT32) frameNameLst.count();
05409   stream << frameNameLst << frameServiceTypeLst << frameServiceNameLst << frameURLLst << frameStateBufferLst;
05410 #ifndef NDEBUG
05411   s_saveStateIndentLevel = indentLevel;
05412 #endif
05413 }
05414 
05415 void KHTMLPart::restoreState( QDataStream &stream )
05416 {
05417   KURL u;
05418   Q_INT32 xOffset, yOffset, wContents, hContents, mWidth, mHeight;
05419   Q_UINT32 frameCount;
05420   QStringList frameNames, frameServiceTypes, docState, frameServiceNames;
05421   KURL::List frameURLs;
05422   QValueList<QByteArray> frameStateBuffers;
05423   QValueList<int> fSizes;
05424   QString encoding, sheetUsed;
05425   long old_cacheId = d->m_cacheId;
05426 
05427   stream >> u >> xOffset >> yOffset >> wContents >> hContents >> mWidth >> mHeight;
05428 
05429   d->m_view->setMarginWidth( mWidth );
05430   d->m_view->setMarginHeight( mHeight );
05431 
05432   // restore link cursor position
05433   // nth node is active. value is set in checkCompleted()
05434   stream >> d->m_focusNodeNumber;
05435   d->m_focusNodeRestored = false;
05436 
05437   stream >> d->m_cacheId;
05438 
05439   stream >> encoding >> sheetUsed >> docState;
05440 
05441   d->m_encoding = encoding;
05442   d->m_sheetUsed = sheetUsed;
05443 
05444   int zoomFactor;
05445   stream >> zoomFactor;
05446   setZoomFactor(zoomFactor);
05447 
05448   stream >> d->m_httpHeaders;
05449   stream >> d->m_pageServices;
05450   stream >> d->m_pageReferrer;
05451 
05452   // Restore ssl data
05453   stream >> d->m_ssl_in_use
05454          >> d->m_ssl_peer_certificate
05455          >> d->m_ssl_peer_chain
05456          >> d->m_ssl_peer_ip
05457          >> d->m_ssl_cipher
05458          >> d->m_ssl_cipher_desc
05459          >> d->m_ssl_cipher_version
05460          >> d->m_ssl_cipher_used_bits
05461          >> d->m_ssl_cipher_bits
05462          >> d->m_ssl_cert_state
05463          >> d->m_ssl_parent_ip
05464          >> d->m_ssl_parent_cert;
05465 
05466   setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
05467 
05468   stream >> frameCount >> frameNames >> frameServiceTypes >> frameServiceNames
05469          >> frameURLs >> frameStateBuffers;
05470 
05471   d->m_bComplete = false;
05472   d->m_bLoadEventEmitted = false;
05473 
05474 //   kdDebug( 6050 ) << "restoreState() docState.count() = " << docState.count() << endl;
05475 //   kdDebug( 6050 ) << "m_url " << m_url.url() << " <-> " << u.url() << endl;
05476 //   kdDebug( 6050 ) << "m_frames.count() " << d->m_frames.count() << " <-> " << frameCount << endl;
05477 
05478   if (d->m_cacheId == old_cacheId)
05479   {
05480     // Partial restore
05481     d->m_redirectionTimer.stop();
05482 
05483     FrameIt fIt = d->m_frames.begin();
05484     const FrameIt fEnd = d->m_frames.end();
05485 
05486     for (; fIt != fEnd; ++fIt )
05487         (*fIt)->m_bCompleted = false;
05488 
05489     fIt = d->m_frames.begin();
05490 
05491     QStringList::ConstIterator fNameIt = frameNames.begin();
05492     QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.begin();
05493     QStringList::ConstIterator fServiceNameIt = frameServiceNames.begin();
05494     KURL::List::ConstIterator fURLIt = frameURLs.begin();
05495     QValueList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.begin();
05496 
05497     for (; fIt != fEnd; ++fIt, ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt )
05498     {
05499       khtml::ChildFrame* const child = *fIt;
05500 
05501 //      kdDebug( 6050 ) <<  *fNameIt  << " ---- " <<  *fServiceTypeIt << endl;
05502 
05503       if ( child->m_name != *fNameIt || child->m_serviceType != *fServiceTypeIt )
05504       {
05505         child->m_bPreloaded = true;
05506         child->m_name = *fNameIt;
05507         child->m_serviceName = *fServiceNameIt;
05508         processObjectRequest( child, *fURLIt, *fServiceTypeIt );
05509       }
05510       if ( child->m_part )
05511       {
05512         child->m_bCompleted = false;
05513         if ( child->m_extension && !(*fBufferIt).isEmpty() )
05514         {
05515           QDataStream frameStream( *fBufferIt, IO_ReadOnly );
05516           child->m_extension->restoreState( frameStream );
05517         }
05518         else
05519           child->m_part->openURL( *fURLIt );
05520       }
05521     }
05522 
05523     KParts::URLArgs args( d->m_extension->urlArgs() );
05524     args.xOffset = xOffset;
05525     args.yOffset = yOffset;
05526     args.docState = docState;
05527     d->m_extension->setURLArgs( args );
05528 
05529     d->m_view->resizeContents( wContents,  hContents);
05530     d->m_view->setContentsPos( xOffset, yOffset );
05531 
05532     m_url = u;
05533   }
05534   else
05535   {
05536     // Full restore.
05537     closeURL();
05538     // We must force a clear because we want to be sure to delete all
05539     // frames.
05540     d->m_bCleared = false;
05541     clear();
05542     d->m_encoding = encoding;
05543     d->m_sheetUsed = sheetUsed;
05544 
05545     QStringList::ConstIterator fNameIt = frameNames.begin();
05546     const QStringList::ConstIterator fNameEnd = frameNames.end();
05547 
05548     QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.begin();
05549     QStringList::ConstIterator fServiceNameIt = frameServiceNames.begin();
05550     KURL::List::ConstIterator fURLIt = frameURLs.begin();
05551     QValueList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.begin();
05552 
05553     for (; fNameIt != fNameEnd; ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt )
05554     {
05555       khtml::ChildFrame* const newChild = new khtml::ChildFrame;
05556       newChild->m_bPreloaded = true;
05557       newChild->m_name = *fNameIt;
05558       newChild->m_serviceName = *fServiceNameIt;
05559 
05560 //      kdDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt << endl;
05561 
05562       const FrameIt childFrame = d->m_frames.append( newChild );
05563 
05564       processObjectRequest( *childFrame, *fURLIt, *fServiceTypeIt );
05565 
05566       (*childFrame)->m_bPreloaded = true;
05567 
05568       if ( (*childFrame)->m_part )
05569       {
05570         if ( (*childFrame)->m_extension )
05571         if ( (*childFrame)->m_extension && !(*fBufferIt).isEmpty() )
05572         {
05573           QDataStream frameStream( *fBufferIt, IO_ReadOnly );
05574           (*childFrame)->m_extension->restoreState( frameStream );
05575         }
05576         else
05577           (*childFrame)->m_part->openURL( *fURLIt );
05578       }
05579     }
05580 
05581     KParts::URLArgs args( d->m_extension->urlArgs() );
05582     args.xOffset = xOffset;
05583     args.yOffset = yOffset;
05584     args.docState = docState;
05585 
05586     d->m_extension->setURLArgs( args );
05587     if (!KHTMLPageCache::self()->isComplete(d->m_cacheId))
05588     {
05589        d->m_restored = true;
05590        openURL( u );
05591        d->m_restored = false;
05592     }
05593     else
05594     {
05595        restoreURL( u );
05596     }
05597   }
05598 
05599 }
05600 
05601 void KHTMLPart::show()
05602 {
05603   if ( d->m_view )
05604     d->m_view->show();
05605 }
05606 
05607 void KHTMLPart::hide()
05608 {
05609   if ( d->m_view )
05610     d->m_view->hide();
05611 }
05612 
05613 DOM::Node KHTMLPart::nodeUnderMouse() const
05614 {
05615     return d->m_view->nodeUnderMouse();
05616 }
05617 
05618 DOM::Node KHTMLPart::nonSharedNodeUnderMouse() const
05619 {
05620     return d->m_view->nonSharedNodeUnderMouse();
05621 }
05622 
05623 void KHTMLPart::emitSelectionChanged()
05624 {
05625   emit d->m_extension->enableAction( "copy", hasSelection() );
05626   if ( d->m_findDialog )
05627        d->m_findDialog->setHasSelection( hasSelection() );
05628 
05629   emit d->m_extension->selectionInfo( selectedText() );
05630   emit selectionChanged();
05631 }
05632 
05633 int KHTMLPart::zoomFactor() const
05634 {
05635   return d->m_zoomFactor;
05636 }
05637 
05638 // ### make the list configurable ?
05639 static const int zoomSizes[] = { 20, 40, 60, 80, 90, 95, 100, 105, 110, 120, 140, 160, 180, 200, 250, 300 };
05640 static const int zoomSizeCount = (sizeof(zoomSizes) / sizeof(int));
05641 static const int minZoom = 20;
05642 static const int maxZoom = 300;
05643 
05644 // My idea of useful stepping ;-) (LS)
05645 extern const int KDE_NO_EXPORT fastZoomSizes[] = { 20, 50, 75, 90, 100, 120, 150, 200, 300 };
05646 extern const int KDE_NO_EXPORT fastZoomSizeCount = sizeof fastZoomSizes / sizeof fastZoomSizes[0];
05647 
05648 void KHTMLPart::slotIncZoom()
05649 {
05650   zoomIn(zoomSizes, zoomSizeCount);
05651 }
05652 
05653 void KHTMLPart::slotDecZoom()
05654 {
05655   zoomOut(zoomSizes, zoomSizeCount);
05656 }
05657 
05658 void KHTMLPart::slotIncZoomFast()
05659 {
05660   zoomIn(fastZoomSizes, fastZoomSizeCount);
05661 }
05662 
05663 void KHTMLPart::slotDecZoomFast()
05664 {
05665   zoomOut(fastZoomSizes, fastZoomSizeCount);
05666 }
05667 
05668 void KHTMLPart::zoomIn(const int stepping[], int count)
05669 {
05670   int zoomFactor = d->m_zoomFactor;
05671 
05672   if (zoomFactor < maxZoom) {
05673     // find the entry nearest to the given zoomsizes
05674     for (int i = 0; i < count; ++i)
05675       if (stepping[i] > zoomFactor) {
05676         zoomFactor = stepping[i];
05677         break;
05678       }
05679     setZoomFactor(zoomFactor);
05680   }
05681 }
05682 
05683 void KHTMLPart::zoomOut(const int stepping[], int count)
05684 {
05685     int zoomFactor = d->m_zoomFactor;
05686     if (zoomFactor > minZoom) {
05687       // find the entry nearest to the given zoomsizes
05688       for (int i = count-1; i >= 0; --i)
05689         if (stepping[i] < zoomFactor) {
05690           zoomFactor = stepping[i];
05691           break;
05692         }
05693       setZoomFactor(zoomFactor);
05694     }
05695 }
05696 
05697 void KHTMLPart::setZoomFactor (int percent)
05698 {
05699   if (percent < minZoom) percent = minZoom;
05700   if (percent > maxZoom) percent = maxZoom;
05701   if (d->m_zoomFactor == percent) return;
05702   d->m_zoomFactor = percent;
05703 
05704   if(d->m_doc) {
05705       QApplication::setOverrideCursor( waitCursor );
05706     if (d->m_doc->styleSelector())
05707       d->m_doc->styleSelector()->computeFontSizes(d->m_doc->paintDeviceMetrics(), d->m_zoomFactor);
05708     d->m_doc->recalcStyle( NodeImpl::Force );
05709     QApplication::restoreOverrideCursor();
05710   }
05711 
05712   ConstFrameIt it = d->m_frames.begin();
05713   const ConstFrameIt end = d->m_frames.end();
05714   for (; it != end; ++it )
05715     if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
05716       KParts::ReadOnlyPart* const p = ( *it )->m_part;
05717       static_cast<KHTMLPart*>( p )->setZoomFactor(d->m_zoomFactor);
05718     }
05719 
05720   if ( d->m_guiProfile == BrowserViewGUI ) {
05721       d->m_paDecZoomFactor->setEnabled( d->m_zoomFactor > minZoom );
05722       d->m_paIncZoomFactor->setEnabled( d->m_zoomFactor < maxZoom );
05723   }
05724 }
05725 
05726 void KHTMLPart::slotZoomView( int delta )
05727 {
05728   if ( delta < 0 )
05729     slotIncZoom();
05730   else
05731     slotDecZoom();
05732 }
05733 
05734 void KHTMLPart::setStatusBarText( const QString& text, StatusBarPriority p)
05735 {
05736   if (!d->m_statusMessagesEnabled)
05737     return;
05738 
05739   d->m_statusBarText[p] = text;
05740 
05741   // shift handling ?
05742   QString tobe = d->m_statusBarText[BarHoverText];
05743   if (tobe.isEmpty())
05744     tobe = d->m_statusBarText[BarOverrideText];
05745   if (tobe.isEmpty()) {
05746     tobe = d->m_statusBarText[BarDefaultText];
05747     if (!tobe.isEmpty() && d->m_jobspeed)
05748       tobe += " ";
05749     if (d->m_jobspeed)
05750       tobe += i18n( "(%1/s)" ).arg( KIO::convertSize( d->m_jobspeed ) );
05751   }
05752   tobe = "<qt>"+tobe;
05753 
05754   emit ReadOnlyPart::setStatusBarText(tobe);
05755 }
05756 
05757 
05758 void KHTMLPart::setJSStatusBarText( const QString &text )
05759 {
05760   setStatusBarText(text, BarOverrideText);
05761 }
05762 
05763 void KHTMLPart::setJSDefaultStatusBarText( const QString &text )
05764 {
05765   setStatusBarText(text, BarDefaultText);
05766 }
05767 
05768 QString KHTMLPart::jsStatusBarText() const
05769 {
05770     return d->m_statusBarText[BarOverrideText];
05771 }
05772 
05773 QString KHTMLPart::jsDefaultStatusBarText() const
05774 {
05775    return d->m_statusBarText[BarDefaultText];
05776 }
05777 
05778 QString KHTMLPart::referrer() const
05779 {
05780    return d->m_referrer;
05781 }
05782 
05783 QString KHTMLPart::pageReferrer() const
05784 {
05785    KURL referrerURL = KURL( d->m_pageReferrer );
05786    if (referrerURL.isValid())
05787    {
05788       QString protocol = referrerURL.protocol();
05789 
05790       if ((protocol == "http") ||
05791          ((protocol == "https") && (m_url.protocol() == "https")))
05792       {
05793           referrerURL.setRef(QString::null);
05794           referrerURL.setUser(QString::null);
05795           referrerURL.setPass(QString::null);
05796           return referrerURL.url();
05797       }
05798    }
05799 
05800    return QString::null;
05801 }
05802 
05803 
05804 QString KHTMLPart::lastModified() const
05805 {
05806   if ( d->m_lastModified.isEmpty() && m_url.isLocalFile() ) {
05807     // Local file: set last-modified from the file's mtime.
05808     // Done on demand to save time when this isn't needed - but can lead
05809     // to slightly wrong results if updating the file on disk w/o reloading.
05810     QDateTime lastModif = QFileInfo( m_url.path() ).lastModified();
05811     d->m_lastModified = lastModif.toString( Qt::LocalDate );
05812   }
05813   //kdDebug(6050) << "KHTMLPart::lastModified: " << d->m_lastModified << endl;
05814   return d->m_lastModified;
05815 }
05816 
05817 void KHTMLPart::slotLoadImages()
05818 {
05819   if (d->m_doc )
05820     d->m_doc->docLoader()->setAutoloadImages( !d->m_doc->docLoader()->autoloadImages() );
05821 
05822   ConstFrameIt it = d->m_frames.begin();
05823   const ConstFrameIt end = d->m_frames.end();
05824   for (; it != end; ++it )
05825     if ( !( *it )->m_part.isNull() && (*it)->m_part->inherits( "KHTMLPart" ) ) {
05826       KParts::ReadOnlyPart* const p = ( *it )->m_part;
05827       static_cast<KHTMLPart*>( p )->slotLoadImages();
05828     }
05829 }
05830 
05831 void KHTMLPart::reparseConfiguration()
05832 {
05833   KHTMLSettings *settings = KHTMLFactory::defaultHTMLSettings();
05834   settings->init();
05835 
05836   setAutoloadImages( settings->autoLoadImages() );
05837   if (d->m_doc)
05838      d->m_doc->docLoader()->setShowAnimations( settings->showAnimations() );
05839 
05840   d->m_bOpenMiddleClick = settings->isOpenMiddleClickEnabled();
05841   d->m_bBackRightClick = settings->isBackRightClickEnabled();
05842   d->m_bJScriptEnabled = settings->isJavaScriptEnabled(m_url.host());
05843   setDebugScript( settings->isJavaScriptDebugEnabled() );
05844   d->m_bJavaEnabled = settings->isJavaEnabled(m_url.host());
05845   d->m_bPluginsEnabled = settings->isPluginsEnabled(m_url.host());
05846   d->m_metaRefreshEnabled = settings->isAutoDelayedActionsEnabled ();
05847 
05848   delete d->m_settings;
05849   d->m_settings = new KHTMLSettings(*KHTMLFactory::defaultHTMLSettings());
05850 
05851   QApplication::setOverrideCursor( waitCursor );
05852   khtml::CSSStyleSelector::reparseConfiguration();
05853   if(d->m_doc) d->m_doc->updateStyleSelector();
05854   QApplication::restoreOverrideCursor();
05855 
05856   if (KHTMLFactory::defaultHTMLSettings()->isAdFilterEnabled())
05857      runAdFilter();
05858 }
05859 
05860 QStringList KHTMLPart::frameNames() const
05861 {
05862   QStringList res;
05863 
05864   ConstFrameIt it = d->m_frames.begin();
05865   const ConstFrameIt end = d->m_frames.end();
05866   for (; it != end; ++it )
05867     if (!(*it)->m_bPreloaded)
05868       res += (*it)->m_name;
05869 
05870   return res;
05871 }
05872 
05873 QPtrList<KParts::ReadOnlyPart> KHTMLPart::frames() const
05874 {
05875   QPtrList<KParts::ReadOnlyPart> res;
05876 
05877   ConstFrameIt it = d->m_frames.begin();
05878   const ConstFrameIt end = d->m_frames.end();
05879   for (; it != end; ++it )
05880     if (!(*it)->m_bPreloaded)
05881       res.append( (*it)->m_part );
05882 
05883   return res;
05884 }
05885 
05886 bool KHTMLPart::openURLInFrame( const KURL &url, const KParts::URLArgs &urlArgs )
05887 {
05888     kdDebug( 6050 ) << this << "KHTMLPart::openURLInFrame " << url << endl;
05889   FrameIt it = d->m_frames.find( urlArgs.frameName );
05890 
05891   if ( it == d->m_frames.end() )
05892     return false;
05893 
05894   // Inform someone that we are about to show something else.
05895   if ( !urlArgs.lockHistory() )
05896       emit d->m_extension->openURLNotify();
05897 
05898   requestObject( *it, url, urlArgs );
05899 
05900   return true;
05901 }
05902 
05903 void KHTMLPart::setDNDEnabled( bool b )
05904 {
05905   d->m_bDnd = b;
05906 }
05907 
05908 bool KHTMLPart::dndEnabled() const
05909 {
05910   return d->m_bDnd;
05911 }
05912 
05913 void KHTMLPart::customEvent( QCustomEvent *event )
05914 {
05915   if ( khtml::MousePressEvent::test( event ) )
05916   {
05917     khtmlMousePressEvent( static_cast<khtml::MousePressEvent *>( event ) );
05918     return;
05919   }
05920 
05921   if ( khtml::MouseDoubleClickEvent::test( event ) )
05922   {
05923     khtmlMouseDoubleClickEvent( static_cast<khtml::MouseDoubleClickEvent *>( event ) );
05924     return;
05925   }
05926 
05927   if ( khtml::MouseMoveEvent::test( event ) )
05928   {
05929     khtmlMouseMoveEvent( static_cast<khtml::MouseMoveEvent *>( event ) );
05930     return;
05931   }
05932 
05933   if ( khtml::MouseReleaseEvent::test( event ) )
05934   {
05935     khtmlMouseReleaseEvent( static_cast<khtml::MouseReleaseEvent *>( event ) );
05936     return;
05937   }
05938 
05939   if ( khtml::DrawContentsEvent::test( event ) )
05940   {
05941     khtmlDrawContentsEvent( static_cast<khtml::DrawContentsEvent *>( event ) );
05942     return;
05943   }
05944 
05945   KParts::ReadOnlyPart::customEvent( event );
05946 }
05947 
05953 static bool firstRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
05954 {
05955     for (khtml::RenderObject *n = renderNode; n; n = n->nextSibling()) {
05956         if (n->isText()) {
05957             khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
05958             const khtml::InlineTextBoxArray &runs = textRenderer->inlineTextBoxes();
05959         const unsigned lim = runs.count();
05960             for (unsigned i = 0; i != lim; ++i) {
05961                 if (runs[i]->m_y == y) {
05962                     startNode = textRenderer->element();
05963                     startOffset = runs[i]->m_start;
05964                     return true;
05965                 }
05966             }
05967         }
05968 
05969         if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
05970             return true;
05971         }
05972     }
05973 
05974     return false;
05975 }
05976 
05982 static bool lastRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
05983 {
05984     khtml::RenderObject *n = renderNode;
05985     if (!n) {
05986         return false;
05987     }
05988     khtml::RenderObject *next;
05989     while ((next = n->nextSibling())) {
05990         n = next;
05991     }
05992 
05993     while (1) {
05994         if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
05995             return true;
05996         }
05997 
05998         if (n->isText()) {
05999             khtml::RenderText* const textRenderer =  static_cast<khtml::RenderText *>(n);
06000             const khtml::InlineTextBoxArray &runs = textRenderer->inlineTextBoxes();
06001             for (int i = (int)runs.count()-1; i >= 0; --i) {
06002                 if (runs[i]->m_y == y) {
06003                     endNode = textRenderer->element();
06004                     endOffset = runs[i]->m_start + runs[i]->m_len;
06005                     return true;
06006                 }
06007             }
06008         }
06009 
06010         if (n == renderNode) {
06011             return false;
06012         }
06013 
06014         n = n->previousSibling();
06015     }
06016 }
06017 
06018 void KHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent *event )
06019 {
06020   DOM::DOMString url = event->url();
06021   QMouseEvent *_mouse = event->qmouseEvent();
06022   DOM::Node innerNode = event->innerNode();
06023   d->m_mousePressNode = innerNode;
06024 
06025    d->m_dragStartPos = _mouse->pos();
06026 
06027    if ( !event->url().isNull() ) {
06028      d->m_strSelectedURL = event->url().string();
06029      d->m_strSelectedURLTarget = event->target().string();
06030    }
06031    else
06032      d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
06033 
06034   if ( _mouse->button() == LeftButton ||
06035        _mouse->button() == MidButton )
06036   {
06037     d->m_bMousePressed = true;
06038 
06039 #ifndef KHTML_NO_SELECTION
06040     if ( _mouse->button() == LeftButton )
06041     {
06042       if ( (!d->m_strSelectedURL.isNull() && !isEditable())
06043             || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) )
06044       return;
06045       if ( !innerNode.isNull()  && innerNode.handle()->renderer()) {
06046           int offset = 0;
06047           DOM::NodeImpl* node = 0;
06048           khtml::RenderObject::SelPointState state;
06049           innerNode.handle()->renderer()->checkSelectionPoint( event->x(), event->y(),
06050                                                                event->absX()-innerNode.handle()->renderer()->xPos(),
06051                                                                event->absY()-innerNode.handle()->renderer()->yPos(), node, offset, state );
06052           d->m_extendMode = d->ExtendByChar;
06053 #ifdef KHTML_NO_CARET
06054           d->m_selectionStart = node;
06055           d->m_startOffset = offset;
06056           //if ( node )
06057           //  kdDebug(6005) << "KHTMLPart::khtmlMousePressEvent selectionStart=" << d->m_selectionStart.handle()->renderer()
06058           //                << " offset=" << d->m_startOffset << endl;
06059           //else
06060           //  kdDebug(6005) << "KHTML::khtmlMousePressEvent selectionStart=(nil)" << endl;
06061           d->m_selectionEnd = d->m_selectionStart;
06062           d->m_endOffset = d->m_startOffset;
06063           d->m_doc->clearSelection();
06064 #else // KHTML_NO_CARET
06065       d->m_view->moveCaretTo(node, offset, (_mouse->state() & ShiftButton) == 0);
06066 #endif // KHTML_NO_CARET
06067       d->m_initialNode = d->m_selectionStart;
06068       d->m_initialOffset = d->m_startOffset;
06069 //           kdDebug(6000) << "press: initOfs " << d->m_initialOffset << endl;
06070       }
06071       else
06072       {
06073 #ifndef KHTML_NO_CARET
06074         // simply leave it. Is this a good idea?
06075 #else
06076         d->m_selectionStart = DOM::Node();
06077         d->m_selectionEnd = DOM::Node();
06078 #endif
06079       }
06080       emitSelectionChanged();
06081       startAutoScroll();
06082     }
06083 #else
06084     d->m_dragLastPos = _mouse->globalPos();
06085 #endif
06086   }
06087 
06088   if ( _mouse->button() == RightButton && parentPart() != 0 && d->m_bBackRightClick )
06089   {
06090     d->m_bRightMousePressed = true;
06091   } else if ( _mouse->button() == RightButton )
06092   {
06093     popupMenu( d->m_strSelectedURL );
06094     // might be deleted, don't touch "this"
06095   }
06096 }
06097 
06098 void KHTMLPart::khtmlMouseDoubleClickEvent( khtml::MouseDoubleClickEvent *event )
06099 {
06100   QMouseEvent *_mouse = event->qmouseEvent();
06101   if ( _mouse->button() == LeftButton )
06102   {
06103     d->m_bMousePressed = true;
06104     DOM::Node innerNode = event->innerNode();
06105     // Find selectionStart again, khtmlMouseReleaseEvent lost it
06106     if ( !innerNode.isNull() && innerNode.handle()->renderer()) {
06107       int offset = 0;
06108       DOM::NodeImpl* node = 0;
06109       khtml::RenderObject::SelPointState state;
06110       innerNode.handle()->renderer()->checkSelectionPoint( event->x(), event->y(),
06111                                                            event->absX()-innerNode.handle()->renderer()->xPos(),
06112                                                            event->absY()-innerNode.handle()->renderer()->yPos(), node, offset, state);
06113 
06114       //kdDebug() << k_funcinfo << "checkSelectionPoint returned node=" << node << " offset=" << offset << endl;
06115 
06116       if ( node && node->renderer() )
06117       {
06118         // Extend selection to a complete word (double-click) or line (triple-click)
06119         bool selectLine = (event->clickCount() == 3);
06120         d->m_extendMode = selectLine ? d->ExtendByLine : d->ExtendByWord;
06121 
06122     // Extend existing selection if Shift was pressed
06123     if (_mouse->state() & ShiftButton) {
06124           d->caretNode() = node;
06125       d->caretOffset() = offset;
06126           d->m_startBeforeEnd = RangeImpl::compareBoundaryPoints(
06127                 d->m_selectionStart.handle(), d->m_startOffset,
06128             d->m_selectionEnd.handle(), d->m_endOffset) <= 0;
06129           d->m_initialNode = d->m_extendAtEnd ? d->m_selectionStart : d->m_selectionEnd;
06130           d->m_initialOffset = d->m_extendAtEnd ? d->m_startOffset : d->m_endOffset;
06131     } else {
06132       d->m_selectionStart = d->m_selectionEnd = node;
06133       d->m_startOffset = d->m_endOffset = offset;
06134           d->m_startBeforeEnd = true;
06135           d->m_initialNode = node;
06136           d->m_initialOffset = offset;
06137     }
06138 //         kdDebug(6000) << "dblclk: initOfs " << d->m_initialOffset << endl;
06139 
06140         // Extend the start
06141         extendSelection( d->m_selectionStart.handle(), d->m_startOffset, d->m_selectionStart, d->m_startOffset, !d->m_startBeforeEnd, selectLine );
06142         // Extend the end
06143         extendSelection( d->m_selectionEnd.handle(), d->m_endOffset, d->m_selectionEnd, d->m_endOffset, d->m_startBeforeEnd, selectLine );
06144 
06145         //kdDebug() << d->m_selectionStart.handle() << " " << d->m_startOffset << "  -  " <<
06146         //  d->m_selectionEnd.handle() << " " << d->m_endOffset << endl;
06147 
06148         emitSelectionChanged();
06149         d->m_doc
06150           ->setSelection(d->m_selectionStart.handle(),d->m_startOffset,
06151                          d->m_selectionEnd.handle(),d->m_endOffset);
06152 #ifndef KHTML_NO_CARET
06153         bool v = d->m_view->placeCaret();
06154         emitCaretPositionChanged(v ? d->caretNode() : 0, d->caretOffset());
06155 #endif
06156         startAutoScroll();
06157       }
06158     }
06159   }
06160 }
06161 
06162 void KHTMLPart::extendSelection( DOM::NodeImpl* node, long offset, DOM::Node& selectionNode, long& selectionOffset, bool right, bool selectLines )
06163 {
06164   khtml::RenderObject* obj = node->renderer();
06165 
06166   if (obj->isText() && selectLines) {
06167     int pos;
06168     khtml::RenderText *renderer = static_cast<khtml::RenderText *>(obj);
06169     khtml::InlineTextBox *run = renderer->findInlineTextBox( offset, pos );
06170     DOMString t = node->nodeValue();
06171     DOM::NodeImpl* selNode = 0;
06172     long selOfs = 0;
06173 
06174     if (!run)
06175       return;
06176 
06177     int selectionPointY = run->m_y;
06178 
06179     // Go up to first non-inline element.
06180     khtml::RenderObject *renderNode = renderer;
06181     while (renderNode && renderNode->isInline())
06182       renderNode = renderNode->parent();
06183 
06184     renderNode = renderNode->firstChild();
06185 
06186     if (right) {
06187       // Look for all the last child in the block that is on the same line
06188       // as the selection point.
06189       if (!lastRunAt (renderNode, selectionPointY, selNode, selOfs))
06190         return;
06191     } else {
06192       // Look for all the first child in the block that is on the same line
06193       // as the selection point.
06194       if (!firstRunAt (renderNode, selectionPointY, selNode, selOfs))
06195         return;
06196     }
06197 
06198     selectionNode = selNode;
06199     selectionOffset = selOfs;
06200     return;
06201   }
06202 
06203   QString str;
06204   int len = 0;
06205   if ( obj->isText() ) { // can be false e.g. when double-clicking on a disabled submit button
06206     str = static_cast<khtml::RenderText *>(obj)->data().string();
06207     len = str.length();
06208   }
06209   //kdDebug() << "extendSelection right=" << right << " offset=" << offset << " len=" << len << " Starting at obj=" << obj << endl;
06210   QChar ch;
06211   do {
06212     // Last char was ok, point to it
06213     if ( node ) {
06214       selectionNode = node;
06215       selectionOffset = offset;
06216     }
06217 
06218     // Get another char
06219     while ( obj && ( (right && offset >= len-1) || (!right && offset <= 0) ) )
06220     {
06221       obj = right ? obj->objectBelow() : obj->objectAbove();
06222       //kdDebug() << "obj=" << obj << endl;
06223       if ( obj ) {
06224         //kdDebug() << "isText=" << obj->isText() << endl;
06225         str = QString::null;
06226         if ( obj->isText() )
06227           str = static_cast<khtml::RenderText *>(obj)->data().string();
06228         else if ( obj->isBR() )
06229           str = '\n';
06230         else if ( !obj->isInline() ) {
06231           obj = 0L; // parag limit -> done
06232           break;
06233         }
06234         len = str.length();
06235         //kdDebug() << "str=" << str << " length=" << len << endl;
06236         // set offset - note that the first thing will be a ++ or -- on it.
06237         if ( right )
06238           offset = -1;
06239         else
06240           offset = len;
06241       }
06242     }
06243     if ( !obj ) // end of parag or document
06244       break;
06245     node = obj->element();
06246     if ( right )
06247     {
06248       Q_ASSERT( offset < len-1 );
06249       ++offset;
06250     }
06251     else
06252     {
06253       Q_ASSERT( offset > 0 );
06254       --offset;
06255     }
06256 
06257     // Test that char
06258     ch = str[ (int)offset ];
06259     //kdDebug() << " offset=" << offset << " ch=" << QString(ch) << endl;
06260   } while ( !ch.isSpace() && !ch.isPunct() );
06261 
06262   // make offset point after last char
06263   if (right) ++selectionOffset;
06264 }
06265 
06266 #ifndef KHTML_NO_SELECTION
06267 void KHTMLPart::extendSelectionTo(int x, int y, int absX, int absY, const DOM::Node &innerNode)
06268 {
06269       int offset;
06270       //kdDebug(6000) << "KHTMLPart::khtmlMouseMoveEvent x=" << event->x() << " y=" << event->y() << endl;
06271       DOM::NodeImpl* node=0;
06272       khtml::RenderObject::SelPointState state;
06273       innerNode.handle()->renderer()->checkSelectionPoint( x, y,
06274                                                            absX-innerNode.handle()->renderer()->xPos(),
06275                                                            absY-innerNode.handle()->renderer()->yPos(), node, offset, state);
06276       if (!node || !node->renderer()) return;
06277 
06278       // Words at the beginning/end of line cannot be deselected in
06279       // ExtendByWord mode. Therefore, do not enforce it if the selection
06280       // point does not match the node under the mouse cursor.
06281       bool withinNode = innerNode == node;
06282 
06283       // we have to get to know if end is before start or not...
06284       // shouldn't be null but it can happen with dynamic updating of nodes
06285       if (d->m_selectionStart.isNull() || d->m_selectionEnd.isNull() ||
06286           d->m_initialNode.isNull() ||
06287           !d->m_selectionStart.handle()->renderer() ||
06288           !d->m_selectionEnd.handle()->renderer()) return;
06289 
06290       if (d->m_extendMode != d->ExtendByChar) {
06291         // check whether we should extend at the front, or at the back
06292         bool caretBeforeInit = RangeImpl::compareBoundaryPoints(
06293                 d->caretNode().handle(), d->caretOffset(),
06294             d->m_initialNode.handle(), d->m_initialOffset) <= 0;
06295         bool nodeBeforeInit = RangeImpl::compareBoundaryPoints(node, offset,
06296             d->m_initialNode.handle(), d->m_initialOffset) <= 0;
06297         // have to fix up start to point to the original end
06298         if (caretBeforeInit != nodeBeforeInit) {
06299 //         kdDebug(6000) << "extto cbi: " << caretBeforeInit << " startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << ")" << " initOfs " << d->m_initialOffset << endl;
06300           extendSelection(d->m_initialNode.handle(), d->m_initialOffset,
06301         d->m_extendAtEnd ? d->m_selectionStart : d->m_selectionEnd,
06302         d->m_extendAtEnd ? d->m_startOffset : d->m_endOffset,
06303         nodeBeforeInit, d->m_extendMode == d->ExtendByLine);
06304     }
06305       }
06306 
06307       d->caretNode() = node;
06308       d->caretOffset() = offset;
06309       //kdDebug( 6000 ) << "setting end of selection to " << d->m_selectionEnd.handle() << "/" << d->m_endOffset << endl;
06310 
06311       d->m_startBeforeEnd = RangeImpl::compareBoundaryPoints(
06312                 d->m_selectionStart.handle(), d->m_startOffset,
06313             d->m_selectionEnd.handle(), d->m_endOffset) <= 0;
06314 
06315       if ( !d->m_selectionStart.isNull() && !d->m_selectionEnd.isNull() )
06316       {
06317 //         kdDebug(6000) << "extto: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << ")" << " initOfs " << d->m_initialOffset << endl;
06318         if (d->m_extendMode != d->ExtendByChar && withinNode)
06319           extendSelection( node, offset, d->caretNode(), d->caretOffset(), d->m_startBeforeEnd ^ !d->m_extendAtEnd, d->m_extendMode == d->ExtendByLine );
06320 
06321         if (d->m_selectionEnd == d->m_selectionStart && d->m_endOffset < d->m_startOffset)
06322           d->m_doc
06323             ->setSelection(d->m_selectionStart.handle(),d->m_endOffset,
06324                            d->m_selectionEnd.handle(),d->m_startOffset);
06325         else if (d->m_startBeforeEnd)
06326           d->m_doc
06327             ->setSelection(d->m_selectionStart.handle(),d->m_startOffset,
06328                            d->m_selectionEnd.handle(),d->m_endOffset);
06329         else
06330           d->m_doc
06331             ->setSelection(d->m_selectionEnd.handle(),d->m_endOffset,
06332                            d->m_selectionStart.handle(),d->m_startOffset);
06333       }
06334 #ifndef KHTML_NO_CARET
06335       d->m_view->placeCaret();
06336 #endif
06337 }
06338 
06339 bool KHTMLPart::isExtendingSelection() const
06340 {
06341   // This is it, the whole detection. khtmlMousePressEvent only sets this
06342   // on LMB or MMB, but never on RMB. As text selection doesn't work for MMB,
06343   // it's sufficient to only rely on this flag to detect selection extension.
06344   return d->m_bMousePressed;
06345 }
06346 #endif // KHTML_NO_SELECTION
06347 
06348 void KHTMLPart::khtmlMouseMoveEvent( khtml::MouseMoveEvent *event )
06349 {
06350   QMouseEvent *_mouse = event->qmouseEvent();
06351 
06352   if( d->m_bRightMousePressed && parentPart() != 0 && d->m_bBackRightClick )
06353   {
06354     popupMenu( d->m_strSelectedURL );
06355     d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
06356     d->m_bRightMousePressed = false;
06357   }
06358 
06359   DOM::DOMString url = event->url();
06360   DOM::DOMString target = event->target();
06361   DOM::Node innerNode = event->innerNode();
06362 
06363 #ifndef QT_NO_DRAGANDDROP
06364   if( d->m_bDnd && d->m_bMousePressed &&
06365       ( (!d->m_strSelectedURL.isEmpty() && !isEditable())
06366         || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) ) ) {
06367     if ( ( d->m_dragStartPos - _mouse->pos() ).manhattanLength() <= KGlobalSettings::dndEventDelay() )
06368       return;
06369 
06370     QPixmap pix;
06371     HTMLImageElementImpl *img = 0L;
06372     QDragObject *drag = 0;
06373     KURL u;
06374 
06375     // qDebug("****************** Event URL: %s", url.string().latin1());
06376     // qDebug("****************** Event Target: %s", target.string().latin1());
06377 
06378     // Normal image...
06379     if ( url.length() == 0 && innerNode.handle() && innerNode.handle()->id() == ID_IMG )
06380     {
06381       img = static_cast<HTMLImageElementImpl *>(innerNode.handle());
06382       u = KURL( completeURL( khtml::parseURL(img->getAttribute(ATTR_SRC)).string() ) );
06383       pix = KMimeType::mimeType("image/png")->pixmap(KIcon::Desktop);
06384     }
06385     else
06386     {
06387       // Text or image link...
06388       u = completeURL( d->m_strSelectedURL );
06389       pix = KMimeType::pixmapForURL(u, 0, KIcon::Desktop, KIcon::SizeMedium);
06390     }
06391 
06392     u.setPass(QString::null);
06393 
06394     KURLDrag* urlDrag = new KURLDrag( u, img ? 0 : d->m_view->viewport() );
06395     if ( !d->m_referrer.isEmpty() )
06396       urlDrag->metaData()["referrer"] = d->m_referrer;
06397 
06398     if( img && img->complete()) {
06399       KMultipleDrag *mdrag = new KMultipleDrag( d->m_view->viewport() );
06400       mdrag->addDragObject( new QImageDrag( img->currentImage(), 0L ) );
06401       mdrag->addDragObject( urlDrag );
06402       drag = mdrag;
06403     }
06404     else
06405       drag = urlDrag;
06406 
06407     if ( !pix.isNull() )
06408       drag->setPixmap( pix );
06409 
06410     stopAutoScroll();
06411     if(drag)
06412       drag->drag();
06413 
06414     // when we finish our drag, we need to undo our mouse press
06415     d->m_bMousePressed = false;
06416     d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
06417     return;
06418   }
06419 #endif
06420 
06421   // Not clicked -> mouse over stuff
06422   if ( !d->m_bMousePressed )
06423   {
06424     // The mouse is over something
06425     if ( url.length() )
06426     {
06427       bool shiftPressed = ( _mouse->state() & ShiftButton );
06428 
06429       // Image map
06430       if ( !innerNode.isNull() && innerNode.elementId() == ID_IMG )
06431       {
06432         HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
06433         if ( i && i->isServerMap() )
06434         {
06435           khtml::RenderObject *r = i->renderer();
06436           if(r)
06437           {
06438             int absx, absy, vx, vy;
06439             r->absolutePosition(absx, absy);
06440             view()->contentsToViewport( absx, absy, vx, vy );
06441 
06442             int x(_mouse->x() - vx), y(_mouse->y() - vy);
06443 
06444             d->m_overURL = url.string() + QString("?%1,%2").arg(x).arg(y);
06445             d->m_overURLTarget = target.string();
06446             overURL( d->m_overURL, target.string(), shiftPressed );
06447             return;
06448           }
06449         }
06450       }
06451 
06452       // normal link
06453       if ( d->m_overURL.isEmpty() || d->m_overURL != url || d->m_overURLTarget != target )
06454       {
06455         d->m_overURL = url.string();
06456         d->m_overURLTarget = target.string();
06457         overURL( d->m_overURL, target.string(), shiftPressed );
06458       }
06459     }
06460     else  // Not over a link...
06461     {
06462       // reset to "default statusbar text"
06463       resetHoverText();
06464     }
06465   }
06466   else {
06467 #ifndef KHTML_NO_SELECTION
06468     // selection stuff
06469     if( d->m_bMousePressed && innerNode.handle() && innerNode.handle()->renderer() &&
06470         ( (_mouse->state() & LeftButton) != 0 )) {
06471       extendSelectionTo(event->x(), event->y(),
06472                         event->absX(), event->absY(), innerNode);
06473 #else
06474       if ( d->m_doc && d->m_view ) {
06475         QPoint diff( _mouse->globalPos() - d->m_dragLastPos );
06476 
06477         if ( abs( diff.x() ) > 64 || abs( diff.y() ) > 64 ) {
06478           d->m_view->scrollBy( -diff.x(), -diff.y() );
06479           d->m_dragLastPos = _mouse->globalPos();
06480         }
06481 #endif
06482     }
06483   }
06484 
06485 }
06486 
06487 void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
06488 {
06489   DOM::Node innerNode = event->innerNode();
06490   d->m_mousePressNode = DOM::Node();
06491 
06492   if ( d->m_bMousePressed ) {
06493     setStatusBarText(QString::null, BarHoverText);
06494     stopAutoScroll();
06495   }
06496 
06497   // Used to prevent mouseMoveEvent from initiating a drag before
06498   // the mouse is pressed again.
06499   d->m_bMousePressed = false;
06500 
06501   QMouseEvent *_mouse = event->qmouseEvent();
06502   if ( _mouse->button() == RightButton && parentPart() != 0 && d->m_bBackRightClick )
06503   {
06504     d->m_bRightMousePressed = false;
06505     KParts::BrowserInterface *tmp_iface = d->m_extension->browserInterface();
06506     if( tmp_iface ) {
06507       tmp_iface->callMethod( "goHistory(int)", -1 );
06508     }
06509   }
06510 #ifndef QT_NO_CLIPBOARD
06511   if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == MidButton) && (event->url().isNull())) {
06512     kdDebug( 6050 ) << "KHTMLPart::khtmlMouseReleaseEvent() MMB shouldOpen="
06513                     << d->m_bOpenMiddleClick << endl;
06514 
06515     if (d->m_bOpenMiddleClick) {
06516     KHTMLPart *p = this;
06517     while (p->parentPart()) p = p->parentPart();
06518     p->d->m_extension->pasteRequest();
06519   }
06520   }
06521 #endif
06522 
06523 #ifndef KHTML_NO_SELECTION
06524   // delete selection in case start and end position are at the same point
06525   if(d->m_selectionStart == d->m_selectionEnd && d->m_startOffset == d->m_endOffset) {
06526 #ifndef KHTML_NO_CARET
06527     d->m_extendAtEnd = true;
06528 #else
06529     d->m_selectionStart = 0;
06530     d->m_selectionEnd = 0;
06531     d->m_startOffset = 0;
06532     d->m_endOffset = 0;
06533 #endif
06534     emitSelectionChanged();
06535   } else {
06536     // we have to get to know if end is before start or not...
06537 //     kdDebug(6000) << "rel: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << ")" << endl;
06538     DOM::Node n = d->m_selectionStart;
06539     d->m_startBeforeEnd = false;
06540     if( d->m_selectionStart == d->m_selectionEnd ) {
06541       if( d->m_startOffset < d->m_endOffset )
06542         d->m_startBeforeEnd = true;
06543     } else {
06544 #if 0
06545       while(!n.isNull()) {
06546         if(n == d->m_selectionEnd) {
06547           d->m_startBeforeEnd = true;
06548           break;
06549         }
06550         DOM::Node next = n.firstChild();
06551         if(next.isNull()) next = n.nextSibling();
06552         while( next.isNull() && !n.parentNode().isNull() ) {
06553           n = n.parentNode();
06554           next = n.nextSibling();
06555         }
06556         n = next;
06557       }
06558 #else
06559       // shouldn't be null but it can happen with dynamic updating of nodes
06560       if (d->m_selectionStart.isNull() || d->m_selectionEnd.isNull() ||
06561           !d->m_selectionStart.handle()->renderer() ||
06562           !d->m_selectionEnd.handle()->renderer()) return;
06563       d->m_startBeforeEnd = RangeImpl::compareBoundaryPoints(
06564                 d->m_selectionStart.handle(), d->m_startOffset,
06565             d->m_selectionEnd.handle(), d->m_endOffset) <= 0;
06566 #endif
06567     }
06568     if(!d->m_startBeforeEnd)
06569     {
06570       DOM::Node tmpNode = d->m_selectionStart;
06571       int tmpOffset = d->m_startOffset;
06572       d->m_selectionStart = d->m_selectionEnd;
06573       d->m_startOffset = d->m_endOffset;
06574       d->m_selectionEnd = tmpNode;
06575       d->m_endOffset = tmpOffset;
06576       d->m_startBeforeEnd = true;
06577       d->m_extendAtEnd = !d->m_extendAtEnd;
06578     }
06579 #ifndef KHTML_NO_CARET
06580     bool v = d->m_view->placeCaret();
06581     emitCaretPositionChanged(v ? d->caretNode() : 0, d->caretOffset());
06582 #endif
06583     // get selected text and paste to the clipboard
06584 #ifndef QT_NO_CLIPBOARD
06585     QString text = selectedText();
06586     text.replace(QChar(0xa0), ' ');
06587     disconnect( kapp->clipboard(), SIGNAL( selectionChanged()), this, SLOT( slotClearSelection()));
06588     kapp->clipboard()->setText(text,QClipboard::Selection);
06589     connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
06590 #endif
06591     //kdDebug( 6000 ) << "selectedText = " << text << endl;
06592     emitSelectionChanged();
06593 //kdDebug(6000) << "rel2: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << "), caretOfs " << d->caretOffset() << endl;
06594   }
06595 #endif
06596   d->m_initialNode = 0;     // don't hold nodes longer than necessary
06597   d->m_initialOffset = 0;
06598 
06599 }
06600 
06601 void KHTMLPart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * )
06602 {
06603 }
06604 
06605 void KHTMLPart::guiActivateEvent( KParts::GUIActivateEvent *event )
06606 {
06607   if ( event->activated() )
06608   {
06609     emitSelectionChanged();
06610     emit d->m_extension->enableAction( "print", d->m_doc != 0 );
06611 
06612     if ( !d->m_settings->autoLoadImages() && d->m_paLoadImages )
06613     {
06614         QPtrList<KAction> lst;
06615         lst.append( d->m_paLoadImages );
06616         plugActionList( "loadImages", lst );
06617     }
06618   }
06619 }
06620 
06621 void KHTMLPart::slotPrintFrame()
06622 {
06623   if ( d->m_frames.count() == 0 )
06624     return;
06625 
06626   KParts::ReadOnlyPart *frame = currentFrame();
06627   if (!frame)
06628     return;
06629 
06630   KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject( frame );
06631 
06632   if ( !ext )
06633     return;
06634 
06635   QMetaObject *mo = ext->metaObject();
06636 
06637   int idx = mo->findSlot( "print()", true );
06638   if ( idx >= 0 ) {
06639     QUObject o[ 1 ];
06640     ext->qt_invoke( idx, o );
06641   }
06642 }
06643 
06644 void KHTMLPart::slotSelectAll()
06645 {
06646   KParts::ReadOnlyPart *part = currentFrame();
06647   if (part && part->inherits("KHTMLPart"))
06648     static_cast<KHTMLPart *>(part)->selectAll();
06649 }
06650 
06651 void KHTMLPart::startAutoScroll()
06652 {
06653    connect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ));
06654    d->m_scrollTimer.start(100, false);
06655 }
06656 
06657 void KHTMLPart::stopAutoScroll()
06658 {
06659    disconnect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() ));
06660    if (d->m_scrollTimer.isActive())
06661        d->m_scrollTimer.stop();
06662 }
06663 
06664 
06665 void KHTMLPart::slotAutoScroll()
06666 {
06667     if (d->m_view)
06668       d->m_view->doAutoScroll();
06669     else
06670       stopAutoScroll(); // Safety
06671 }
06672 
06673 void KHTMLPart::runAdFilter()
06674 {
06675     if ( parentPart() )
06676         parentPart()->runAdFilter();
06677 
06678     if ( !d->m_doc )
06679         return;
06680 
06681     QPtrDictIterator<khtml::CachedObject> it( d->m_doc->docLoader()->m_docObjects );
06682     for ( ; it.current(); ++it )
06683         if ( it.current()->type() == khtml::CachedObject::Image ) {
06684             khtml::CachedImage *image = static_cast<khtml::CachedImage *>(it.current());
06685             bool wasBlocked = image->m_wasBlocked;
06686             image->m_wasBlocked = KHTMLFactory::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( (*it).url().string() ) );
06687             if ( image->m_wasBlocked != wasBlocked )
06688                 image->do_notify(image->pixmap(), image->valid_rect());
06689         }
06690 
06691     if ( KHTMLFactory::defaultHTMLSettings()->isHideAdsEnabled() ) {
06692         for ( NodeImpl *nextNode, *node = d->m_doc; node; node = nextNode ) {
06693 
06694             // We might be deleting 'node' shortly.
06695             nextNode = node->traverseNextNode();
06696 
06697             if ( node->id() == ID_IMG ||
06698                  node->id() == ID_IFRAME ||
06699                  (node->id() == ID_INPUT && !strcasecmp( static_cast<ElementImpl *>(node)->getAttribute(ATTR_TYPE), "image")) )
06700             {
06701                 if ( KHTMLFactory::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( static_cast<ElementImpl *>(node)->getAttribute(ATTR_SRC).string() ) ) )
06702                 {
06703                     // We found an IMG, IFRAME or INPUT (of type "image") matching a filter.
06704 
06705                     // Detach the node from the document and rendering trees.
06706                     node->detach();
06707 
06708                     // Connect its siblings to each other instead.
06709                     NodeImpl *next = node->nextSibling();
06710                     NodeImpl *prev = node->previousSibling();
06711 
06712                     if( next ) next->setPreviousSibling( prev );
06713                     if( prev ) prev->setNextSibling( next );
06714 
06715                     // If it's the first or last child of its parent, we cut it off there too.
06716                     NodeImpl *parent = node->parent();
06717                     if( parent )
06718                     {
06719                         if( node == parent->firstChild() )
06720                             parent->setFirstChild( next );
06721 
06722                         if( node == parent->lastChild() )
06723                             parent->setLastChild( prev );
06724                     }
06725 
06726                     node->removedFromDocument();
06727 
06728                     // If nobody needs this node, we can safely delete it.
06729                     if( !node->refCount() )
06730                         delete node;
06731                 }
06732             }
06733         }
06734     }
06735 }
06736 
06737 void KHTMLPart::selectAll()
06738 {
06739   if (!d->m_doc) return;
06740 
06741   NodeImpl *first;
06742   if (d->m_doc->isHTMLDocument())
06743     first = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
06744   else
06745     first = d->m_doc;
06746   NodeImpl *next;
06747 
06748   // Look for first text/cdata node that has a renderer,
06749   // or first childless replaced element
06750   while ( first && !(first->renderer()
06751     && ((first->nodeType() == Node::TEXT_NODE || first->nodeType() == Node::CDATA_SECTION_NODE)
06752         || (first->renderer()->isReplaced() && !first->renderer()->firstChild()))))
06753   {
06754     next = first->firstChild();
06755     if ( !next ) next = first->nextSibling();
06756     while( first && !next )
06757     {
06758       first = first->parentNode();
06759       if ( first )
06760         next = first->nextSibling();
06761     }
06762     first = next;
06763   }
06764 
06765   NodeImpl *last;
06766   if (d->m_doc->isHTMLDocument())
06767     last = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
06768   else
06769     last = d->m_doc;
06770   // Look for last text/cdata node that has a renderer,
06771   // or last childless replaced element
06772   // ### Instead of changing this loop, use findLastSelectableNode
06773   // in render_table.cpp (LS)
06774   while ( last && !(last->renderer()
06775     && ((last->nodeType() == Node::TEXT_NODE || last->nodeType() == Node::CDATA_SECTION_NODE)
06776         || (last->renderer()->isReplaced() && !last->renderer()->lastChild()))))
06777   {
06778     next = last->lastChild();
06779     if ( !next ) next = last->previousSibling();
06780     while ( last && !next )
06781     {
06782       last = last->parentNode();
06783       if ( last )
06784         next = last->previousSibling();
06785     }
06786     last = next;
06787   }
06788 
06789   if ( !first || !last )
06790     return;
06791   Q_ASSERT(first->renderer());
06792   Q_ASSERT(last->renderer());
06793   d->m_selectionStart = first;
06794   d->m_startOffset = 0;
06795   d->m_selectionEnd = last;
06796   d->m_endOffset = last->nodeValue().length();
06797   d->m_startBeforeEnd = true;
06798 
06799   d->m_doc->setSelection( d->m_selectionStart.handle(), d->m_startOffset,
06800                           d->m_selectionEnd.handle(), d->m_endOffset );
06801 
06802   emitSelectionChanged();
06803 }
06804 
06805 bool KHTMLPart::checkLinkSecurity(const KURL &linkURL,const QString &message, const QString &button)
06806 {
06807   bool linkAllowed = true;
06808 
06809   if ( d->m_doc )
06810     linkAllowed = kapp && kapp->authorizeURLAction("redirect", url(), linkURL);
06811 
06812   if ( !linkAllowed ) {
06813     khtml::Tokenizer *tokenizer = d->m_doc->tokenizer();
06814     if (tokenizer)
06815       tokenizer->setOnHold(true);
06816 
06817     int response = KMessageBox::Cancel;
06818     if (!message.isEmpty())
06819     {
06820         response = KMessageBox::warningContinueCancel( 0,
06821                                message.arg(linkURL.htmlURL()),
06822                                i18n( "Security Warning" ),
06823                                button);
06824     }
06825     else
06826     {
06827         KMessageBox::error( 0,
06828                 i18n( "<qt>Access by untrusted page to<BR><B>%1</B><BR> denied.").arg(linkURL.htmlURL()),
06829                 i18n( "Security Alert" ));
06830     }
06831 
06832     if (tokenizer)
06833        tokenizer->setOnHold(false);
06834     return (response==KMessageBox::Continue);
06835   }
06836   return true;
06837 }
06838 
06839 void KHTMLPart::slotPartRemoved( KParts::Part *part )
06840 {
06841 //    kdDebug(6050) << "KHTMLPart::slotPartRemoved " << part << endl;
06842     if ( part == d->m_activeFrame )
06843     {
06844         d->m_activeFrame = 0L;
06845         if ( !part->inherits( "KHTMLPart" ) )
06846         {
06847             if (factory()) {
06848                 factory()->removeClient( part );
06849             }
06850             if (childClients()->containsRef(part)) {
06851                 removeChildClient( part );
06852             }
06853         }
06854     }
06855 }
06856 
06857 void KHTMLPart::slotActiveFrameChanged( KParts::Part *part )
06858 {
06859 //    kdDebug(6050) << "KHTMLPart::slotActiveFrameChanged this=" << this << "part=" << part << endl;
06860     if ( part == this )
06861     {
06862         kdError(6050) << "strange error! we activated ourselves" << endl;
06863         assert( false );
06864         return;
06865     }
06866 //    kdDebug(6050) << "KHTMLPart::slotActiveFrameChanged d->m_activeFrame=" << d->m_activeFrame << endl;
06867     if ( d->m_activeFrame && d->m_activeFrame->widget() && d->m_activeFrame->widget()->inherits( "QFrame" ) )
06868     {
06869         QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
06870         if (frame->frameStyle() != QFrame::NoFrame)
06871         {
06872            frame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken);
06873            frame->repaint();
06874         }
06875     }
06876 
06877     if( d->m_activeFrame && !d->m_activeFrame->inherits( "KHTMLPart" ) )
06878     {
06879         if (factory()) {
06880             factory()->removeClient( d->m_activeFrame );
06881         }
06882         removeChildClient( d->m_activeFrame );
06883     }
06884     if( part && !part->inherits( "KHTMLPart" ) )
06885     {
06886         if (factory()) {
06887             factory()->addClient( part );
06888         }
06889         insertChildClient( part );
06890     }
06891 
06892 
06893     d->m_activeFrame = part;
06894 
06895     if ( d->m_activeFrame && d->m_activeFrame->widget()->inherits( "QFrame" ) )
06896     {
06897         QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
06898         if (frame->frameStyle() != QFrame::NoFrame)
06899         {
06900            frame->setFrameStyle( QFrame::StyledPanel | QFrame::Plain);
06901            frame->repaint();
06902         }
06903         kdDebug(6050) << "new active frame " << d->m_activeFrame << endl;
06904     }
06905 
06906     updateActions();
06907 
06908     // (note: childObject returns 0 if the argument is 0)
06909     d->m_extension->setExtensionProxy( KParts::BrowserExtension::childObject( d->m_activeFrame ) );
06910 }
06911 
06912 void KHTMLPart::setActiveNode(const DOM::Node &node)
06913 {
06914     if (!d->m_doc || !d->m_view)
06915         return;
06916 
06917     // Set the document's active node
06918     d->m_doc->setFocusNode(node.handle());
06919 
06920     // Scroll the view if necessary to ensure that the new focus node is visible
06921     QRect rect  = node.handle()->getRect();
06922     d->m_view->ensureVisible(rect.right(), rect.bottom());
06923     d->m_view->ensureVisible(rect.left(), rect.top());
06924 }
06925 
06926 DOM::Node KHTMLPart::activeNode() const
06927 {
06928     return DOM::Node(d->m_doc?d->m_doc->focusNode():0);
06929 }
06930 
06931 DOM::EventListener *KHTMLPart::createHTMLEventListener( QString code, QString name, NodeImpl* node )
06932 {
06933   KJSProxy *proxy = jScript();
06934 
06935   if (!proxy)
06936     return 0;
06937 
06938   return proxy->createHTMLEventHandler( m_url.url(), name, code, node );
06939 }
06940 
06941 KHTMLPart *KHTMLPart::opener()
06942 {
06943     return d->m_opener;
06944 }
06945 
06946 void KHTMLPart::setOpener(KHTMLPart *_opener)
06947 {
06948     d->m_opener = _opener;
06949 }
06950 
06951 bool KHTMLPart::openedByJS()
06952 {
06953     return d->m_openedByJS;
06954 }
06955 
06956 void KHTMLPart::setOpenedByJS(bool _openedByJS)
06957 {
06958     d->m_openedByJS = _openedByJS;
06959 }
06960 
06961 void KHTMLPart::preloadStyleSheet(const QString &url, const QString &stylesheet)
06962 {
06963     khtml::Cache::preloadStyleSheet(url, stylesheet);
06964 }
06965 
06966 void KHTMLPart::preloadScript(const QString &url, const QString &script)
06967 {
06968     khtml::Cache::preloadScript(url, script);
06969 }
06970 
06971 QCString KHTMLPart::dcopObjectId() const
06972 {
06973   QCString id;
06974   id.sprintf("html-widget%d", d->m_dcop_counter);
06975   return id;
06976 }
06977 
06978 long KHTMLPart::cacheId() const
06979 {
06980   return d->m_cacheId;
06981 }
06982 
06983 bool KHTMLPart::restored() const
06984 {
06985   return d->m_restored;
06986 }
06987 
06988 bool KHTMLPart::pluginPageQuestionAsked(const QString& mimetype) const
06989 {
06990   // parentPart() should be const!
06991   KHTMLPart* parent = const_cast<KHTMLPart *>(this)->parentPart();
06992   if ( parent )
06993     return parent->pluginPageQuestionAsked(mimetype);
06994 
06995   return d->m_pluginPageQuestionAsked.contains(mimetype);
06996 }
06997 
06998 void KHTMLPart::setPluginPageQuestionAsked(const QString& mimetype)
06999 {
07000   if ( parentPart() )
07001     parentPart()->setPluginPageQuestionAsked(mimetype);
07002 
07003   d->m_pluginPageQuestionAsked.append(mimetype);
07004 }
07005 
07006 void KHTMLPart::slotAutomaticDetectionLanguage( int _id )
07007 {
07008   d->m_automaticDetection->setItemChecked( _id, true );
07009 
07010   switch ( _id ) {
07011     case 0 :
07012       d->m_autoDetectLanguage = khtml::Decoder::SemiautomaticDetection;
07013       break;
07014     case 1 :
07015       d->m_autoDetectLanguage = khtml::Decoder::Arabic;
07016       break;
07017     case 2 :
07018       d->m_autoDetectLanguage = khtml::Decoder::Baltic;
07019       break;
07020     case 3 :
07021       d->m_autoDetectLanguage = khtml::Decoder::CentralEuropean;
07022       break;
07023     case 4 :
07024       d->m_autoDetectLanguage = khtml::Decoder::Chinese;
07025       break;
07026     case 5 :
07027       d->m_autoDetectLanguage = khtml::Decoder::Greek;
07028       break;
07029     case 6 :
07030       d->m_autoDetectLanguage = khtml::Decoder::Hebrew;
07031       break;
07032     case 7 :
07033       d->m_autoDetectLanguage = khtml::Decoder::Japanese;
07034       break;
07035     case 8 :
07036       d->m_autoDetectLanguage = khtml::Decoder::Korean;
07037       break;
07038     case 9 :
07039       d->m_autoDetectLanguage = khtml::Decoder::Russian;
07040       break;
07041     case 10 :
07042       d->m_autoDetectLanguage = khtml::Decoder::Thai;
07043       break;
07044     case 11 :
07045       d->m_autoDetectLanguage = khtml::Decoder::Turkish;
07046       break;
07047     case 12 :
07048       d->m_autoDetectLanguage = khtml::Decoder::Ukrainian;
07049       break;
07050     case 13 :
07051       d->m_autoDetectLanguage = khtml::Decoder::Unicode;
07052       break;
07053     case 14 :
07054       d->m_autoDetectLanguage = khtml::Decoder::WesternEuropean;
07055       break;
07056     default :
07057       d->m_autoDetectLanguage = khtml::Decoder::SemiautomaticDetection;
07058       break;
07059   }
07060 
07061   for ( int i = 0; i <= 14; ++i ) {
07062     if ( i != _id )
07063       d->m_automaticDetection->setItemChecked( i, false );
07064   }
07065 
07066   d->m_paSetEncoding->popupMenu()->setItemChecked( 0, true );
07067 
07068   setEncoding( QString::null, false );
07069 
07070   if( d->m_manualDetection )
07071     d->m_manualDetection->setCurrentItem( -1 );
07072   d->m_paSetEncoding->popupMenu()->setItemChecked( d->m_paSetEncoding->popupMenu()->idAt( 2 ), false );
07073 }
07074 
07075 khtml::Decoder *KHTMLPart::createDecoder()
07076 {
07077     khtml::Decoder *dec = new khtml::Decoder();
07078     if( !d->m_encoding.isNull() )
07079         dec->setEncoding( d->m_encoding.latin1(),
07080             d->m_haveEncoding ? khtml::Decoder::UserChosenEncoding : khtml::Decoder::EncodingFromHTTPHeader);
07081     else {
07082         // Inherit the default encoding from the parent frame if there is one.
07083         const char *defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
07084             ? parentPart()->d->m_decoder->encoding() : settings()->encoding().latin1();
07085         dec->setEncoding(defaultEncoding, khtml::Decoder::DefaultEncoding);
07086     }
07087 #ifdef APPLE_CHANGES
07088     if (d->m_doc)
07089         d->m_doc->setDecoder(d->m_decoder);
07090 #endif
07091     dec->setAutoDetectLanguage( d->m_autoDetectLanguage );
07092     return dec;
07093 }
07094 
07095 void KHTMLPart::emitCaretPositionChanged(const DOM::Node &node, long offset) {
07096   emit caretPositionChanged(node, offset);
07097 }
07098 
07099 void KHTMLPart::restoreScrollPosition()
07100 {
07101   KParts::URLArgs args = d->m_extension->urlArgs();
07102 
07103   if ( m_url.hasRef() && !d->m_restoreScrollPosition && !args.reload) {
07104     if ( !d->m_doc || !d->m_doc->parsing() )
07105       disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
07106     if ( !gotoAnchor(m_url.encodedHtmlRef()) )
07107       gotoAnchor(m_url.htmlRef());
07108     return;
07109   }
07110 
07111   // Check whether the viewport has become large enough to encompass the stored
07112   // offsets. If the document has been fully loaded, force the new coordinates,
07113   // even if the canvas is too short (can happen when user resizes the window
07114   // during loading).
07115   if (d->m_view->contentsHeight() - d->m_view->visibleHeight() >= args.yOffset
07116       || d->m_bComplete) {
07117     d->m_view->setContentsPos(args.xOffset, args.yOffset);
07118     disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
07119   }
07120 }
07121 
07122 
07123 void KHTMLPart::openWallet(DOM::HTMLFormElementImpl *form)
07124 {
07125 #ifndef KHTML_NO_WALLET
07126   KHTMLPart *p;
07127 
07128   for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
07129   }
07130 
07131   if (p) {
07132     p->openWallet(form);
07133     return;
07134   }
07135 
07136   if (onlyLocalReferences()) { // avoid triggering on local apps, thumbnails
07137     return;
07138   }
07139 
07140   if (d->m_wallet) {
07141     if (d->m_bWalletOpened) {
07142       if (d->m_wallet->isOpen()) {
07143         form->walletOpened(d->m_wallet);
07144         return;
07145       }
07146       d->m_wallet->deleteLater();
07147       d->m_wallet = 0L;
07148       d->m_bWalletOpened = false;
07149     }
07150   }
07151 
07152   if (!d->m_wq) {
07153     KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
07154     d->m_wq = new KHTMLWalletQueue(this);
07155     d->m_wq->wallet = wallet;
07156     connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
07157     connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
07158   }
07159   assert(form);
07160   d->m_wq->callers.append(KHTMLWalletQueue::Caller(form, form->getDocument()));
07161 #endif // KHTML_NO_WALLET
07162 }
07163 
07164 
07165 void KHTMLPart::saveToWallet(const QString& key, const QMap<QString,QString>& data)
07166 {
07167 #ifndef KHTML_NO_WALLET
07168   KHTMLPart *p;
07169 
07170   for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
07171   }
07172 
07173   if (p) {
07174     p->saveToWallet(key, data);
07175     return;
07176   }
07177 
07178   if (d->m_wallet) {
07179     if (d->m_bWalletOpened) {
07180       if (d->m_wallet->isOpen()) {
07181         if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder())) {
07182           d->m_wallet->createFolder(KWallet::Wallet::FormDataFolder());
07183         }
07184         d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder());
07185         d->m_wallet->writeMap(key, data);
07186         return;
07187       }
07188       d->m_wallet->deleteLater();
07189       d->m_wallet = 0L;
07190       d->m_bWalletOpened = false;
07191     }
07192   }
07193 
07194   if (!d->m_wq) {
07195     KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
07196     d->m_wq = new KHTMLWalletQueue(this);
07197     d->m_wq->wallet = wallet;
07198     connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
07199     connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
07200   }
07201   d->m_wq->savers.append(qMakePair(key, data));
07202 #endif // KHTML_NO_WALLET
07203 }
07204 
07205 
07206 void KHTMLPart::dequeueWallet(DOM::HTMLFormElementImpl *form) {
07207 #ifndef KHTML_NO_WALLET
07208   KHTMLPart *p;
07209 
07210   for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
07211   }
07212 
07213   if (p) {
07214     p->dequeueWallet(form);
07215     return;
07216   }
07217 
07218   if (d->m_wq) {
07219     d->m_wq->callers.remove(KHTMLWalletQueue::Caller(form, form->getDocument()));
07220   }
07221 #endif // KHTML_NO_WALLET
07222 }
07223 
07224 
07225 void KHTMLPart::walletOpened(KWallet::Wallet *wallet) {
07226 #ifndef KHTML_NO_WALLET
07227   assert(!d->m_wallet);
07228   assert(d->m_wq);
07229 
07230   d->m_wq->deleteLater(); // safe?
07231   d->m_wq = 0L;
07232 
07233   if (!wallet) {
07234     d->m_bWalletOpened = false;
07235     return;
07236   }
07237 
07238   d->m_wallet = wallet;
07239   d->m_bWalletOpened = true;
07240   connect(d->m_wallet, SIGNAL(walletClosed()), SLOT(slotWalletClosed()));
07241 
07242   if (!d->m_statusBarWalletLabel) {
07243     d->m_statusBarWalletLabel = new KURLLabel(d->m_statusBarExtension->statusBar());
07244     d->m_statusBarWalletLabel->setFixedHeight(instance()->iconLoader()->currentSize(KIcon::Small));
07245     d->m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
07246     d->m_statusBarWalletLabel->setUseCursor(false);
07247     d->m_statusBarExtension->addStatusBarItem(d->m_statusBarWalletLabel, 0, false);
07248     d->m_statusBarWalletLabel->setPixmap(SmallIcon("wallet_open", instance()));
07249     connect(d->m_statusBarWalletLabel, SIGNAL(leftClickedURL()), SLOT(launchWalletManager()));
07250     connect(d->m_statusBarWalletLabel, SIGNAL(rightClickedURL()), SLOT(walletMenu()));
07251   } else {
07252     QToolTip::remove(d->m_statusBarWalletLabel);
07253   }
07254   QToolTip::add(d->m_statusBarWalletLabel, i18n("The wallet '%1' is open and being used for form data and passwords.").arg(KWallet::Wallet::NetworkWallet()));
07255 #endif // KHTML_NO_WALLET
07256 }
07257 
07258 
07259 KWallet::Wallet *KHTMLPart::wallet()
07260 {
07261 #ifndef KHTML_NO_WALLET
07262   KHTMLPart *p;
07263 
07264   for (p = parentPart(); p && p->parentPart(); p = p->parentPart())
07265     ;
07266 
07267   if (p)
07268     return p->wallet();
07269 
07270 #endif // KHTML_NO_WALLET
07271   return d->m_wallet;
07272 }
07273 
07274 
07275 void KHTMLPart::slotWalletClosed()
07276 {
07277 #ifndef KHTML_NO_WALLET
07278   if (d->m_wallet) {
07279     d->m_wallet->deleteLater();
07280     d->m_wallet = 0L;
07281   }
07282   d->m_bWalletOpened = false;
07283   if (d->m_statusBarWalletLabel) {
07284     d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarWalletLabel);
07285     delete d->m_statusBarWalletLabel;
07286     d->m_statusBarWalletLabel = 0L;
07287   }
07288 #endif // KHTML_NO_WALLET
07289 }
07290 
07291 void KHTMLPart::launchWalletManager()
07292 {
07293 #ifndef KHTML_NO_WALLET
07294   if (!DCOPClient::mainClient()->isApplicationRegistered("kwalletmanager")) {
07295     KApplication::startServiceByDesktopName("kwalletmanager_show");
07296   } else {
07297     DCOPRef r("kwalletmanager", "kwalletmanager-mainwindow#1");
07298     r.send("show");
07299     r.send("raise");
07300   }
07301 #endif // KHTML_NO_WALLET
07302 }
07303 
07304 void KHTMLPart::walletMenu()
07305 {
07306 #ifndef KHTML_NO_WALLET
07307   KPopupMenu *m = new KPopupMenu(0L);
07308   m->insertItem(i18n("&Close Wallet"), this, SLOT(slotWalletClosed()));
07309   m->popup(QCursor::pos());
07310 #endif // KHTML_NO_WALLET
07311 }
07312 
07313 void KHTMLPart::slotToggleCaretMode()
07314 {
07315   setCaretMode(d->m_paToggleCaretMode->isChecked());
07316 }
07317 
07318 void KHTMLPart::setFormNotification(KHTMLPart::FormNotification fn) {
07319   d->m_formNotification = fn;
07320 }
07321 
07322 KHTMLPart::FormNotification KHTMLPart::formNotification() const {
07323   return d->m_formNotification;
07324 }
07325 
07326 KURL KHTMLPart::toplevelURL()
07327 {
07328   KHTMLPart* part = this;
07329   while (part->parentPart())
07330     part = part->parentPart();
07331 
07332   if (!part)
07333     return KURL();
07334 
07335   return part->url();
07336 }
07337 
07338 bool KHTMLPart::isModified() const
07339 {
07340   if ( !d->m_doc )
07341     return false;
07342 
07343   return d->m_doc->unsubmittedFormChanges();
07344 }
07345 
07346 void KHTMLPart::setDebugScript( bool enable )
07347 {
07348   unplugActionList( "debugScriptList" );
07349   if ( enable ) {
07350     if (!d->m_paDebugScript) {
07351       d->m_paDebugScript = new KAction( i18n( "JavaScript &Debugger" ), 0, this, SLOT( slotDebugScript() ), actionCollection(), "debugScript" );
07352     }
07353     d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
07354     QPtrList<KAction> lst;
07355     lst.append( d->m_paDebugScript );
07356     plugActionList( "debugScriptList", lst );
07357   }
07358   d->m_bJScriptDebugEnabled = enable;
07359 }
07360 
07361 void KHTMLPart::setSuppressedPopupIndicator( bool enable )
07362 {
07363     setSuppressedPopupIndicator( enable, 0 );
07364 }
07365 
07366 void KHTMLPart::setSuppressedPopupIndicator( bool enable, KHTMLPart *originPart )
07367 {
07368     if ( parentPart() ) {
07369         parentPart()->setSuppressedPopupIndicator( enable, originPart );
07370         return;
07371     }
07372 
07373     if ( enable && originPart ) {
07374         d->m_openableSuppressedPopups++;
07375         if ( d->m_suppressedPopupOriginParts.find( originPart ) == -1 )
07376             d->m_suppressedPopupOriginParts.append( originPart );
07377     }
07378 
07379     if ( enable && !d->m_statusBarPopupLabel ) {
07380         d->m_statusBarPopupLabel = new KURLLabel( d->m_statusBarExtension->statusBar() );
07381         d->m_statusBarPopupLabel->setFixedHeight( instance()->iconLoader()->currentSize( KIcon::Small) );
07382         d->m_statusBarPopupLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ));
07383         d->m_statusBarPopupLabel->setUseCursor( false );
07384         d->m_statusBarExtension->addStatusBarItem( d->m_statusBarPopupLabel, 0, false );
07385         d->m_statusBarPopupLabel->setPixmap( SmallIcon( "window_suppressed", instance() ) );
07386         QToolTip::add( d->m_statusBarPopupLabel, i18n("This page was prevented from opening a new window via JavaScript." ) );
07387 
07388         connect(d->m_statusBarPopupLabel, SIGNAL(leftClickedURL()), SLOT(suppressedPopupMenu()));
07389         if (d->m_settings->jsPopupBlockerPassivePopup()) {
07390             QPixmap px;
07391             px = MainBarIcon( "window_suppressed" );
07392             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);
07393         }
07394     } else if ( !enable && d->m_statusBarPopupLabel ) {
07395         QToolTip::remove( d->m_statusBarPopupLabel );
07396         d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarPopupLabel );
07397         delete d->m_statusBarPopupLabel;
07398         d->m_statusBarPopupLabel = 0L;
07399     }
07400 }
07401 
07402 void KHTMLPart::suppressedPopupMenu() {
07403   KPopupMenu *m = new KPopupMenu(0L);
07404   m->setCheckable(true);
07405   if ( d->m_openableSuppressedPopups )
07406       m->insertItem(i18n("&Show Blocked Popup Window","Show %n Blocked Popup Windows", d->m_openableSuppressedPopups), this, SLOT(showSuppressedPopups()));
07407   m->insertItem(i18n("Show Blocked Window Passive Popup &Notification"), this, SLOT(togglePopupPassivePopup()),0,57);
07408   m->setItemChecked(57,d->m_settings->jsPopupBlockerPassivePopup());
07409   m->insertItem(i18n("&Configure JavaScript New Window Policies..."), this, SLOT(launchJSConfigDialog()));
07410   m->popup(QCursor::pos());
07411 }
07412 
07413 void KHTMLPart::togglePopupPassivePopup() {
07414   // Same hack as in disableJSErrorExtension()
07415   d->m_settings->setJSPopupBlockerPassivePopup( !d->m_settings->jsPopupBlockerPassivePopup() );
07416   DCOPClient::mainClient()->send("konqueror*", "KonquerorIface", "reparseConfiguration()", QByteArray());
07417 }
07418 
07419 void KHTMLPart::showSuppressedPopups() {
07420     for ( KHTMLPart* part = d->m_suppressedPopupOriginParts.first(); part; part = d->m_suppressedPopupOriginParts.next() ) {
07421        KJS::Window *w = KJS::Window::retrieveWindow( part );
07422        if (w) {
07423            w->showSuppressedWindows();
07424            w->forgetSuppressedWindows();
07425        }
07426     }
07427     setSuppressedPopupIndicator( false );
07428     d->m_openableSuppressedPopups = 0;
07429     d->m_suppressedPopupOriginParts.clear();
07430 }
07431 
07432 // Extension to use for "view document source", "save as" etc.
07433 // Using the right extension can help the viewer get into the right mode (#40496)
07434 QString KHTMLPart::defaultExtension() const
07435 {
07436     if ( !d->m_doc )
07437         return ".html";
07438     if ( !d->m_doc->isHTMLDocument() )
07439         return ".xml";
07440     return d->m_doc->htmlMode() == DOM::DocumentImpl::XHtml ? ".xhtml" : ".html";
07441 }
07442 
07443 bool KHTMLPart::inProgress() const
07444 {
07445     if (d->m_runningScripts || (d->m_doc && d->m_doc->parsing()))
07446         return true;
07447 
07448     // Any frame that hasn't completed yet ?
07449     ConstFrameIt it = d->m_frames.begin();
07450     const ConstFrameIt end = d->m_frames.end();
07451     for (; it != end; ++it ) {
07452         if ((*it)->m_run || !(*it)->m_bCompleted)
07453         return true;
07454     }
07455 
07456     return d->m_submitForm || !d->m_redirectURL.isEmpty() || d->m_redirectionTimer.isActive() || d->m_job;
07457 }
07458 
07459 using namespace KParts;
07460 #include "khtml_part.moc"
07461 #include "khtmlpart_p.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys