khtml_part.cpp

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