KHTML
khtml_part.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 * 00003 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 00004 * 1999 Lars Knoll <knoll@kde.org> 00005 * 1999 Antti Koivisto <koivisto@kde.org> 00006 * 2000 Simon Hausmann <hausmann@kde.org> 00007 * 2000 Stefan Schimanski <1Stein@gmx.de> 00008 * 2001-2005 George Staikos <staikos@kde.org> 00009 * 2001-2003 Dirk Mueller <mueller@kde.org> 00010 * 2000-2005 David Faure <faure@kde.org> 00011 * 2002 Apple Computer, Inc. 00012 * 2010 Maksim Orlovich (maksim@kde.org) 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 "ui_htmlpageinfo.h" 00034 00035 #include "khtmlviewbar.h" 00036 #include "khtml_pagecache.h" 00037 00038 #include "dom/dom_string.h" 00039 #include "dom/dom_element.h" 00040 #include "dom/dom_exception.h" 00041 #include "dom/html_document.h" 00042 #include "dom/dom2_range.h" 00043 #include "editing/editor.h" 00044 #include "html/html_documentimpl.h" 00045 #include "html/html_baseimpl.h" 00046 #include "html/html_objectimpl.h" 00047 #include "html/html_miscimpl.h" 00048 #include "html/html_imageimpl.h" 00049 #include "imload/imagemanager.h" 00050 #include "rendering/render_text.h" 00051 #include "rendering/render_frames.h" 00052 #include "rendering/render_layer.h" 00053 #include "rendering/render_position.h" 00054 #include "misc/loader.h" 00055 #include "misc/khtml_partaccessor.h" 00056 #include "xml/dom2_eventsimpl.h" 00057 #include "xml/dom2_rangeimpl.h" 00058 #include "xml/xml_tokenizer.h" 00059 #include "css/cssstyleselector.h" 00060 #include "css/csshelper.h" 00061 using namespace DOM; 00062 00063 #include "khtmlview.h" 00064 #include <kparts/partmanager.h> 00065 #include <kparts/browseropenorsavequestion.h> 00066 #include <kacceleratormanager.h> 00067 #include "ecma/kjs_proxy.h" 00068 #include "ecma/kjs_window.h" 00069 #include "khtml_settings.h" 00070 #include "kjserrordlg.h" 00071 00072 #include <kjs/function.h> 00073 #include <kjs/interpreter.h> 00074 00075 #include <sys/types.h> 00076 #include <assert.h> 00077 #include <unistd.h> 00078 00079 #include <config.h> 00080 00081 #include <kstandarddirs.h> 00082 #include <kstringhandler.h> 00083 #include <kio/job.h> 00084 #include <kio/jobuidelegate.h> 00085 #include <kio/global.h> 00086 #include <kio/netaccess.h> 00087 #include <kio/hostinfo_p.h> 00088 #include <kprotocolmanager.h> 00089 #include <kdebug.h> 00090 #include <kicon.h> 00091 #include <kiconloader.h> 00092 #include <klocale.h> 00093 #include <kmessagebox.h> 00094 #include <kstandardaction.h> 00095 #include <kstandardguiitem.h> 00096 #include <kactioncollection.h> 00097 #include <kfiledialog.h> 00098 #include <kmimetypetrader.h> 00099 #include <ktemporaryfile.h> 00100 #include <kglobalsettings.h> 00101 #include <ktoolinvocation.h> 00102 #include <kauthorized.h> 00103 #include <kparts/browserinterface.h> 00104 #include <kparts/scriptableextension.h> 00105 #include <kde_file.h> 00106 #include <kactionmenu.h> 00107 #include <ktoggleaction.h> 00108 #include <kcodecaction.h> 00109 #include <kselectaction.h> 00110 00111 #include <ksslinfodialog.h> 00112 #include <ksslsettings.h> 00113 00114 #include <kfileitem.h> 00115 #include <kurifilter.h> 00116 #include <kstatusbar.h> 00117 #include <kurllabel.h> 00118 00119 #include <QtGui/QClipboard> 00120 #include <QtGui/QToolTip> 00121 #include <QtCore/QFile> 00122 #include <QtCore/QMetaEnum> 00123 #include <QtGui/QTextDocument> 00124 #include <QtCore/QDate> 00125 #include <QtNetwork/QSslCertificate> 00126 00127 #include "khtmlpart_p.h" 00128 #include "khtml_iface.h" 00129 #include "kpassivepopup.h" 00130 #include "kmenu.h" 00131 #include "rendering/render_form.h" 00132 #include <kwindowsystem.h> 00133 #include <kconfiggroup.h> 00134 00135 #include "ecma/debugger/debugwindow.h" 00136 00137 // SVG 00138 #include <svg/SVGDocument.h> 00139 00140 bool KHTMLPartPrivate::s_dnsInitialised = false; 00141 00142 // DNS prefetch settings 00143 static const int sMaxDNSPrefetchPerPage = 42; 00144 static const int sDNSPrefetchTimerDelay = 200; 00145 static const int sDNSTTLSeconds = 400; 00146 static const int sDNSCacheSize = 500; 00147 00148 00149 namespace khtml { 00150 00151 class PartStyleSheetLoader : public CachedObjectClient 00152 { 00153 public: 00154 PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl) 00155 { 00156 m_part = part; 00157 m_cachedSheet = dl->requestStyleSheet(url, QString(), "text/css", 00158 true /* "user sheet" */); 00159 if (m_cachedSheet) 00160 m_cachedSheet->ref( this ); 00161 } 00162 virtual ~PartStyleSheetLoader() 00163 { 00164 if ( m_cachedSheet ) m_cachedSheet->deref(this); 00165 } 00166 virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet, const DOM::DOMString &, const DOM::DOMString &/*mimetype*/) 00167 { 00168 if ( m_part ) 00169 m_part->setUserStyleSheet( sheet.string() ); 00170 00171 delete this; 00172 } 00173 virtual void error( int, const QString& ) { 00174 delete this; 00175 } 00176 QPointer<KHTMLPart> m_part; 00177 khtml::CachedCSSStyleSheet *m_cachedSheet; 00178 }; 00179 } 00180 00181 KHTMLPart::KHTMLPart( QWidget *parentWidget, QObject *parent, GUIProfile prof ) 00182 : KParts::ReadOnlyPart( parent ) 00183 { 00184 d = 0; 00185 KHTMLGlobal::registerPart( this ); 00186 setComponentData( KHTMLGlobal::componentData(), false ); 00187 init( new KHTMLView( this, parentWidget ), prof ); 00188 } 00189 00190 KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, GUIProfile prof ) 00191 : KParts::ReadOnlyPart( parent ) 00192 { 00193 d = 0; 00194 KHTMLGlobal::registerPart( this ); 00195 setComponentData( KHTMLGlobal::componentData(), false ); 00196 assert( view ); 00197 if (!view->part()) 00198 view->setPart( this ); 00199 init( view, prof ); 00200 } 00201 00202 void KHTMLPart::init( KHTMLView *view, GUIProfile prof ) 00203 { 00204 if ( prof == DefaultGUI ) 00205 setXMLFile( "khtml.rc" ); 00206 else if ( prof == BrowserViewGUI ) 00207 setXMLFile( "khtml_browser.rc" ); 00208 00209 d = new KHTMLPartPrivate(this, parent()); 00210 00211 d->m_view = view; 00212 00213 if (!parentPart()) { 00214 QWidget *widget = new QWidget( view->parentWidget() ); 00215 widget->setObjectName("khtml_part_widget"); 00216 QVBoxLayout *layout = new QVBoxLayout( widget ); 00217 layout->setContentsMargins( 0, 0, 0, 0 ); 00218 layout->setSpacing( 0 ); 00219 widget->setLayout( layout ); 00220 00221 d->m_topViewBar = new KHTMLViewBar( KHTMLViewBar::Top, d->m_view, widget ); 00222 d->m_bottomViewBar = new KHTMLViewBar( KHTMLViewBar::Bottom, d->m_view, widget ); 00223 00224 layout->addWidget( d->m_topViewBar ); 00225 layout->addWidget( d->m_view ); 00226 layout->addWidget( d->m_bottomViewBar ); 00227 setWidget( widget ); 00228 widget->setFocusProxy( d->m_view ); 00229 } else { 00230 setWidget( view ); 00231 } 00232 00233 d->m_guiProfile = prof; 00234 d->m_extension = new KHTMLPartBrowserExtension( this ); 00235 d->m_extension->setObjectName( "KHTMLBrowserExtension" ); 00236 d->m_hostExtension = new KHTMLPartBrowserHostExtension( this ); 00237 d->m_statusBarExtension = new KParts::StatusBarExtension( this ); 00238 d->m_scriptableExtension = new KJS::KHTMLPartScriptable( this ); 00239 new KHTMLTextExtension( this ); 00240 new KHTMLHtmlExtension( this ); 00241 d->m_statusBarPopupLabel = 0L; 00242 d->m_openableSuppressedPopups = 0; 00243 00244 d->m_paLoadImages = 0; 00245 d->m_paDebugScript = 0; 00246 d->m_bMousePressed = false; 00247 d->m_bRightMousePressed = false; 00248 d->m_bCleared = false; 00249 00250 if ( prof == BrowserViewGUI ) { 00251 d->m_paViewDocument = new KAction( i18n( "View Do&cument Source" ), this ); 00252 actionCollection()->addAction( "viewDocumentSource", d->m_paViewDocument ); 00253 connect( d->m_paViewDocument, SIGNAL( triggered( bool ) ), this, SLOT( slotViewDocumentSource() ) ); 00254 if (!parentPart()) { 00255 d->m_paViewDocument->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_U) ); 00256 } 00257 00258 d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), this ); 00259 actionCollection()->addAction( "viewFrameSource", d->m_paViewFrame ); 00260 connect( d->m_paViewFrame, SIGNAL( triggered( bool ) ), this, SLOT( slotViewFrameSource() ) ); 00261 if (!parentPart()) { 00262 d->m_paViewFrame->setShortcut( QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_U) ); 00263 } 00264 00265 d->m_paViewInfo = new KAction( i18n( "View Document Information" ), this ); 00266 actionCollection()->addAction( "viewPageInfo", d->m_paViewInfo ); 00267 if (!parentPart()) { 00268 d->m_paViewInfo->setShortcut( QKeySequence(Qt::CTRL+Qt::Key_I) ); 00269 } 00270 connect( d->m_paViewInfo, SIGNAL( triggered( bool ) ), this, SLOT( slotViewPageInfo() ) ); 00271 00272 d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), this ); 00273 actionCollection()->addAction( "saveBackground", d->m_paSaveBackground ); 00274 connect( d->m_paSaveBackground, SIGNAL( triggered( bool ) ), this, SLOT( slotSaveBackground() ) ); 00275 00276 d->m_paSaveDocument = actionCollection()->addAction( KStandardAction::SaveAs, "saveDocument", 00277 this, SLOT( slotSaveDocument() ) ); 00278 if ( parentPart() ) 00279 d->m_paSaveDocument->setShortcuts( KShortcut() ); // avoid clashes 00280 00281 d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), this ); 00282 actionCollection()->addAction( "saveFrame", d->m_paSaveFrame ); 00283 connect( d->m_paSaveFrame, SIGNAL( triggered( bool ) ), this, SLOT( slotSaveFrame() ) ); 00284 } else { 00285 d->m_paViewDocument = 0; 00286 d->m_paViewFrame = 0; 00287 d->m_paViewInfo = 0; 00288 d->m_paSaveBackground = 0; 00289 d->m_paSaveDocument = 0; 00290 d->m_paSaveFrame = 0; 00291 } 00292 00293 d->m_paSecurity = new KAction( i18n( "SSL" ), this ); 00294 actionCollection()->addAction( "security", d->m_paSecurity ); 00295 connect( d->m_paSecurity, SIGNAL( triggered( bool ) ), this, SLOT( slotSecurity() ) ); 00296 00297 d->m_paDebugRenderTree = new KAction( i18n( "Print Rendering Tree to STDOUT" ), this ); 00298 actionCollection()->addAction( "debugRenderTree", d->m_paDebugRenderTree ); 00299 connect( d->m_paDebugRenderTree, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugRenderTree() ) ); 00300 00301 d->m_paDebugDOMTree = new KAction( i18n( "Print DOM Tree to STDOUT" ), this ); 00302 actionCollection()->addAction( "debugDOMTree", d->m_paDebugDOMTree ); 00303 connect( d->m_paDebugDOMTree, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugDOMTree() ) ); 00304 00305 KAction* paDebugFrameTree = new KAction( i18n( "Print frame tree to STDOUT" ), this ); 00306 actionCollection()->addAction( "debugFrameTree", paDebugFrameTree ); 00307 connect( paDebugFrameTree, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugFrameTree() ) ); 00308 00309 d->m_paStopAnimations = new KAction( i18n( "Stop Animated Images" ), this ); 00310 actionCollection()->addAction( "stopAnimations", d->m_paStopAnimations ); 00311 connect( d->m_paStopAnimations, SIGNAL( triggered( bool ) ), this, SLOT( slotStopAnimations() ) ); 00312 00313 d->m_paSetEncoding = new KCodecAction( KIcon("character-set"), i18n( "Set &Encoding" ), this, true ); 00314 actionCollection()->addAction( "setEncoding", d->m_paSetEncoding ); 00315 // d->m_paSetEncoding->setDelayed( false ); 00316 00317 connect( d->m_paSetEncoding, SIGNAL(triggered(const QString&)), this, SLOT( slotSetEncoding(const QString &))); 00318 connect( d->m_paSetEncoding, SIGNAL(triggered(KEncodingDetector::AutoDetectScript)), this, SLOT( slotAutomaticDetectionLanguage(KEncodingDetector::AutoDetectScript))); 00319 00320 if ( KGlobal::config()->hasGroup( "HTML Settings" ) ) { 00321 KConfigGroup config( KGlobal::config(), "HTML Settings" ); 00322 00323 d->m_autoDetectLanguage = static_cast<KEncodingDetector::AutoDetectScript>(config.readEntry( "AutomaticDetectionLanguage", /*static_cast<int>(language) */0)); 00324 if (d->m_autoDetectLanguage==KEncodingDetector::None) { 00325 const QByteArray name = KGlobal::locale()->encoding().toLower(); 00326 // kWarning() << "00000000 "; 00327 if (name.endsWith("1251")||name.startsWith("koi")||name=="iso-8859-5") 00328 d->m_autoDetectLanguage=KEncodingDetector::Cyrillic; 00329 else if (name.endsWith("1256")||name=="iso-8859-6") 00330 d->m_autoDetectLanguage=KEncodingDetector::Arabic; 00331 else if (name.endsWith("1257")||name=="iso-8859-13"||name=="iso-8859-4") 00332 d->m_autoDetectLanguage=KEncodingDetector::Baltic; 00333 else if (name.endsWith("1250")|| name=="ibm852" || name=="iso-8859-2" || name=="iso-8859-3" ) 00334 d->m_autoDetectLanguage=KEncodingDetector::CentralEuropean; 00335 else if (name.endsWith("1253")|| name=="iso-8859-7" ) 00336 d->m_autoDetectLanguage=KEncodingDetector::Greek; 00337 else if (name.endsWith("1255")|| name=="iso-8859-8" || name=="iso-8859-8-i" ) 00338 d->m_autoDetectLanguage=KEncodingDetector::Hebrew; 00339 else if (name=="jis7" || name=="eucjp" || name=="sjis" ) 00340 d->m_autoDetectLanguage=KEncodingDetector::Japanese; 00341 else if (name.endsWith("1254")|| name=="iso-8859-9" ) 00342 d->m_autoDetectLanguage=KEncodingDetector::Turkish; 00343 else if (name.endsWith("1252")|| name=="iso-8859-1" || name=="iso-8859-15" ) 00344 d->m_autoDetectLanguage=KEncodingDetector::WesternEuropean; 00345 else 00346 d->m_autoDetectLanguage=KEncodingDetector::SemiautomaticDetection; 00347 // kWarning() << "0000000end " << d->m_autoDetectLanguage << " " << KGlobal::locale()->encodingMib(); 00348 } 00349 d->m_paSetEncoding->setCurrentAutoDetectScript(d->m_autoDetectLanguage); 00350 } 00351 00352 d->m_paUseStylesheet = new KSelectAction( i18n( "Use S&tylesheet"), this ); 00353 actionCollection()->addAction( "useStylesheet", d->m_paUseStylesheet ); 00354 connect( d->m_paUseStylesheet, SIGNAL( triggered( int ) ), this, SLOT( slotUseStylesheet() ) ); 00355 00356 if ( prof == BrowserViewGUI ) { 00357 d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, "format-font-size-more", i18n( "Enlarge Font" ), this ); 00358 actionCollection()->addAction( "incFontSizes", d->m_paIncZoomFactor ); 00359 connect(d->m_paIncZoomFactor, SIGNAL(triggered(bool)), SLOT( slotIncFontSizeFast() )); 00360 d->m_paIncZoomFactor->setWhatsThis( i18n( "<qt>Enlarge Font<br /><br />" 00361 "Make the font in this window bigger. " 00362 "Click and hold down the mouse button for a menu with all available font sizes.</qt>" ) ); 00363 00364 d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, "format-font-size-less", i18n( "Shrink Font" ), this ); 00365 actionCollection()->addAction( "decFontSizes", d->m_paDecZoomFactor ); 00366 connect(d->m_paDecZoomFactor, SIGNAL(triggered(bool)), SLOT( slotDecFontSizeFast() )); 00367 d->m_paDecZoomFactor->setWhatsThis( i18n( "<qt>Shrink Font<br /><br />" 00368 "Make the font in this window smaller. " 00369 "Click and hold down the mouse button for a menu with all available font sizes.</qt>" ) ); 00370 if (!parentPart()) { 00371 // For framesets, this action also affects frames, so only 00372 // the frameset needs to define a shortcut for the action. 00373 00374 // TODO: Why also CTRL+=? Because of http://trolltech.com/developer/knowledgebase/524/? 00375 // Nobody else does it... 00376 d->m_paIncZoomFactor->setShortcut( KShortcut("CTRL++; CTRL+=") ); 00377 d->m_paDecZoomFactor->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_Minus) ); 00378 } 00379 } 00380 00381 d->m_paFind = actionCollection()->addAction( KStandardAction::Find, "find", this, SLOT( slotFind() ) ); 00382 d->m_paFind->setWhatsThis( i18n( "<qt>Find text<br /><br />" 00383 "Shows a dialog that allows you to find text on the displayed page.</qt>" ) ); 00384 00385 d->m_paFindNext = actionCollection()->addAction( KStandardAction::FindNext, "findNext", this, SLOT( slotFindNext() ) ); 00386 d->m_paFindNext->setWhatsThis( i18n( "<qt>Find next<br /><br />" 00387 "Find the next occurrence of the text that you " 00388 "have found using the <b>Find Text</b> function.</qt>" ) ); 00389 00390 d->m_paFindPrev = actionCollection()->addAction( KStandardAction::FindPrev, "findPrevious", 00391 this, SLOT( slotFindPrev() ) ); 00392 d->m_paFindPrev->setWhatsThis( i18n( "<qt>Find previous<br /><br />" 00393 "Find the previous occurrence of the text that you " 00394 "have found using the <b>Find Text</b> function.</qt>" ) ); 00395 00396 // These two actions aren't visible in the menus, but exist for the (configurable) shortcut 00397 d->m_paFindAheadText = new KAction( i18n("Find Text as You Type"), this ); 00398 actionCollection()->addAction( "findAheadText", d->m_paFindAheadText ); 00399 d->m_paFindAheadText->setShortcuts( KShortcut( '/' ) ); 00400 d->m_paFindAheadText->setHelpText(i18n("This shortcut shows the find bar, for finding text in the displayed page. It cancels the effect of \"Find Links as You Type\", which sets the \"Find links only\" option.")); 00401 connect( d->m_paFindAheadText, SIGNAL( triggered( bool ) ), this, SLOT( slotFindAheadText()) ); 00402 00403 d->m_paFindAheadLinks = new KAction( i18n("Find Links as You Type"), this ); 00404 actionCollection()->addAction( "findAheadLink", d->m_paFindAheadLinks ); 00405 // The issue is that it sets the (sticky) option FindLinksOnly, so 00406 // if you trigger this shortcut once by mistake, Esc and Ctrl+F will still have the option set. 00407 // Better let advanced users configure a shortcut for this advanced option 00408 //d->m_paFindAheadLinks->setShortcuts( KShortcut( '\'' ) ); 00409 d->m_paFindAheadLinks->setHelpText(i18n("This shortcut shows the find bar, and sets the option \"Find links only\".")); 00410 connect( d->m_paFindAheadLinks, SIGNAL( triggered( bool ) ), this, SLOT( slotFindAheadLink() ) ); 00411 00412 if ( parentPart() ) 00413 { 00414 d->m_paFind->setShortcuts( KShortcut() ); // avoid clashes 00415 d->m_paFindNext->setShortcuts( KShortcut() ); // avoid clashes 00416 d->m_paFindPrev->setShortcuts( KShortcut() ); // avoid clashes 00417 d->m_paFindAheadText->setShortcuts( KShortcut()); 00418 d->m_paFindAheadLinks->setShortcuts( KShortcut()); 00419 } 00420 00421 d->m_paPrintFrame = new KAction( i18n( "Print Frame..." ), this ); 00422 actionCollection()->addAction( "printFrame", d->m_paPrintFrame ); 00423 d->m_paPrintFrame->setIcon( KIcon( "document-print-frame" ) ); 00424 connect( d->m_paPrintFrame, SIGNAL( triggered( bool ) ), this, SLOT( slotPrintFrame() ) ); 00425 d->m_paPrintFrame->setWhatsThis( i18n( "<qt>Print Frame<br /><br />" 00426 "Some pages have several frames. To print only a single frame, click " 00427 "on it and then use this function.</qt>" ) ); 00428 00429 // Warning: The name selectAll is used hardcoded by some 3rd parties to remove the 00430 // shortcut for selectAll so they do not get ambigous shortcuts. Renaming it 00431 // will either crash or render useless that workaround. It would be better 00432 // to use the name KStandardAction::name(KStandardAction::SelectAll) but we 00433 // can't for the same reason. 00434 d->m_paSelectAll = actionCollection()->addAction( KStandardAction::SelectAll, "selectAll", 00435 this, SLOT( slotSelectAll() ) ); 00436 if ( parentPart() ) // Only the frameset has the shortcut, but the slot uses the current frame. 00437 d->m_paSelectAll->setShortcuts( KShortcut() ); // avoid clashes 00438 00439 d->m_paToggleCaretMode = new KToggleAction(i18n("Toggle Caret Mode"), this ); 00440 actionCollection()->addAction( "caretMode", d->m_paToggleCaretMode ); 00441 d->m_paToggleCaretMode->setShortcut( QKeySequence(Qt::Key_F7) ); 00442 connect( d->m_paToggleCaretMode, SIGNAL( triggered( bool ) ), this, SLOT(slotToggleCaretMode()) ); 00443 d->m_paToggleCaretMode->setChecked(isCaretMode()); 00444 if (parentPart()) 00445 d->m_paToggleCaretMode->setShortcut(KShortcut()); // avoid clashes 00446 00447 // set the default java(script) flags according to the current host. 00448 d->m_bOpenMiddleClick = d->m_settings->isOpenMiddleClickEnabled(); 00449 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(); 00450 setDebugScript( d->m_settings->isJavaScriptDebugEnabled() ); 00451 d->m_bJavaEnabled = d->m_settings->isJavaEnabled(); 00452 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(); 00453 00454 // Set the meta-refresh flag... 00455 d->m_metaRefreshEnabled = d->m_settings->isAutoDelayedActionsEnabled (); 00456 00457 KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling(); 00458 if (ssm == KHTMLSettings::KSmoothScrollingDisabled) 00459 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled); 00460 else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient) 00461 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient); 00462 else 00463 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled); 00464 00465 if (d->m_bDNSPrefetchIsDefault && !onlyLocalReferences()) { 00466 KHTMLSettings::KDNSPrefetch dpm = d->m_settings->dnsPrefetch(); 00467 if (dpm == KHTMLSettings::KDNSPrefetchDisabled) 00468 d->m_bDNSPrefetch = DNSPrefetchDisabled; 00469 else if (dpm == KHTMLSettings::KDNSPrefetchOnlyWWWAndSLD) 00470 d->m_bDNSPrefetch = DNSPrefetchOnlyWWWAndSLD; 00471 else 00472 d->m_bDNSPrefetch = DNSPrefetchEnabled; 00473 } 00474 00475 if (!KHTMLPartPrivate::s_dnsInitialised && d->m_bDNSPrefetch != DNSPrefetchDisabled) { 00476 KIO::HostInfo::setCacheSize( sDNSCacheSize ); 00477 KIO::HostInfo::setTTL( sDNSTTLSeconds ); 00478 KHTMLPartPrivate::s_dnsInitialised = true; 00479 } 00480 00481 // all shortcuts should only be active, when this part has focus 00482 foreach ( QAction *action, actionCollection ()->actions () ) { 00483 action->setShortcutContext ( Qt::WidgetWithChildrenShortcut ); 00484 } 00485 actionCollection()->associateWidget(view); 00486 00487 connect( view, SIGNAL( zoomView( int ) ), SLOT( slotZoomView( int ) ) ); 00488 00489 connect( this, SIGNAL( completed() ), 00490 this, SLOT( updateActions() ) ); 00491 connect( this, SIGNAL( completed( bool ) ), 00492 this, SLOT( updateActions() ) ); 00493 connect( this, SIGNAL( started( KIO::Job * ) ), 00494 this, SLOT( updateActions() ) ); 00495 00496 // #### FIXME: the process wide loader is going to signal every part about every loaded object. 00497 // That's quite inefficient. Should be per-document-tree somehow. Even signaling to 00498 // child parts that a request from an ancestor has loaded is inefficent.. 00499 connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ), 00500 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) ); 00501 connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ), 00502 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) ); 00503 connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ), 00504 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) ); 00505 00506 connect ( &d->m_progressUpdateTimer, SIGNAL( timeout() ), this, SLOT( slotProgressUpdate() ) ); 00507 00508 findTextBegin(); //reset find variables 00509 00510 connect( &d->m_redirectionTimer, SIGNAL( timeout() ), 00511 this, SLOT( slotRedirect() ) ); 00512 00513 if (QDBusConnection::sessionBus().isConnected()) { 00514 new KHTMLPartIface(this); // our "adaptor" 00515 for (int i = 1; ; ++i) 00516 if (QDBusConnection::sessionBus().registerObject(QString("/KHTML/%1/widget").arg(i), this)) 00517 break; 00518 else if (i == 0xffff) 00519 kFatal() << "Something is very wrong in KHTMLPart!"; 00520 } 00521 00522 if (prof == BrowserViewGUI && !parentPart()) 00523 loadPlugins(); 00524 00525 // "khtml" catalog does not exist, our translations are in kdelibs. 00526 // removing this catalog from KGlobal::locale() prevents problems 00527 // with changing the language in applications at runtime -Thomas Reitelbach 00528 // DF: a better fix would be to set the right catalog name in the KComponentData! 00529 KGlobal::locale()->removeCatalog("khtml"); 00530 } 00531 00532 KHTMLPart::~KHTMLPart() 00533 { 00534 kDebug(6050) << this; 00535 KConfigGroup config( KGlobal::config(), "HTML Settings" ); 00536 config.writeEntry( "AutomaticDetectionLanguage", int(d->m_autoDetectLanguage) ); 00537 00538 if (d->m_manager) { // the PartManager for this part's children 00539 d->m_manager->removePart(this); 00540 } 00541 00542 slotWalletClosed(); 00543 if (!parentPart()) { // only delete it if the top khtml_part closes 00544 removeJSErrorExtension(); 00545 } 00546 00547 stopAutoScroll(); 00548 d->m_redirectionTimer.stop(); 00549 00550 if (!d->m_bComplete) 00551 closeUrl(); 00552 00553 disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ), 00554 this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) ); 00555 disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ), 00556 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) ); 00557 disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ), 00558 this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) ); 00559 00560 clear(); 00561 hide(); 00562 00563 if ( d->m_view ) 00564 { 00565 d->m_view->m_part = 0; 00566 } 00567 00568 // Have to delete this here since we forward declare it in khtmlpart_p and 00569 // at least some compilers won't call the destructor in this case. 00570 delete d->m_jsedlg; 00571 d->m_jsedlg = 0; 00572 00573 if (!parentPart()) // only delete d->m_frame if the top khtml_part closes 00574 delete d->m_frame; 00575 else if (d->m_frame && d->m_frame->m_run) // for kids, they may get detached while 00576 d->m_frame->m_run.data()->abort(); // resolving mimetype; cancel that if needed 00577 delete d; d = 0; 00578 KHTMLGlobal::deregisterPart( this ); 00579 } 00580 00581 bool KHTMLPart::restoreURL( const KUrl &url ) 00582 { 00583 kDebug( 6050 ) << url; 00584 00585 d->m_redirectionTimer.stop(); 00586 00587 /* 00588 * That's not a good idea as it will call closeUrl() on all 00589 * child frames, preventing them from further loading. This 00590 * method gets called from restoreState() in case of a full frameset 00591 * restoral, and restoreState() calls closeUrl() before restoring 00592 * anyway. 00593 kDebug( 6050 ) << "closing old URL"; 00594 closeUrl(); 00595 */ 00596 00597 d->m_bComplete = false; 00598 d->m_bLoadEventEmitted = false; 00599 d->m_workingURL = url; 00600 00601 // set the java(script) flags according to the current host. 00602 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host()); 00603 setDebugScript( KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled() ); 00604 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host()); 00605 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host()); 00606 00607 setUrl(url); 00608 00609 d->m_restoreScrollPosition = true; 00610 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 00611 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 00612 00613 KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(const QByteArray &))); 00614 00615 emit started( 0L ); 00616 00617 return true; 00618 } 00619 00620 bool KHTMLPartPrivate::isLocalAnchorJump( const KUrl& url ) 00621 { 00622 // kio_help actually uses fragments to identify different pages, so 00623 // always reload with it. 00624 if (url.protocol() == QLatin1String("help")) 00625 return false; 00626 00627 return url.hasRef() && url.equals( q->url(), 00628 KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment | KUrl::AllowEmptyPath ); 00629 } 00630 00631 void KHTMLPartPrivate::executeAnchorJump( const KUrl& url, bool lockHistory ) 00632 { 00633 // Note: we want to emit openUrlNotify first thing, to make the history capture the old state. 00634 if (!lockHistory) 00635 emit m_extension->openUrlNotify(); 00636 00637 if ( !q->gotoAnchor( url.encodedHtmlRef()) ) 00638 q->gotoAnchor( url.htmlRef() ); 00639 00640 q->setUrl(url); 00641 emit m_extension->setLocationBarUrl( url.prettyUrl() ); 00642 } 00643 00644 bool KHTMLPart::openUrl( const KUrl &url ) 00645 { 00646 kDebug( 6050 ) << this << "opening" << url; 00647 00648 // Wallet forms are per page, so clear it when loading a different page if we 00649 // are not an iframe (because we store walletforms only on the topmost part). 00650 if(!parentPart()) 00651 d->m_walletForms.clear(); 00652 00653 d->m_redirectionTimer.stop(); 00654 00655 // check to see if this is an "error://" URL. This is caused when an error 00656 // occurs before this part was loaded (e.g. KonqRun), and is passed to 00657 // khtmlpart so that it can display the error. 00658 if ( url.protocol() == "error" ) { 00659 closeUrl(); 00660 00661 if( d->m_bJScriptEnabled ) { 00662 d->m_statusBarText[BarOverrideText].clear(); 00663 d->m_statusBarText[BarDefaultText].clear(); 00664 } 00665 00671 KUrl::List urls = KUrl::split( url ); 00672 //kDebug(6050) << "Handling error URL. URL count:" << urls.count(); 00673 00674 if ( !urls.isEmpty() ) { 00675 const KUrl mainURL = urls.first(); 00676 int error = mainURL.queryItem( "error" ).toInt(); 00677 // error=0 isn't a valid error code, so 0 means it's missing from the URL 00678 if ( error == 0 ) error = KIO::ERR_UNKNOWN; 00679 const QString errorText = mainURL.queryItem( "errText" ); 00680 urls.pop_front(); 00681 d->m_workingURL = KUrl::join( urls ); 00682 //kDebug(6050) << "Emitting fixed URL " << d->m_workingURL.prettyUrl(); 00683 emit d->m_extension->setLocationBarUrl( d->m_workingURL.prettyUrl() ); 00684 htmlError( error, errorText, d->m_workingURL ); 00685 return true; 00686 } 00687 } 00688 00689 if (!parentPart()) { // only do it for toplevel part 00690 QString host = url.isLocalFile() ? "localhost" : url.host(); 00691 QString userAgent = KProtocolManager::userAgentForHost(host); 00692 if (userAgent != KProtocolManager::userAgentForHost(QString())) { 00693 if (!d->m_statusBarUALabel) { 00694 d->m_statusBarUALabel = new KUrlLabel(d->m_statusBarExtension->statusBar()); 00695 d->m_statusBarUALabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); 00696 d->m_statusBarUALabel->setUseCursor(false); 00697 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarUALabel, 0, false); 00698 d->m_statusBarUALabel->setPixmap(SmallIcon("preferences-web-browser-identification")); 00699 } 00700 d->m_statusBarUALabel->setToolTip(i18n("The fake user-agent '%1' is in use.", userAgent)); 00701 } else if (d->m_statusBarUALabel) { 00702 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarUALabel); 00703 delete d->m_statusBarUALabel; 00704 d->m_statusBarUALabel = 0L; 00705 } 00706 } 00707 00708 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() ); 00709 KParts::OpenUrlArguments args( arguments() ); 00710 00711 // in case 00712 // a) we have no frameset (don't test m_frames.count(), iframes get in there) 00713 // b) the url is identical with the currently displayed one (except for the htmlref!) 00714 // c) the url request is not a POST operation and 00715 // d) the caller did not request to reload the page 00716 // e) there was no HTTP redirection meanwhile (testcase: webmin's software/tree.cgi) 00717 // => we don't reload the whole document and 00718 // we just jump to the requested html anchor 00719 bool isFrameSet = false; 00720 if ( d->m_doc && d->m_doc->isHTMLDocument() ) { 00721 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc); 00722 isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET); 00723 } 00724 00725 if (isFrameSet && d->isLocalAnchorJump(url) && browserArgs.softReload) 00726 { 00727 QList<khtml::ChildFrame*>::Iterator it = d->m_frames.begin(); 00728 const QList<khtml::ChildFrame*>::Iterator end = d->m_frames.end(); 00729 for (; it != end; ++it) { 00730 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part.data() ); 00731 if (part) 00732 { 00733 // We are reloading frames to make them jump into offsets. 00734 KParts::OpenUrlArguments partargs( part->arguments() ); 00735 partargs.setReload( true ); 00736 part->setArguments( partargs ); 00737 00738 part->openUrl( part->url() ); 00739 } 00740 }/*next it*/ 00741 return true; 00742 } 00743 00744 if ( url.hasRef() && !isFrameSet ) 00745 { 00746 bool noReloadForced = !args.reload() && !browserArgs.redirectedRequest() && !browserArgs.doPost(); 00747 if ( noReloadForced && d->isLocalAnchorJump(url) ) 00748 { 00749 kDebug( 6050 ) << "jumping to anchor. m_url = " << url; 00750 setUrl(url); 00751 emit started( 0 ); 00752 00753 if ( !gotoAnchor( url.encodedHtmlRef()) ) 00754 gotoAnchor( url.htmlRef() ); 00755 00756 d->m_bComplete = true; 00757 if (d->m_doc) 00758 d->m_doc->setParsing(false); 00759 00760 kDebug( 6050 ) << "completed..."; 00761 emit completed(); 00762 return true; 00763 } 00764 } 00765 00766 // Save offset of viewport when page is reloaded to be compliant 00767 // to every other capable browser out there. 00768 if (args.reload()) { 00769 args.setXOffset( d->m_view->contentsX() ); 00770 args.setYOffset( d->m_view->contentsY() ); 00771 setArguments(args); 00772 } 00773 00774 if (!d->m_restored) 00775 closeUrl(); 00776 00777 d->m_restoreScrollPosition = d->m_restored; 00778 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 00779 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 00780 00781 // Classify the mimetype. Some, like images and plugins are handled 00782 // by wrapping things up in tags, so we want to plain output the HTML, 00783 // and not start the job and all that (since we would want the 00784 // KPart or whatever to load it). 00785 // This is also the only place we need to do this, as it's for 00786 // internal iframe use, not any other clients. 00787 MimeType type = d->classifyMimeType(args.mimeType()); 00788 00789 if (type == MimeImage || type == MimeOther) { 00790 begin(url, args.xOffset(), args.yOffset()); 00791 write(QString::fromLatin1("<html><head></head><body>")); 00792 if (type == MimeImage) 00793 write(QString::fromLatin1("<img ")); 00794 else 00795 write(QString::fromLatin1("<embed ")); 00796 write(QString::fromLatin1("src=\"")); 00797 00798 assert(url.url().indexOf('"') == -1); 00799 write(url.url()); 00800 00801 write(QString::fromLatin1("\">")); 00802 end(); 00803 return true; 00804 } 00805 00806 00807 // 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 00808 // data arrives) (Simon) 00809 d->m_workingURL = url; 00810 if(url.protocol().startsWith( "http" ) && !url.host().isEmpty() && 00811 url.path().isEmpty()) { 00812 d->m_workingURL.setPath("/"); 00813 emit d->m_extension->setLocationBarUrl( d->m_workingURL.prettyUrl() ); 00814 } 00815 setUrl(d->m_workingURL); 00816 00817 QMap<QString,QString>& metaData = args.metaData(); 00818 metaData.insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" ); 00819 metaData.insert("ssl_parent_ip", d->m_ssl_parent_ip); 00820 metaData.insert("ssl_parent_cert", d->m_ssl_parent_cert); 00821 metaData.insert("PropagateHttpHeader", "true"); 00822 metaData.insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" ); 00823 metaData.insert("ssl_activate_warnings", "TRUE" ); 00824 metaData.insert("cross-domain", toplevelURL().url()); 00825 00826 if (d->m_restored) 00827 { 00828 metaData.insert("referrer", d->m_pageReferrer); 00829 d->m_cachePolicy = KIO::CC_Cache; 00830 } 00831 else if (args.reload() && !browserArgs.softReload) 00832 d->m_cachePolicy = KIO::CC_Reload; 00833 else 00834 d->m_cachePolicy = KProtocolManager::cacheControl(); 00835 00836 if ( browserArgs.doPost() && (url.protocol().startsWith("http")) ) 00837 { 00838 d->m_job = KIO::http_post( url, browserArgs.postData, KIO::HideProgressInfo ); 00839 d->m_job->addMetaData("content-type", browserArgs.contentType() ); 00840 } 00841 else 00842 { 00843 d->m_job = KIO::get( url, KIO::NoReload, KIO::HideProgressInfo ); 00844 d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy)); 00845 } 00846 00847 if (widget()) 00848 d->m_job->ui()->setWindow(widget()->topLevelWidget()); 00849 d->m_job->addMetaData(metaData); 00850 00851 connect( d->m_job, SIGNAL( result( KJob* ) ), 00852 SLOT( slotFinished( KJob* ) ) ); 00853 connect( d->m_job, SIGNAL( data( KIO::Job*, const QByteArray& ) ), 00854 SLOT( slotData( KIO::Job*, const QByteArray& ) ) ); 00855 connect ( d->m_job, SIGNAL( infoMessage( KJob*, const QString&, const QString& ) ), 00856 SLOT( slotInfoMessage(KJob*, const QString& ) ) ); 00857 connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KUrl& ) ), 00858 SLOT( slotRedirection(KIO::Job*, const KUrl&) ) ); 00859 00860 d->m_bComplete = false; 00861 d->m_bLoadEventEmitted = false; 00862 00863 // delete old status bar msg's from kjs (if it _was_ activated on last URL) 00864 if( d->m_bJScriptEnabled ) { 00865 d->m_statusBarText[BarOverrideText].clear(); 00866 d->m_statusBarText[BarDefaultText].clear(); 00867 } 00868 00869 // set the javascript flags according to the current url 00870 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host()); 00871 setDebugScript( KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled() ); 00872 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host()); 00873 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host()); 00874 00875 00876 connect( d->m_job, SIGNAL( speed( KJob*, unsigned long ) ), 00877 this, SLOT( slotJobSpeed( KJob*, unsigned long ) ) ); 00878 00879 connect( d->m_job, SIGNAL( percent( KJob*, unsigned long ) ), 00880 this, SLOT( slotJobPercent( KJob*, unsigned long ) ) ); 00881 00882 connect( d->m_job, SIGNAL( result( KJob* ) ), 00883 this, SLOT( slotJobDone( KJob* ) ) ); 00884 00885 d->m_jobspeed = 0; 00886 00887 // If this was an explicit reload and the user style sheet should be used, 00888 // do a stat to see whether the stylesheet was changed in the meanwhile. 00889 if ( args.reload() && !settings()->userStyleSheet().isEmpty() ) { 00890 KUrl url( settings()->userStyleSheet() ); 00891 KIO::StatJob *job = KIO::stat( url, KIO::HideProgressInfo ); 00892 connect( job, SIGNAL( result( KJob * ) ), 00893 this, SLOT( slotUserSheetStatDone( KJob * ) ) ); 00894 } 00895 startingJob( d->m_job ); 00896 emit started( 0L ); 00897 00898 return true; 00899 } 00900 00901 bool KHTMLPart::closeUrl() 00902 { 00903 if ( d->m_job ) 00904 { 00905 KHTMLPageCache::self()->cancelEntry(d->m_cacheId); 00906 d->m_job->kill(); 00907 d->m_job = 0; 00908 } 00909 00910 if ( d->m_doc && d->m_doc->isHTMLDocument() ) { 00911 HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc ); 00912 00913 if ( hdoc->body() && d->m_bLoadEventEmitted ) { 00914 hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false ); 00915 if ( d->m_doc ) 00916 d->m_doc->updateRendering(); 00917 d->m_bLoadEventEmitted = false; 00918 } 00919 } 00920 00921 d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David) 00922 d->m_bLoadEventEmitted = true; // don't want that one either 00923 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy 00924 00925 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 00926 00927 KHTMLPageCache::self()->cancelFetch(this); 00928 if ( d->m_doc && d->m_doc->parsing() ) 00929 { 00930 kDebug( 6050 ) << " was still parsing... calling end "; 00931 slotFinishedParsing(); 00932 d->m_doc->setParsing(false); 00933 } 00934 00935 if ( !d->m_workingURL.isEmpty() ) 00936 { 00937 // Aborted before starting to render 00938 kDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << url().prettyUrl(); 00939 emit d->m_extension->setLocationBarUrl( url().prettyUrl() ); 00940 } 00941 00942 d->m_workingURL = KUrl(); 00943 00944 if ( d->m_doc && d->m_doc->docLoader() ) 00945 khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() ); 00946 00947 // tell all subframes to stop as well 00948 { 00949 ConstFrameIt it = d->m_frames.constBegin(); 00950 const ConstFrameIt end = d->m_frames.constEnd(); 00951 for (; it != end; ++it ) 00952 { 00953 if ( (*it)->m_run ) 00954 (*it)->m_run.data()->abort(); 00955 if ( !( *it )->m_part.isNull() ) 00956 ( *it )->m_part.data()->closeUrl(); 00957 } 00958 } 00959 // tell all objects to stop as well 00960 { 00961 ConstFrameIt it = d->m_objects.constBegin(); 00962 const ConstFrameIt end = d->m_objects.constEnd(); 00963 for (; it != end; ++it) 00964 { 00965 if ( !( *it )->m_part.isNull() ) 00966 ( *it )->m_part.data()->closeUrl(); 00967 } 00968 } 00969 // Stop any started redirections as well!! (DA) 00970 if ( d && d->m_redirectionTimer.isActive() ) 00971 d->m_redirectionTimer.stop(); 00972 00973 // null node activated. 00974 emit nodeActivated(Node()); 00975 00976 // make sure before clear() runs, we pop out of a dialog's message loop 00977 if ( d->m_view ) 00978 d->m_view->closeChildDialogs(); 00979 00980 return true; 00981 } 00982 00983 DOM::HTMLDocument KHTMLPart::htmlDocument() const 00984 { 00985 if (d->m_doc && d->m_doc->isHTMLDocument()) 00986 return static_cast<HTMLDocumentImpl*>(d->m_doc); 00987 else 00988 return static_cast<HTMLDocumentImpl*>(0); 00989 } 00990 00991 DOM::Document KHTMLPart::document() const 00992 { 00993 return d->m_doc; 00994 } 00995 00996 QString KHTMLPart::documentSource() const 00997 { 00998 QString sourceStr; 00999 if ( !( url().isLocalFile() ) && KHTMLPageCache::self()->isComplete( d->m_cacheId ) ) 01000 { 01001 QByteArray sourceArray; 01002 QDataStream dataStream( &sourceArray, QIODevice::WriteOnly ); 01003 KHTMLPageCache::self()->saveData( d->m_cacheId, &dataStream ); 01004 QTextStream stream( sourceArray, QIODevice::ReadOnly ); 01005 stream.setCodec( QTextCodec::codecForName( encoding().toLatin1().constData() ) ); 01006 sourceStr = stream.readAll(); 01007 } else 01008 { 01009 QString tmpFile; 01010 if( KIO::NetAccess::download( url(), tmpFile, NULL ) ) 01011 { 01012 QFile f( tmpFile ); 01013 if ( f.open( QIODevice::ReadOnly ) ) 01014 { 01015 QTextStream stream( &f ); 01016 stream.setCodec( QTextCodec::codecForName( encoding().toLatin1().constData() ) ); 01017 sourceStr = stream.readAll(); 01018 f.close(); 01019 } 01020 KIO::NetAccess::removeTempFile( tmpFile ); 01021 } 01022 } 01023 01024 return sourceStr; 01025 } 01026 01027 01028 KParts::BrowserExtension *KHTMLPart::browserExtension() const 01029 { 01030 return d->m_extension; 01031 } 01032 01033 KParts::BrowserHostExtension *KHTMLPart::browserHostExtension() const 01034 { 01035 return d->m_hostExtension; 01036 } 01037 01038 KHTMLView *KHTMLPart::view() const 01039 { 01040 return d->m_view; 01041 } 01042 01043 KHTMLViewBar *KHTMLPart::pTopViewBar() const 01044 { 01045 if (const_cast<KHTMLPart*>(this)->parentPart()) 01046 return const_cast<KHTMLPart*>(this)->parentPart()->pTopViewBar(); 01047 return d->m_topViewBar; 01048 } 01049 01050 KHTMLViewBar *KHTMLPart::pBottomViewBar() const 01051 { 01052 if (const_cast<KHTMLPart*>(this)->parentPart()) 01053 return const_cast<KHTMLPart*>(this)->parentPart()->pBottomViewBar(); 01054 return d->m_bottomViewBar; 01055 } 01056 01057 void KHTMLPart::setStatusMessagesEnabled( bool enable ) 01058 { 01059 d->m_statusMessagesEnabled = enable; 01060 } 01061 01062 KJS::Interpreter *KHTMLPart::jScriptInterpreter() 01063 { 01064 KJSProxy *proxy = jScript(); 01065 if (!proxy || proxy->paused()) 01066 return 0; 01067 01068 return proxy->interpreter(); 01069 } 01070 01071 bool KHTMLPart::statusMessagesEnabled() const 01072 { 01073 return d->m_statusMessagesEnabled; 01074 } 01075 01076 void KHTMLPart::setJScriptEnabled( bool enable ) 01077 { 01078 if ( !enable && jScriptEnabled() && d->m_frame && d->m_frame->m_jscript ) { 01079 d->m_frame->m_jscript->clear(); 01080 } 01081 d->m_bJScriptForce = enable; 01082 d->m_bJScriptOverride = true; 01083 } 01084 01085 bool KHTMLPart::jScriptEnabled() const 01086 { 01087 if(onlyLocalReferences()) return false; 01088 01089 if ( d->m_bJScriptOverride ) 01090 return d->m_bJScriptForce; 01091 return d->m_bJScriptEnabled; 01092 } 01093 01094 void KHTMLPart::setDNSPrefetch( DNSPrefetch pmode ) 01095 { 01096 d->m_bDNSPrefetch = pmode; 01097 d->m_bDNSPrefetchIsDefault = false; 01098 } 01099 01100 KHTMLPart::DNSPrefetch KHTMLPart::dnsPrefetch() const 01101 { 01102 if (onlyLocalReferences()) 01103 return DNSPrefetchDisabled; 01104 return d->m_bDNSPrefetch; 01105 } 01106 01107 void KHTMLPart::setMetaRefreshEnabled( bool enable ) 01108 { 01109 d->m_metaRefreshEnabled = enable; 01110 } 01111 01112 bool KHTMLPart::metaRefreshEnabled() const 01113 { 01114 return d->m_metaRefreshEnabled; 01115 } 01116 01117 KJSProxy *KHTMLPart::jScript() 01118 { 01119 if (!jScriptEnabled()) return 0; 01120 01121 if ( !d->m_frame ) { 01122 KHTMLPart * p = parentPart(); 01123 if (!p) { 01124 d->m_frame = new khtml::ChildFrame; 01125 d->m_frame->m_part = this; 01126 } else { 01127 ConstFrameIt it = p->d->m_frames.constBegin(); 01128 const ConstFrameIt end = p->d->m_frames.constEnd(); 01129 for (; it != end; ++it) 01130 if ((*it)->m_part.data() == this) { 01131 d->m_frame = *it; 01132 break; 01133 } 01134 } 01135 if ( !d->m_frame ) 01136 return 0; 01137 } 01138 if ( !d->m_frame->m_jscript ) 01139 d->m_frame->m_jscript = new KJSProxy(d->m_frame); 01140 d->m_frame->m_jscript->setDebugEnabled(d->m_bJScriptDebugEnabled); 01141 01142 return d->m_frame->m_jscript; 01143 } 01144 01145 QVariant KHTMLPart::crossFrameExecuteScript(const QString& target, const QString& script) 01146 { 01147 KHTMLPart* destpart = this; 01148 01149 QString trg = target.toLower(); 01150 01151 if (target == "_top") { 01152 while (destpart->parentPart()) 01153 destpart = destpart->parentPart(); 01154 } 01155 else if (target == "_parent") { 01156 if (parentPart()) 01157 destpart = parentPart(); 01158 } 01159 else if (target == "_self" || target == "_blank") { 01160 // we always allow these 01161 } 01162 else { 01163 destpart = findFrame(target); 01164 if (!destpart) 01165 destpart = this; 01166 } 01167 01168 // easy way out? 01169 if (destpart == this) 01170 return executeScript(DOM::Node(), script); 01171 01172 // now compare the domains 01173 if (destpart->checkFrameAccess(this)) 01174 return destpart->executeScript(DOM::Node(), script); 01175 01176 // eww, something went wrong. better execute it in our frame 01177 return executeScript(DOM::Node(), script); 01178 } 01179 01180 //Enable this to see all JS scripts being executed 01181 //#define KJS_VERBOSE 01182 01183 KJSErrorDlg *KHTMLPart::jsErrorExtension() { 01184 if (!d->m_settings->jsErrorsEnabled()) { 01185 return 0L; 01186 } 01187 01188 if (parentPart()) { 01189 return parentPart()->jsErrorExtension(); 01190 } 01191 01192 if (!d->m_statusBarJSErrorLabel) { 01193 d->m_statusBarJSErrorLabel = new KUrlLabel(d->m_statusBarExtension->statusBar()); 01194 d->m_statusBarJSErrorLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); 01195 d->m_statusBarJSErrorLabel->setUseCursor(false); 01196 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarJSErrorLabel, 0, false); 01197 d->m_statusBarJSErrorLabel->setToolTip(i18n("This web page contains coding errors.")); 01198 d->m_statusBarJSErrorLabel->setPixmap(SmallIcon("script-error")); 01199 connect(d->m_statusBarJSErrorLabel, SIGNAL(leftClickedUrl()), SLOT(launchJSErrorDialog())); 01200 connect(d->m_statusBarJSErrorLabel, SIGNAL(rightClickedUrl()), SLOT(jsErrorDialogContextMenu())); 01201 } 01202 if (!d->m_jsedlg) { 01203 d->m_jsedlg = new KJSErrorDlg; 01204 d->m_jsedlg->setURL(url().prettyUrl()); 01205 if (KGlobalSettings::showIconsOnPushButtons()) { 01206 d->m_jsedlg->_clear->setIcon(KIcon("edit-clear-locationbar-ltr")); 01207 d->m_jsedlg->_close->setIcon(KIcon("window-close")); 01208 } 01209 } 01210 return d->m_jsedlg; 01211 } 01212 01213 void KHTMLPart::removeJSErrorExtension() { 01214 if (parentPart()) { 01215 parentPart()->removeJSErrorExtension(); 01216 return; 01217 } 01218 if (d->m_statusBarJSErrorLabel != 0) { 01219 d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarJSErrorLabel ); 01220 delete d->m_statusBarJSErrorLabel; 01221 d->m_statusBarJSErrorLabel = 0; 01222 } 01223 delete d->m_jsedlg; 01224 d->m_jsedlg = 0; 01225 } 01226 01227 void KHTMLPart::disableJSErrorExtension() { 01228 removeJSErrorExtension(); 01229 // These two lines are really kind of hacky, and it sucks to do this inside 01230 // KHTML but I don't know of anything that's reasonably easy as an alternative 01231 // right now. It makes me wonder if there should be a more clean way to 01232 // contact all running "KHTML" instance as opposed to Konqueror instances too. 01233 d->m_settings->setJSErrorsEnabled(false); 01234 emit configurationChanged(); 01235 } 01236 01237 void KHTMLPart::jsErrorDialogContextMenu() { 01238 KMenu *m = new KMenu(0L); 01239 m->addAction(i18n("&Hide Errors"), this, SLOT(removeJSErrorExtension())); 01240 m->addAction(i18n("&Disable Error Reporting"), this, SLOT(disableJSErrorExtension())); 01241 m->popup(QCursor::pos()); 01242 } 01243 01244 void KHTMLPart::launchJSErrorDialog() { 01245 KJSErrorDlg *dlg = jsErrorExtension(); 01246 if (dlg) { 01247 dlg->show(); 01248 dlg->raise(); 01249 } 01250 } 01251 01252 void KHTMLPart::launchJSConfigDialog() { 01253 QStringList args; 01254 args << "khtml_java_js"; 01255 KToolInvocation::kdeinitExec( "kcmshell4", args ); 01256 } 01257 01258 QVariant KHTMLPart::executeScript(const QString& filename, int baseLine, const DOM::Node& n, const QString& script) 01259 { 01260 #ifdef KJS_VERBOSE 01261 // The script is now printed by KJS's Parser::parse 01262 kDebug(6070) << "executeScript: caller='" << objectName() << "' filename=" << filename << " baseLine=" << baseLine /*<< " script=" << script*/; 01263 #endif 01264 KJSProxy *proxy = jScript(); 01265 01266 if (!proxy || proxy->paused()) 01267 return QVariant(); 01268 01269 //Make sure to initialize the interpreter before creating Completion 01270 (void)proxy->interpreter(); 01271 01272 KJS::Completion comp; 01273 01274 QVariant ret = proxy->evaluate(filename, baseLine, script, n, &comp); 01275 01276 /* 01277 * Error handling 01278 */ 01279 if (comp.complType() == KJS::Throw && comp.value()) { 01280 KJSErrorDlg *dlg = jsErrorExtension(); 01281 if (dlg) { 01282 QString msg = KJSDebugger::DebugWindow::exceptionToString( 01283 proxy->interpreter()->globalExec(), comp.value()); 01284 dlg->addError(i18n("<qt><b>Error</b>: %1: %2</qt>", 01285 Qt::escape(filename), Qt::escape(msg))); 01286 } 01287 } 01288 01289 // Handle immediate redirects now (e.g. location='foo') 01290 if ( !d->m_redirectURL.isEmpty() && d->m_delayRedirect == -1 ) 01291 { 01292 kDebug(6070) << "executeScript done, handling immediate redirection NOW"; 01293 // Must abort tokenizer, no further script must execute. 01294 khtml::Tokenizer* t = d->m_doc->tokenizer(); 01295 if(t) 01296 t->abort(); 01297 d->m_redirectionTimer.setSingleShot( true ); 01298 d->m_redirectionTimer.start( 0 ); 01299 } 01300 01301 return ret; 01302 } 01303 01304 QVariant KHTMLPart::executeScript( const QString &script ) 01305 { 01306 return executeScript( DOM::Node(), script ); 01307 } 01308 01309 QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script ) 01310 { 01311 #ifdef KJS_VERBOSE 01312 kDebug(6070) << "caller=" << objectName() << "node=" << n.nodeName().string().toLatin1().constData() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " /* << script */; 01313 #endif 01314 KJSProxy *proxy = jScript(); 01315 01316 if (!proxy || proxy->paused()) 01317 return QVariant(); 01318 (void)proxy->interpreter();//Make sure stuff is initialized 01319 01320 ++(d->m_runningScripts); 01321 KJS::Completion comp; 01322 const QVariant ret = proxy->evaluate( QString(), 1, script, n, &comp ); 01323 --(d->m_runningScripts); 01324 01325 /* 01326 * Error handling 01327 */ 01328 if (comp.complType() == KJS::Throw && comp.value()) { 01329 KJSErrorDlg *dlg = jsErrorExtension(); 01330 if (dlg) { 01331 QString msg = KJSDebugger::DebugWindow::exceptionToString( 01332 proxy->interpreter()->globalExec(), comp.value()); 01333 dlg->addError(i18n("<qt><b>Error</b>: node %1: %2</qt>", 01334 n.nodeName().string(), Qt::escape(msg))); 01335 } 01336 } 01337 01338 if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm ) 01339 submitFormAgain(); 01340 01341 #ifdef KJS_VERBOSE 01342 kDebug(6070) << "done"; 01343 #endif 01344 return ret; 01345 } 01346 01347 void KHTMLPart::setJavaEnabled( bool enable ) 01348 { 01349 d->m_bJavaForce = enable; 01350 d->m_bJavaOverride = true; 01351 } 01352 01353 bool KHTMLPart::javaEnabled() const 01354 { 01355 if (onlyLocalReferences()) return false; 01356 01357 #ifndef Q_WS_QWS 01358 if( d->m_bJavaOverride ) 01359 return d->m_bJavaForce; 01360 return d->m_bJavaEnabled; 01361 #else 01362 return false; 01363 #endif 01364 } 01365 01366 void KHTMLPart::setPluginsEnabled( bool enable ) 01367 { 01368 d->m_bPluginsForce = enable; 01369 d->m_bPluginsOverride = true; 01370 } 01371 01372 bool KHTMLPart::pluginsEnabled() const 01373 { 01374 if (onlyLocalReferences()) return false; 01375 01376 if ( d->m_bPluginsOverride ) 01377 return d->m_bPluginsForce; 01378 return d->m_bPluginsEnabled; 01379 } 01380 01381 static int s_DOMTreeIndentLevel = 0; 01382 01383 void KHTMLPart::slotDebugDOMTree() 01384 { 01385 if ( d->m_doc ) 01386 qDebug("%s", d->m_doc->toString().string().toLatin1().constData()); 01387 01388 // Now print the contents of the frames that contain HTML 01389 01390 const int indentLevel = s_DOMTreeIndentLevel++; 01391 01392 ConstFrameIt it = d->m_frames.constBegin(); 01393 const ConstFrameIt end = d->m_frames.constEnd(); 01394 for (; it != end; ++it ) 01395 if ( !( *it )->m_part.isNull() && (*it)->m_part.data()->inherits( "KHTMLPart" ) ) { 01396 KParts::ReadOnlyPart* const p = ( *it )->m_part.data(); 01397 kDebug(6050) << QString().leftJustified(s_DOMTreeIndentLevel*4,' ') << "FRAME " << p->objectName() << " "; 01398 static_cast<KHTMLPart*>( p )->slotDebugDOMTree(); 01399 } 01400 s_DOMTreeIndentLevel = indentLevel; 01401 } 01402 01403 void KHTMLPart::slotDebugScript() 01404 { 01405 if (jScript()) 01406 jScript()->showDebugWindow(); 01407 } 01408 01409 void KHTMLPart::slotDebugRenderTree() 01410 { 01411 #ifndef NDEBUG 01412 if ( d->m_doc ) { 01413 d->m_doc->renderer()->printTree(); 01414 // dump out the contents of the rendering & DOM trees 01415 // QString dumps; 01416 // QTextStream outputStream(&dumps,QIODevice::WriteOnly); 01417 // d->m_doc->renderer()->layer()->dump( outputStream ); 01418 // kDebug() << "dump output:" << "\n" + dumps; 01419 // d->m_doc->renderer()->printLineBoxTree(); 01420 } 01421 #endif 01422 } 01423 01424 void KHTMLPart::slotDebugFrameTree() 01425 { 01426 khtml::ChildFrame::dumpFrameTree(this); 01427 } 01428 01429 void KHTMLPart::slotStopAnimations() 01430 { 01431 stopAnimations(); 01432 } 01433 01434 void KHTMLPart::setAutoloadImages( bool enable ) 01435 { 01436 if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable ) 01437 return; 01438 01439 if ( d->m_doc ) 01440 d->m_doc->docLoader()->setAutoloadImages( enable ); 01441 01442 unplugActionList( "loadImages" ); 01443 01444 if ( enable ) { 01445 delete d->m_paLoadImages; 01446 d->m_paLoadImages = 0; 01447 } 01448 else if ( !d->m_paLoadImages ) { 01449 d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), this ); 01450 actionCollection()->addAction( "loadImages", d->m_paLoadImages ); 01451 d->m_paLoadImages->setIcon( KIcon( "image-loading" ) ); 01452 connect( d->m_paLoadImages, SIGNAL( triggered( bool ) ), this, SLOT( slotLoadImages() ) ); 01453 } 01454 01455 if ( d->m_paLoadImages ) { 01456 QList<QAction*> lst; 01457 lst.append( d->m_paLoadImages ); 01458 plugActionList( "loadImages", lst ); 01459 } 01460 } 01461 01462 bool KHTMLPart::autoloadImages() const 01463 { 01464 if ( d->m_doc ) 01465 return d->m_doc->docLoader()->autoloadImages(); 01466 01467 return true; 01468 } 01469 01470 void KHTMLPart::clear() 01471 { 01472 if ( d->m_bCleared ) 01473 return; 01474 01475 d->m_bCleared = true; 01476 01477 d->m_bClearing = true; 01478 01479 { 01480 ConstFrameIt it = d->m_frames.constBegin(); 01481 const ConstFrameIt end = d->m_frames.constEnd(); 01482 for(; it != end; ++it ) 01483 { 01484 // Stop HTMLRun jobs for frames 01485 if ( (*it)->m_run ) 01486 (*it)->m_run.data()->abort(); 01487 } 01488 } 01489 01490 { 01491 ConstFrameIt it = d->m_objects.constBegin(); 01492 const ConstFrameIt end = d->m_objects.constEnd(); 01493 for(; it != end; ++it ) 01494 { 01495 // Stop HTMLRun jobs for objects 01496 if ( (*it)->m_run ) 01497 (*it)->m_run.data()->abort(); 01498 } 01499 } 01500 01501 01502 findTextBegin(); // resets d->m_findNode and d->m_findPos 01503 d->m_mousePressNode = DOM::Node(); 01504 01505 01506 if ( d->m_doc ) 01507 { 01508 if (d->m_doc->attached()) //the view may have detached it already 01509 d->m_doc->detach(); 01510 } 01511 01512 // Moving past doc so that onUnload works. 01513 if ( d->m_frame && d->m_frame->m_jscript ) 01514 d->m_frame->m_jscript->clear(); 01515 01516 // stopping marquees 01517 if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->layer()) 01518 d->m_doc->renderer()->layer()->suspendMarquees(); 01519 01520 if ( d->m_view ) 01521 d->m_view->clear(); 01522 01523 // do not dereference the document before the jscript and view are cleared, as some destructors 01524 // might still try to access the document. 01525 if ( d->m_doc ) { 01526 d->m_doc->deref(); 01527 } 01528 d->m_doc = 0; 01529 01530 delete d->m_decoder; 01531 d->m_decoder = 0; 01532 01533 // We don't want to change between parts if we are going to delete all of them anyway 01534 disconnect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ), 01535 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) ); 01536 01537 if (d->m_frames.count()) 01538 { 01539 const KHTMLFrameList frames = d->m_frames; 01540 d->m_frames.clear(); 01541 ConstFrameIt it = frames.begin(); 01542 const ConstFrameIt end = frames.end(); 01543 for(; it != end; ++it ) 01544 { 01545 if ( (*it)->m_part ) 01546 { 01547 partManager()->removePart( (*it)->m_part.data() ); 01548 delete (*it)->m_part.data(); 01549 } 01550 delete *it; 01551 } 01552 } 01553 d->m_suppressedPopupOriginParts.clear(); 01554 01555 if (d->m_objects.count()) 01556 { 01557 KHTMLFrameList objects = d->m_objects; 01558 d->m_objects.clear(); 01559 ConstFrameIt oi = objects.constBegin(); 01560 const ConstFrameIt oiEnd = objects.constEnd(); 01561 01562 for (; oi != oiEnd; ++oi ) 01563 { 01564 delete (*oi)->m_part.data(); 01565 delete *oi; 01566 } 01567 } 01568 01569 // Listen to part changes again 01570 connect( partManager(), SIGNAL( activePartChanged( KParts::Part * ) ), 01571 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) ); 01572 01573 d->clearRedirection(); 01574 d->m_redirectLockHistory = true; 01575 d->m_bClearing = false; 01576 d->m_frameNameId = 1; 01577 d->m_bFirstData = true; 01578 01579 d->m_bMousePressed = false; 01580 01581 if (d->editor_context.m_caretBlinkTimer >= 0) 01582 killTimer(d->editor_context.m_caretBlinkTimer); 01583 d->editor_context.reset(); 01584 #ifndef QT_NO_CLIPBOARD 01585 connect( qApp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection())); 01586 #endif 01587 01588 d->m_jobPercent = 0; 01589 01590 if ( !d->m_haveEncoding ) 01591 d->m_encoding.clear(); 01592 01593 d->m_DNSPrefetchQueue.clear(); 01594 if (d->m_DNSPrefetchTimer > 0) 01595 killTimer(d->m_DNSPrefetchTimer); 01596 d->m_DNSPrefetchTimer = -1; 01597 d->m_lookedupHosts.clear(); 01598 if (d->m_DNSTTLTimer > 0) 01599 killTimer(d->m_DNSTTLTimer); 01600 d->m_DNSTTLTimer = -1; 01601 d->m_numDNSPrefetchedNames = 0; 01602 01603 #ifdef SPEED_DEBUG 01604 d->m_parsetime.restart(); 01605 #endif 01606 } 01607 01608 bool KHTMLPart::openFile() 01609 { 01610 return true; 01611 } 01612 01613 DOM::HTMLDocumentImpl *KHTMLPart::docImpl() const 01614 { 01615 if ( d && d->m_doc && d->m_doc->isHTMLDocument() ) 01616 return static_cast<HTMLDocumentImpl*>(d->m_doc); 01617 return 0; 01618 } 01619 01620 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const 01621 { 01622 if ( d ) 01623 return d->m_doc; 01624 return 0; 01625 } 01626 01627 void KHTMLPart::slotInfoMessage(KJob* kio_job, const QString& msg) 01628 { 01629 assert(d->m_job == kio_job); 01630 Q_ASSERT(kio_job); 01631 Q_UNUSED(kio_job); 01632 01633 if (!parentPart()) 01634 setStatusBarText(msg, BarDefaultText); 01635 } 01636 01637 void KHTMLPart::setPageSecurity( PageSecurity sec ) 01638 { 01639 emit d->m_extension->setPageSecurity( sec ); 01640 } 01641 01642 void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data ) 01643 { 01644 assert ( d->m_job == kio_job ); 01645 Q_ASSERT(kio_job); 01646 Q_UNUSED(kio_job); 01647 01648 //kDebug( 6050 ) << "slotData: " << data.size(); 01649 // The first data ? 01650 if ( !d->m_workingURL.isEmpty() ) 01651 { 01652 //kDebug( 6050 ) << "begin!"; 01653 01654 // We must suspend KIO while we're inside begin() because it can cause 01655 // crashes if a window (such as kjsdebugger) goes back into the event loop, 01656 // more data arrives, and begin() gets called again (re-entered). 01657 d->m_job->suspend(); 01658 begin( d->m_workingURL, arguments().xOffset(), arguments().yOffset() ); 01659 d->m_job->resume(); 01660 01661 // CC_Refresh means : always send the server an If-Modified-Since conditional request. 01662 // This is the default cache setting and correspond to the KCM's "Keep cache in sync". 01663 // CC_Verify means : only send a conditional request if the cache expiry date is passed. 01664 // It doesn't have a KCM setter. 01665 // We override the first to the second, except when doing a soft-reload. 01666 if (d->m_cachePolicy == KIO::CC_Refresh && !d->m_extension->browserArguments().softReload) 01667 d->m_doc->docLoader()->setCachePolicy(KIO::CC_Verify); 01668 else 01669 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy); 01670 01671 d->m_workingURL = KUrl(); 01672 01673 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry(); 01674 01675 // When the first data arrives, the metadata has just been made available 01676 d->m_httpHeaders = d->m_job->queryMetaData("HTTP-Headers"); 01677 time_t cacheCreationDate = d->m_job->queryMetaData("cache-creation-date").toLong(); 01678 d->m_doc->docLoader()->setCacheCreationDate(cacheCreationDate); 01679 01680 d->m_pageServices = d->m_job->queryMetaData("PageServices"); 01681 d->m_pageReferrer = d->m_job->queryMetaData("referrer"); 01682 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE"); 01683 01684 { 01685 KHTMLPart *p = parentPart(); 01686 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) { 01687 while (p->parentPart()) p = p->parentPart(); 01688 01689 p->setPageSecurity( NotCrypted ); 01690 } 01691 } 01692 01693 setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted ); 01694 01695 // Shouldn't all of this be done only if ssl_in_use == true ? (DF) 01696 d->m_ssl_parent_ip = d->m_job->queryMetaData("ssl_parent_ip"); 01697 d->m_ssl_parent_cert = d->m_job->queryMetaData("ssl_parent_cert"); 01698 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain"); 01699 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip"); 01700 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher"); 01701 d->m_ssl_protocol_version = d->m_job->queryMetaData("ssl_protocol_version"); 01702 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits"); 01703 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits"); 01704 d->m_ssl_cert_errors = d->m_job->queryMetaData("ssl_cert_errors"); 01705 01706 // Check for charset meta-data 01707 QString qData = d->m_job->queryMetaData("charset"); 01708 if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings 01709 d->m_encoding = qData; 01710 01711 01712 // Support for http-refresh 01713 qData = d->m_job->queryMetaData("http-refresh"); 01714 if( !qData.isEmpty()) 01715 d->m_doc->processHttpEquiv("refresh", qData); 01716 01717 // DISABLED: Support Content-Location per section 14.14 of RFC 2616. 01718 // See BR# 51185,BR# 82747 01719 /* 01720 QString baseURL = d->m_job->queryMetaData ("content-location"); 01721 if (!baseURL.isEmpty()) 01722 d->m_doc->setBaseURL(KUrl( d->m_doc->completeURL(baseURL) )); 01723 */ 01724 01725 // Support for Content-Language 01726 QString language = d->m_job->queryMetaData("content-language"); 01727 if (!language.isEmpty()) 01728 d->m_doc->setContentLanguage(language); 01729 01730 if ( !url().isLocalFile() ) 01731 { 01732 // Support for http last-modified 01733 d->m_lastModified = d->m_job->queryMetaData("modified"); 01734 } 01735 else 01736 d->m_lastModified.clear(); // done on-demand by lastModified() 01737 } 01738 01739 KHTMLPageCache::self()->addData(d->m_cacheId, data); 01740 write( data.data(), data.size() ); 01741 } 01742 01743 void KHTMLPart::slotRestoreData(const QByteArray &data ) 01744 { 01745 // The first data ? 01746 if ( !d->m_workingURL.isEmpty() ) 01747 { 01748 long saveCacheId = d->m_cacheId; 01749 QString savePageReferrer = d->m_pageReferrer; 01750 QString saveEncoding = d->m_encoding; 01751 begin( d->m_workingURL, arguments().xOffset(), arguments().yOffset() ); 01752 d->m_encoding = saveEncoding; 01753 d->m_pageReferrer = savePageReferrer; 01754 d->m_cacheId = saveCacheId; 01755 d->m_workingURL = KUrl(); 01756 } 01757 01758 //kDebug( 6050 ) << data.size(); 01759 write( data.data(), data.size() ); 01760 01761 if (data.size() == 0) 01762 { 01763 //kDebug( 6050 ) << "<<end of data>>"; 01764 // End of data. 01765 if (d->m_doc && d->m_doc->parsing()) 01766 end(); //will emit completed() 01767 } 01768 } 01769 01770 void KHTMLPart::showError( KJob* job ) 01771 { 01772 kDebug(6050) << "d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete 01773 << " d->m_bCleared=" << d->m_bCleared; 01774 01775 if (job->error() == KIO::ERR_NO_CONTENT) 01776 return; 01777 01778 if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already 01779 job->uiDelegate()->showErrorMessage(); 01780 else 01781 { 01782 htmlError( job->error(), job->errorText(), d->m_workingURL ); 01783 } 01784 } 01785 01786 // This is a protected method, placed here because of it's relevance to showError 01787 void KHTMLPart::htmlError( int errorCode, const QString& text, const KUrl& reqUrl ) 01788 { 01789 kDebug(6050) << "errorCode" << errorCode << "text" << text; 01790 // make sure we're not executing any embedded JS 01791 bool bJSFO = d->m_bJScriptForce; 01792 bool bJSOO = d->m_bJScriptOverride; 01793 d->m_bJScriptForce = false; 01794 d->m_bJScriptOverride = true; 01795 begin(); 01796 01797 QString errorName, techName, description; 01798 QStringList causes, solutions; 01799 01800 QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl ); 01801 QDataStream stream(raw); 01802 01803 stream >> errorName >> techName >> description >> causes >> solutions; 01804 01805 QString url, protocol, datetime; 01806 01807 // This is somewhat confusing, but we have to escape the externally- 01808 // controlled URL twice: once for i18n, and once for HTML. 01809 url = Qt::escape( Qt::escape( reqUrl.prettyUrl() ) ); 01810 protocol = reqUrl.protocol(); 01811 datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(), 01812 KLocale::LongDate ); 01813 01814 QString filename( KStandardDirs::locate( "data", "khtml/error.html" ) ); 01815 QFile file( filename ); 01816 bool isOpened = file.open( QIODevice::ReadOnly ); 01817 if ( !isOpened ) 01818 kWarning(6050) << "Could not open error html template:" << filename; 01819 01820 QString html = QString( QLatin1String( file.readAll() ) ); 01821 01822 html.replace( QLatin1String( "TITLE" ), i18n( "Error: %1 - %2", errorName, url ) ); 01823 html.replace( QLatin1String( "DIRECTION" ), QApplication::isRightToLeft() ? "rtl" : "ltr" ); 01824 html.replace( QLatin1String( "ICON_PATH" ), KIconLoader::global()->iconPath( "dialog-warning", -KIconLoader::SizeHuge ) ); 01825 01826 QString doc = QLatin1String( "<h1>" ); 01827 doc += i18n( "The requested operation could not be completed" ); 01828 doc += QLatin1String( "</h1><h2>" ); 01829 doc += errorName; 01830 doc += QLatin1String( "</h2>" ); 01831 if ( !techName.isNull() ) { 01832 doc += QLatin1String( "<h2>" ); 01833 doc += i18n( "Technical Reason: " ); 01834 doc += techName; 01835 doc += QLatin1String( "</h2>" ); 01836 } 01837 doc += QLatin1String( "<br clear=\"all\">" ); 01838 doc += QLatin1String( "<h3>" ); 01839 doc += i18n( "Details of the Request:" ); 01840 doc += QLatin1String( "</h3><ul><li>" ); 01841 doc += i18n( "URL: %1" , url ); 01842 doc += QLatin1String( "</li><li>" ); 01843 if ( !protocol.isNull() ) { 01844 doc += i18n( "Protocol: %1", protocol ); 01845 doc += QLatin1String( "</li><li>" ); 01846 } 01847 doc += i18n( "Date and Time: %1" , datetime ); 01848 doc += QLatin1String( "</li><li>" ); 01849 doc += i18n( "Additional Information: %1" , text ); 01850 doc += QLatin1String( "</li></ul><h3>" ); 01851 doc += i18n( "Description:" ); 01852 doc += QLatin1String( "</h3><p>" ); 01853 doc += description; 01854 doc += QLatin1String( "</p>" ); 01855 if ( causes.count() ) { 01856 doc += QLatin1String( "<h3>" ); 01857 doc += i18n( "Possible Causes:" ); 01858 doc += QLatin1String( "</h3><ul><li>" ); 01859 doc += causes.join( "</li><li>" ); 01860 doc += QLatin1String( "</li></ul>" ); 01861 } 01862 if ( solutions.count() ) { 01863 doc += QLatin1String( "<h3>" ); 01864 doc += i18n( "Possible Solutions:" ); 01865 doc += QLatin1String( "</h3><ul><li>" ); 01866 doc += solutions.join( "</li><li>" ); 01867 doc += QLatin1String( "</li></ul>" ); 01868 } 01869 01870 html.replace( QLatin1String("TEXT"), doc ); 01871 01872 write( html ); 01873 end(); 01874 01875 d->m_bJScriptForce = bJSFO; 01876 d->m_bJScriptOverride = bJSOO; 01877 01878 // make the working url the current url, so that reload works and 01879 // emit the progress signals to advance one step in the history 01880 // (so that 'back' works) 01881 setUrl(reqUrl); // same as d->m_workingURL 01882 d->m_workingURL = KUrl(); 01883 emit started( 0 ); 01884 emit completed(); 01885 } 01886 01887 void KHTMLPart::slotFinished( KJob * job ) 01888 { 01889 d->m_job = 0L; 01890 d->m_jobspeed = 0L; 01891 01892 if (job->error()) 01893 { 01894 KHTMLPageCache::self()->cancelEntry(d->m_cacheId); 01895 01896 // The following catches errors that occur as a result of HTTP 01897 // to FTP redirections where the FTP URL is a directory. Since 01898 // KIO cannot change a redirection request from GET to LISTDIR, 01899 // we have to take care of it here once we know for sure it is 01900 // a directory... 01901 if (job->error() == KIO::ERR_IS_DIRECTORY) 01902 { 01903 emit canceled( job->errorString() ); 01904 emit d->m_extension->openUrlRequest( d->m_workingURL ); 01905 } 01906 else 01907 { 01908 emit canceled( job->errorString() ); 01909 // TODO: what else ? 01910 checkCompleted(); 01911 showError( job ); 01912 } 01913 01914 return; 01915 } 01916 KIO::TransferJob *tjob = ::qobject_cast<KIO::TransferJob*>(job); 01917 if (tjob && tjob->isErrorPage()) { 01918 HTMLPartContainerElementImpl *elt = d->m_frame ? 01919 d->m_frame->m_partContainerElement.data() : 0; 01920 01921 if (!elt) 01922 return; 01923 01924 elt->partLoadingErrorNotify(); 01925 checkCompleted(); 01926 if (d->m_bComplete) return; 01927 } 01928 01929 //kDebug( 6050 ) << "slotFinished"; 01930 01931 KHTMLPageCache::self()->endData(d->m_cacheId); 01932 01933 if ( d->m_doc && d->m_doc->docLoader()->expireDate() && url().protocol().toLower().startsWith("http")) 01934 KIO::http_update_cache(url(), false, d->m_doc->docLoader()->expireDate()); 01935 01936 d->m_workingURL = KUrl(); 01937 01938 if ( d->m_doc && d->m_doc->parsing()) 01939 end(); //will emit completed() 01940 } 01941 01942 MimeType KHTMLPartPrivate::classifyMimeType(const QString& mimeStr) 01943 { 01944 // See HTML5's "5.5.1 Navigating across documents" section. 01945 if (mimeStr == "application/xhtml+xml") 01946 return MimeXHTML; 01947 if (mimeStr == "image/svg+xml") 01948 return MimeSVG; 01949 if (mimeStr == "text/html" || mimeStr.isEmpty()) 01950 return MimeHTML; 01951 01952 KMimeType::Ptr mime = KMimeType::mimeType(mimeStr, KMimeType::ResolveAliases); 01953 if ((mime && mime->is("text/xml")) || mimeStr.endsWith("+xml")) 01954 return MimeXML; 01955 01956 if (mime && mime->is("text/plain")) 01957 return MimeText; 01958 01959 if (khtmlImLoad::ImageManager::loaderDatabase()->supportedMimeTypes().contains(mimeStr)) 01960 return MimeImage; 01961 01962 // Sometimes our subclasses like to handle custom mimetypes. In that case, 01963 // we want to handle them as HTML. We do that in the following cases: 01964 // 1) We're at top-level, so we were forced to open something 01965 // 2) We're an object --- this again means we were forced to open something, 01966 // as an iframe-generating-an-embed case would have us as an iframe 01967 if (!q->parentPart() || (m_frame && m_frame->m_type == khtml::ChildFrame::Object)) 01968 return MimeHTML; 01969 01970 return MimeOther; 01971 } 01972 01973 void KHTMLPart::begin( const KUrl &url, int xOffset, int yOffset ) 01974 { 01975 if ( d->m_view->underMouse() ) 01976 QToolTip::hideText(); // in case a previous tooltip is still shown 01977 01978 // No need to show this for a new page until an error is triggered 01979 if (!parentPart()) { 01980 removeJSErrorExtension(); 01981 setSuppressedPopupIndicator( false ); 01982 d->m_openableSuppressedPopups = 0; 01983 foreach ( KHTMLPart* part, d->m_suppressedPopupOriginParts ) { 01984 if (part) { 01985 KJS::Window *w = KJS::Window::retrieveWindow( part ); 01986 if (w) 01987 w->forgetSuppressedWindows(); 01988 } 01989 } 01990 } 01991 01992 d->m_bCleared = false; 01993 d->m_cacheId = 0; 01994 d->m_bComplete = false; 01995 d->m_bLoadEventEmitted = false; 01996 clear(); 01997 d->m_bCleared = false; 01998 01999 if(url.isValid()) { 02000 QString urlString = url.url(); 02001 KHTMLGlobal::vLinks()->insert( urlString ); 02002 QString urlString2 = url.prettyUrl(); 02003 if ( urlString != urlString2 ) { 02004 KHTMLGlobal::vLinks()->insert( urlString2 ); 02005 } 02006 } 02007 02008 // ### 02009 //stopParser(); 02010 02011 KParts::OpenUrlArguments args = arguments(); 02012 args.setXOffset(xOffset); 02013 args.setYOffset(yOffset); 02014 setArguments(args); 02015 02016 d->m_pageReferrer.clear(); 02017 02018 KUrl ref(url); 02019 d->m_referrer = ref.protocol().startsWith("http") ? ref.url() : ""; 02020 02021 setUrl(url); 02022 02023 // Note: by now, any special mimetype besides plaintext would have been 02024 // handled specially inside openURL, so we handle their cases the same 02025 // as HTML. 02026 MimeType type = d->classifyMimeType(args.mimeType()); 02027 switch (type) { 02028 case MimeSVG: 02029 d->m_doc = DOMImplementationImpl::createSVGDocument( d->m_view ); 02030 break; 02031 case MimeXML: // any XML derivative, except XHTML or SVG 02032 // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl 02033 d->m_doc = DOMImplementationImpl::createXMLDocument( d->m_view ); 02034 break; 02035 case MimeText: 02036 d->m_doc = new HTMLTextDocumentImpl( d->m_view ); 02037 break; 02038 case MimeXHTML: 02039 case MimeHTML: 02040 default: 02041 d->m_doc = DOMImplementationImpl::createHTMLDocument( d->m_view ); 02042 // HTML or XHTML? (#86446) 02043 static_cast<HTMLDocumentImpl *>(d->m_doc)->setHTMLRequested( type != MimeXHTML ); 02044 } 02045 02046 d->m_doc->ref(); 02047 d->m_doc->setURL( url.url() ); 02048 d->m_doc->open( ); 02049 if (!d->m_doc->attached()) 02050 d->m_doc->attach( ); 02051 d->m_doc->setBaseURL( KUrl() ); 02052 d->m_doc->docLoader()->setShowAnimations( KHTMLGlobal::defaultHTMLSettings()->showAnimations() ); 02053 emit docCreated(); 02054 02055 d->m_paUseStylesheet->setItems(QStringList()); 02056 d->m_paUseStylesheet->setEnabled( false ); 02057 02058 setAutoloadImages( KHTMLGlobal::defaultHTMLSettings()->autoLoadImages() ); 02059 QString userStyleSheet = KHTMLGlobal::defaultHTMLSettings()->userStyleSheet(); 02060 if ( !userStyleSheet.isEmpty() ) 02061 setUserStyleSheet( KUrl( userStyleSheet ) ); 02062 02063 d->m_doc->setRestoreState(d->m_extension->browserArguments().docState); 02064 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing())); 02065 02066 emit d->m_extension->enableAction( "print", true ); 02067 02068 d->m_doc->setParsing(true); 02069 } 02070 02071 void KHTMLPart::write( const char *data, int len ) 02072 { 02073 if ( !d->m_decoder ) 02074 d->m_decoder = createDecoder(); 02075 02076 if ( len == -1 ) 02077 len = strlen( data ); 02078 02079 if ( len == 0 ) 02080 return; 02081 02082 QString decoded=d->m_decoder->decodeWithBuffering(data,len); 02083 02084 if(decoded.isEmpty()) 02085 return; 02086 02087 if(d->m_bFirstData) 02088 onFirstData(); 02089 02090 khtml::Tokenizer* t = d->m_doc->tokenizer(); 02091 if(t) 02092 t->write( decoded, true ); 02093 } 02094 02095 // ### KDE5: remove 02096 void KHTMLPart::setAlwaysHonourDoctype( bool b ) 02097 { 02098 d->m_bStrictModeQuirk = !b; 02099 } 02100 02101 void KHTMLPart::write( const QString &str ) 02102 { 02103 if ( str.isNull() ) 02104 return; 02105 02106 if(d->m_bFirstData) { 02107 // determine the parse mode 02108 if (d->m_bStrictModeQuirk) { 02109 d->m_doc->setParseMode( DocumentImpl::Strict ); 02110 d->m_bFirstData = false; 02111 } else { 02112 onFirstData(); 02113 } 02114 } 02115 khtml::Tokenizer* t = d->m_doc->tokenizer(); 02116 if(t) 02117 t->write( str, true ); 02118 } 02119 02120 void KHTMLPart::end() 02121 { 02122 if (d->m_doc) { 02123 if (d->m_decoder) 02124 { 02125 QString decoded=d->m_decoder->flush(); 02126 if (d->m_bFirstData) 02127 onFirstData(); 02128 if (!decoded.isEmpty()) 02129 write(decoded); 02130 } 02131 d->m_doc->finishParsing(); 02132 } 02133 } 02134 02135 void KHTMLPart::onFirstData() 02136 { 02137 assert( d->m_bFirstData ); 02138 02139 // determine the parse mode 02140 d->m_doc->determineParseMode(); 02141 d->m_bFirstData = false; 02142 02143 // ### this is still quite hacky, but should work a lot better than the old solution 02144 // Note: decoder may be null if only write(QString) is used. 02145 if (d->m_decoder && d->m_decoder->visuallyOrdered()) 02146 d->m_doc->setVisuallyOrdered(); 02147 // ensure part and view shares zoom-level before styling 02148 updateZoomFactor(); 02149 d->m_doc->recalcStyle( NodeImpl::Force ); 02150 } 02151 02152 bool KHTMLPart::doOpenStream( const QString& mimeType ) 02153 { 02154 KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases); 02155 if ( mime && ( mime->is( "text/html" ) || mime->is( "text/xml" ) ) ) 02156 { 02157 begin( url() ); 02158 return true; 02159 } 02160 return false; 02161 } 02162 02163 bool KHTMLPart::doWriteStream( const QByteArray& data ) 02164 { 02165 write( data.data(), data.size() ); 02166 return true; 02167 } 02168 02169 bool KHTMLPart::doCloseStream() 02170 { 02171 end(); 02172 return true; 02173 } 02174 02175 02176 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more) 02177 { 02178 if (!d->m_view) return; 02179 d->m_view->paint(p, rc, yOff, more); 02180 } 02181 02182 void KHTMLPart::stopAnimations() 02183 { 02184 if ( d->m_doc ) 02185 d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled ); 02186 02187 ConstFrameIt it = d->m_frames.constBegin(); 02188 const ConstFrameIt end = d->m_frames.constEnd(); 02189 for (; it != end; ++it ) { 02190 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) ) 02191 p->stopAnimations(); 02192 } 02193 } 02194 02195 void KHTMLPart::resetFromScript() 02196 { 02197 closeUrl(); 02198 d->m_bComplete = false; 02199 d->m_bLoadEventEmitted = false; 02200 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing())); 02201 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing())); 02202 d->m_doc->setParsing(true); 02203 02204 emit started( 0L ); 02205 } 02206 02207 void KHTMLPart::slotFinishedParsing() 02208 { 02209 d->m_doc->setParsing(false); 02210 d->m_doc->dispatchHTMLEvent(EventImpl::KHTML_CONTENTLOADED_EVENT, true, false); 02211 checkEmitLoadEvent(); 02212 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing())); 02213 02214 if (!d->m_view) 02215 return; // We are probably being destructed. 02216 02217 checkCompleted(); 02218 } 02219 02220 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj ) 02221 { 02222 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) { 02223 KHTMLPart* p = this; 02224 while ( p ) { 02225 KHTMLPart* const op = p; 02226 ++(p->d->m_totalObjectCount); 02227 p = p->parentPart(); 02228 if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount 02229 && !op->d->m_progressUpdateTimer.isActive()) { 02230 op->d->m_progressUpdateTimer.setSingleShot( true ); 02231 op->d->m_progressUpdateTimer.start( 200 ); 02232 } 02233 } 02234 } 02235 } 02236 02237 static bool isAncestorOrSamePart(KHTMLPart* p1, KHTMLPart* p2) 02238 { 02239 KHTMLPart* p = p2; 02240 do { 02241 if (p == p1) 02242 return true; 02243 } while ((p = p->parentPart())); 02244 return false; 02245 } 02246 02247 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj ) 02248 { 02249 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) { 02250 KHTMLPart* p = this; 02251 while ( p ) { 02252 KHTMLPart* const op = p; 02253 ++(p->d->m_loadedObjects); 02254 p = p->parentPart(); 02255 if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount && op->d->m_jobPercent <= 100 02256 && !op->d->m_progressUpdateTimer.isActive()) { 02257 op->d->m_progressUpdateTimer.setSingleShot( true ); 02258 op->d->m_progressUpdateTimer.start( 200 ); 02259 } 02260 } 02261 } 02263 // then our loading state can't possibly be affected : don't waste time checking for completion. 02264 if (!d->m_doc || !dl->doc()->part() || !isAncestorOrSamePart(this, dl->doc()->part())) 02265 return; 02266 checkCompleted(); 02267 } 02268 02269 void KHTMLPart::slotProgressUpdate() 02270 { 02271 int percent; 02272 if ( d->m_loadedObjects < d->m_totalObjectCount ) 02273 percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount ); 02274 else 02275 percent = d->m_jobPercent; 02276 02277 if( d->m_bComplete ) 02278 percent = 100; 02279 02280 if (d->m_statusMessagesEnabled) { 02281 if( d->m_bComplete ) 02282 emit d->m_extension->infoMessage( i18n( "Page loaded." )); 02283 else if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 ) 02284 emit d->m_extension->infoMessage( i18np( "%1 Image of %2 loaded.", "%1 Images of %2 loaded.", d->m_loadedObjects, d->m_totalObjectCount) ); 02285 } 02286 02287 emit d->m_extension->loadingProgress( percent ); 02288 } 02289 02290 void KHTMLPart::slotJobSpeed( KJob* /*job*/, unsigned long speed ) 02291 { 02292 d->m_jobspeed = speed; 02293 if (!parentPart()) 02294 setStatusBarText(jsStatusBarText(), BarOverrideText); 02295 } 02296 02297 void KHTMLPart::slotJobPercent( KJob* /*job*/, unsigned long percent ) 02298 { 02299 d->m_jobPercent = percent; 02300 02301 if ( !parentPart() ) { 02302 d->m_progressUpdateTimer.setSingleShot( true ); 02303 d->m_progressUpdateTimer.start( 0 ); 02304 } 02305 } 02306 02307 void KHTMLPart::slotJobDone( KJob* /*job*/ ) 02308 { 02309 d->m_jobPercent = 100; 02310 02311 if ( !parentPart() ) { 02312 d->m_progressUpdateTimer.setSingleShot( true ); 02313 d->m_progressUpdateTimer.start( 0 ); 02314 } 02315 } 02316 02317 void KHTMLPart::slotUserSheetStatDone( KJob *_job ) 02318 { 02319 using namespace KIO; 02320 02321 if ( _job->error() ) { 02322 showError( _job ); 02323 return; 02324 } 02325 02326 const UDSEntry entry = dynamic_cast<KIO::StatJob *>( _job )->statResult(); 02327 const time_t lastModified = entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, -1 ); 02328 02329 // If the filesystem supports modification times, only reload the 02330 // user-defined stylesheet if necessary - otherwise always reload. 02331 if ( lastModified != static_cast<time_t>(-1) ) { 02332 if ( d->m_userStyleSheetLastModified >= lastModified ) { 02333 return; 02334 } 02335 d->m_userStyleSheetLastModified = lastModified; 02336 } 02337 02338 setUserStyleSheet( KUrl( settings()->userStyleSheet() ) ); 02339 } 02340 02341 bool KHTMLPartPrivate::isFullyLoaded(bool* pendingRedirections) const 02342 { 02343 *pendingRedirections = false; 02344 02345 // Any frame that hasn't completed yet ? 02346 ConstFrameIt it = m_frames.constBegin(); 02347 const ConstFrameIt end = m_frames.constEnd(); 02348 for (; it != end; ++it ) { 02349 if ( !(*it)->m_bCompleted || (*it)->m_run ) 02350 { 02351 //kDebug( 6050 ) << this << " is waiting for " << (*it)->m_part; 02352 return false; 02353 } 02354 // Check for frames with pending redirections 02355 if ( (*it)->m_bPendingRedirection ) 02356 *pendingRedirections = true; 02357 } 02358 02359 // Any object that hasn't completed yet ? 02360 { 02361 ConstFrameIt oi = m_objects.constBegin(); 02362 const ConstFrameIt oiEnd = m_objects.constEnd(); 02363 02364 for (; oi != oiEnd; ++oi ) 02365 if ( !(*oi)->m_bCompleted ) 02366 return false; 02367 } 02368 02369 // Are we still parsing 02370 if ( m_doc && m_doc->parsing() ) 02371 return false; 02372 02373 // Still waiting for images/scripts from the loader ? 02374 int requests = 0; 02375 if ( m_doc && m_doc->docLoader() ) 02376 requests = khtml::Cache::loader()->numRequests( m_doc->docLoader() ); 02377 02378 if ( requests > 0 ) 02379 { 02380 //kDebug(6050) << "still waiting for images/scripts from the loader - requests:" << requests; 02381 return false; 02382 } 02383 02384 return true; 02385 } 02386 02387 void KHTMLPart::checkCompleted() 02388 { 02389 // kDebug( 6050 ) << this; 02390 // kDebug( 6050 ) << " parsing: " << (d->m_doc && d->m_doc->parsing()); 02391 // kDebug( 6050 ) << " complete: " << d->m_bComplete; 02392 02393 // restore the cursor position 02394 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored) 02395 { 02396 if (d->m_focusNodeNumber >= 0) 02397 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber)); 02398 02399 d->m_focusNodeRestored = true; 02400 } 02401 02402 bool fullyLoaded, pendingChildRedirections; 02403 fullyLoaded = d->isFullyLoaded(&pendingChildRedirections); 02404 02405 // Are we still loading, or already have done the relevant work? 02406 if (!fullyLoaded || d->m_bComplete) 02407 return; 02408 02409 // OK, completed. 02410 // Now do what should be done when we are really completed. 02411 d->m_bComplete = true; 02412 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy 02413 d->m_totalObjectCount = 0; 02414 d->m_loadedObjects = 0; 02415 02416 KHTMLPart* p = this; 02417 while ( p ) { 02418 KHTMLPart* op = p; 02419 p = p->parentPart(); 02420 if ( !p && !op->d->m_progressUpdateTimer.isActive()) { 02421 op->d->m_progressUpdateTimer.setSingleShot( true ); 02422 op->d->m_progressUpdateTimer.start( 0 ); 02423 } 02424 } 02425 02426 checkEmitLoadEvent(); // if we didn't do it before 02427 02428 bool pendingAction = false; 02429 02430 if ( !d->m_redirectURL.isEmpty() ) 02431 { 02432 // DA: Do not start redirection for frames here! That action is 02433 // deferred until the parent emits a completed signal. 02434 if ( parentPart() == 0 ) { 02435 //kDebug(6050) << this << " starting redirection timer"; 02436 d->m_redirectionTimer.setSingleShot( true ); 02437 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) ); 02438 } else { 02439 //kDebug(6050) << this << " not toplevel -> not starting redirection timer. Waiting for slotParentCompleted."; 02440 } 02441 02442 pendingAction = true; 02443 } 02444 else if ( pendingChildRedirections ) 02445 { 02446 pendingAction = true; 02447 } 02448 02449 // the view will emit completed on our behalf, 02450 // either now or at next repaint if one is pending 02451 02452 //kDebug(6050) << this << " asks the view to emit completed. pendingAction=" << pendingAction; 02453 d->m_view->complete( pendingAction ); 02454 02455 // find the alternate stylesheets 02456 QStringList sheets; 02457 if (d->m_doc) 02458 sheets = d->m_doc->availableStyleSheets(); 02459 sheets.prepend( i18n( "Automatic Detection" ) ); 02460 d->m_paUseStylesheet->setItems( sheets ); 02461 02462 d->m_paUseStylesheet->setEnabled( sheets.count() > 2); 02463 if (sheets.count() > 2) 02464 { 02465 d->m_paUseStylesheet->setCurrentItem(qMax(sheets.indexOf(d->m_sheetUsed), 0)); 02466 slotUseStylesheet(); 02467 } 02468 02469 setJSDefaultStatusBarText(QString()); 02470 02471 #ifdef SPEED_DEBUG 02472 if (!parentPart()) 02473 kDebug(6080) << "DONE:" <<d->m_parsetime.elapsed(); 02474 #endif 02475 } 02476 02477 void KHTMLPart::checkEmitLoadEvent() 02478 { 02479 bool fullyLoaded, pendingChildRedirections; 02480 fullyLoaded = d->isFullyLoaded(&pendingChildRedirections); 02481 02482 // ### might want to wait on pendingChildRedirections here, too 02483 if ( d->m_bLoadEventEmitted || !d->m_doc || !fullyLoaded ) return; 02484 02485 d->m_bLoadEventEmitted = true; 02486 if (d->m_doc) 02487 d->m_doc->close(); 02488 } 02489 02490 const KHTMLSettings *KHTMLPart::settings() const 02491 { 02492 return d->m_settings; 02493 } 02494 02495 #ifndef KDE_NO_COMPAT // KDE5: remove this ifndef, keep the method (renamed to baseUrl) 02496 KUrl KHTMLPart::baseURL() const 02497 { 02498 if ( !d->m_doc ) return KUrl(); 02499 02500 return d->m_doc->baseURL(); 02501 } 02502 #endif 02503 02504 KUrl KHTMLPart::completeURL( const QString &url ) 02505 { 02506 if ( !d->m_doc ) return KUrl( url ); 02507 02508 #if 0 02509 if (d->m_decoder) 02510 return KUrl(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum()); 02511 #endif 02512 02513 return KUrl( d->m_doc->completeURL( url ) ); 02514 } 02515 02516 QString KHTMLPartPrivate::codeForJavaScriptURL(const QString &u) 02517 { 02518 return KUrl::fromPercentEncoding( u.right( u.length() - 11 ).toUtf8() ); 02519 } 02520 02521 void KHTMLPartPrivate::executeJavascriptURL(const QString &u) 02522 { 02523 QString script = codeForJavaScriptURL(u); 02524 kDebug( 6050 ) << "script=" << script; 02525 QVariant res = q->executeScript( DOM::Node(), script ); 02526 if ( res.type() == QVariant::String ) { 02527 q->begin( q->url() ); 02528 q->setAlwaysHonourDoctype(); // Disable public API compat; it messes with doctype 02529 q->write( res.toString() ); 02530 q->end(); 02531 } 02532 emit q->completed(); 02533 } 02534 02535 bool KHTMLPartPrivate::isJavaScriptURL(const QString& url) 02536 { 02537 return url.indexOf( QLatin1String( "javascript:" ), 0, Qt::CaseInsensitive ) == 0; 02538 } 02539 02540 // Called by ecma/kjs_window in case of redirections from Javascript, 02541 // and by xml/dom_docimpl.cpp in case of http-equiv meta refresh. 02542 void KHTMLPart::scheduleRedirection( int delay, const QString &url, bool doLockHistory ) 02543 { 02544 kDebug(6050) << "delay=" << delay << " url=" << url << " from=" << this->url() << "parent=" << parentPart(); 02545 kDebug(6050) << "current redirectURL=" << d->m_redirectURL << " with delay " << d->m_delayRedirect; 02546 02547 // In case of JS redirections, some, such as jump to anchors, and javascript: 02548 // evaluation should actually be handled immediately, and not waiting until 02549 // the end of the script. (Besides, we don't want to abort the tokenizer for those) 02550 if ( delay == -1 && d->isInPageURL(url) ) { 02551 d->executeInPageURL(url, doLockHistory); 02552 return; 02553 } 02554 02555 if( delay < 24*60*60 && 02556 ( d->m_redirectURL.isEmpty() || delay <= d->m_delayRedirect) ) { 02557 d->m_delayRedirect = delay; 02558 d->m_redirectURL = url; 02559 d->m_redirectLockHistory = doLockHistory; 02560 kDebug(6050) << " d->m_bComplete=" << d->m_bComplete; 02561 02562 if ( d->m_bComplete ) { 02563 d->m_redirectionTimer.stop(); 02564 d->m_redirectionTimer.setSingleShot( true ); 02565 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) ); 02566 } 02567 } 02568 } 02569 02570 void KHTMLPartPrivate::clearRedirection() 02571 { 02572 m_delayRedirect = 0; 02573 m_redirectURL.clear(); 02574 m_redirectionTimer.stop(); 02575 } 02576 02577 void KHTMLPart::slotRedirect() 02578 { 02579 kDebug(6050) << this; 02580 QString u = d->m_redirectURL; 02581 KUrl url( u ); 02582 d->clearRedirection(); 02583 02584 if ( d->isInPageURL(u) ) 02585 { 02586 d->executeInPageURL(u, d->m_redirectLockHistory); 02587 return; 02588 } 02589 02590 KParts::OpenUrlArguments args; 02591 KUrl cUrl( this->url() ); 02592 02593 // handle windows opened by JS 02594 if ( openedByJS() && d->m_opener ) 02595 cUrl = d->m_opener->url(); 02596 02597 if (!KAuthorized::authorizeUrlAction("redirect", cUrl, url)) 02598 { 02599 kWarning(6050) << "KHTMLPart::scheduleRedirection: Redirection from " << cUrl << " to " << url << " REJECTED!"; 02600 emit completed(); 02601 return; 02602 } 02603 02604 if ( url.equals(this->url(), 02605 KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment | KUrl::AllowEmptyPath) ) 02606 { 02607 args.metaData().insert("referrer", d->m_pageReferrer); 02608 } 02609 02610 // For javascript and META-tag based redirections: 02611 // - We don't take cross-domain-ness in consideration if we are the 02612 // toplevel frame because the new URL may be in a different domain as the current URL 02613 // but that's ok. 02614 // - If we are not the toplevel frame then we check against the toplevelURL() 02615 if (parentPart()) 02616 args.metaData().insert("cross-domain", toplevelURL().url()); 02617 02618 KParts::BrowserArguments browserArgs; 02619 browserArgs.setLockHistory( d->m_redirectLockHistory ); 02620 // _self: make sure we don't use any <base target=>'s 02621 02622 if ( !urlSelected( u, 0, 0, "_self", args, browserArgs ) ) { 02623 // urlSelected didn't open a url, so emit completed ourselves 02624 emit completed(); 02625 } 02626 } 02627 02628 void KHTMLPart::slotRedirection(KIO::Job*, const KUrl& url) 02629 { 02630 // the slave told us that we got redirected 02631 //kDebug( 6050 ) << "redirection by KIO to" << url; 02632 emit d->m_extension->setLocationBarUrl( url.prettyUrl() ); 02633 d->m_workingURL = url; 02634 } 02635 02636 bool KHTMLPart::setEncoding( const QString &name, bool override ) 02637 { 02638 d->m_encoding = name; 02639 d->m_haveEncoding = override; 02640 02641 if( !url().isEmpty() ) { 02642 // reload document 02643 closeUrl(); 02644 KUrl oldUrl = url(); 02645 setUrl(KUrl()); 02646 d->m_restored = true; 02647 openUrl(oldUrl); 02648 d->m_restored = false; 02649 } 02650 02651 return true; 02652 } 02653 02654 QString KHTMLPart::encoding() const 02655 { 02656 if(d->m_haveEncoding && !d->m_encoding.isEmpty()) 02657 return d->m_encoding; 02658 02659 if(d->m_decoder && d->m_decoder->encoding()) 02660 return QString(d->m_decoder->encoding()); 02661 02662 return defaultEncoding(); 02663 } 02664 02665 QString KHTMLPart::defaultEncoding() const 02666 { 02667 QString encoding = settings()->encoding(); 02668 if ( !encoding.isEmpty() ) 02669 return encoding; 02670 // HTTP requires the default encoding to be latin1, when neither 02671 // the user nor the page requested a particular encoding. 02672 if ( url().protocol().startsWith( "http" ) ) 02673 return "iso-8859-1"; 02674 else 02675 return KGlobal::locale()->encoding(); 02676 } 02677 02678 void KHTMLPart::setUserStyleSheet(const KUrl &url) 02679 { 02680 if ( d->m_doc && d->m_doc->docLoader() ) 02681 (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader()); 02682 } 02683 02684 void KHTMLPart::setUserStyleSheet(const QString &styleSheet) 02685 { 02686 if ( d->m_doc ) 02687 d->m_doc->setUserStyleSheet( styleSheet ); 02688 } 02689 02690 bool KHTMLPart::gotoAnchor( const QString &name ) 02691 { 02692 if (!d->m_doc) 02693 return false; 02694 02695 HTMLCollectionImpl *anchors = 02696 new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS); 02697 anchors->ref(); 02698 NodeImpl *n = anchors->namedItem(name); 02699 anchors->deref(); 02700 02701 if(!n) { 02702 n = d->m_doc->getElementById( name ); 02703 } 02704 02705 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target. 02706 02707 // Implement the rule that "" and "top" both mean top of page as in other browsers. 02708 bool quirkyName = !n && !d->m_doc->inStrictMode() && (name.isEmpty() || name.toLower() == "top"); 02709 02710 if (quirkyName) { 02711 d->m_view->setContentsPos( d->m_view->contentsX(), 0); 02712 return true; 02713 } else if (!n) { 02714 kDebug(6050) << name << "not found"; 02715 return false; 02716 } 02717 02718 int x = 0, y = 0; 02719 int gox, dummy; 02720 HTMLElementImpl *a = static_cast<HTMLElementImpl *>(n); 02721 02722 a->getUpperLeftCorner(x, y); 02723 if (x <= d->m_view->contentsX()) 02724 gox = x - 10; 02725 else { 02726 gox = d->m_view->contentsX(); 02727 if ( x + 10 > d->m_view->contentsX()+d->m_view->visibleWidth()) { 02728 a->getLowerRightCorner(x, dummy); 02729 gox = x - d->m_view->visibleWidth() + 10; 02730 } 02731 } 02732 02733 d->m_view->setContentsPos(gox, y); 02734 02735 return true; 02736 } 02737 02738 bool KHTMLPart::nextAnchor() 02739 { 02740 if (!d->m_doc) 02741 return false; 02742 d->m_view->focusNextPrevNode ( true ); 02743 02744 return true; 02745 } 02746 02747 bool KHTMLPart::prevAnchor() 02748 { 02749 if (!d->m_doc) 02750 return false; 02751 d->m_view->focusNextPrevNode ( false ); 02752 02753 return true; 02754 } 02755 02756 void KHTMLPart::setStandardFont( const QString &name ) 02757 { 02758 d->m_settings->setStdFontName(name); 02759 } 02760 02761 void KHTMLPart::setFixedFont( const QString &name ) 02762 { 02763 d->m_settings->setFixedFontName(name); 02764 } 02765 02766 void KHTMLPart::setURLCursor( const QCursor &c ) 02767 { 02768 d->m_linkCursor = c; 02769 } 02770 02771 QCursor KHTMLPart::urlCursor() const 02772 { 02773 return d->m_linkCursor; 02774 } 02775 02776 bool KHTMLPart::onlyLocalReferences() const 02777 { 02778 return d->m_onlyLocalReferences; 02779 } 02780 02781 void KHTMLPart::setOnlyLocalReferences(bool enable) 02782 { 02783 d->m_onlyLocalReferences = enable; 02784 } 02785 02786 bool KHTMLPart::forcePermitLocalImages() const 02787 { 02788 return d->m_forcePermitLocalImages; 02789 } 02790 02791 void KHTMLPart::setForcePermitLocalImages(bool enable) 02792 { 02793 d->m_forcePermitLocalImages = enable; 02794 } 02795 02796 void KHTMLPartPrivate::setFlagRecursively( 02797 bool KHTMLPartPrivate::*flag, bool value) 02798 { 02799 // first set it on the current one 02800 this->*flag = value; 02801 02802 // descend into child frames recursively 02803 { 02804 QList<khtml::ChildFrame*>::Iterator it = m_frames.begin(); 02805 const QList<khtml::ChildFrame*>::Iterator itEnd = m_frames.end(); 02806 for (; it != itEnd; ++it) { 02807 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part.data() ); 02808 if (part) 02809 part->d->setFlagRecursively(flag, value); 02810 }/*next it*/ 02811 } 02812 // do the same again for objects 02813 { 02814 QList<khtml::ChildFrame*>::Iterator it = m_objects.begin(); 02815 const QList<khtml::ChildFrame*>::Iterator itEnd = m_objects.end(); 02816 for (; it != itEnd; ++it) { 02817 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part.data() ); 02818 if (part) 02819 part->d->setFlagRecursively(flag, value); 02820 }/*next it*/ 02821 } 02822 } 02823 02824 void KHTMLPart::initCaret() 02825 { 02826 // initialize caret if not used yet 02827 if (d->editor_context.m_selection.state() == Selection::NONE) { 02828 if (d->m_doc) { 02829 NodeImpl *node; 02830 if (d->m_doc->isHTMLDocument()) { 02831 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc); 02832 node = htmlDoc->body(); 02833 } else 02834 node = d->m_doc; 02835 if (!node) return; 02836 d->editor_context.m_selection.moveTo(Position(node, 0)); 02837 d->editor_context.m_selection.setNeedsLayout(); 02838 d->editor_context.m_selection.needsCaretRepaint(); 02839 } 02840 } 02841 } 02842 02843 static void setCaretInvisibleIfNeeded(KHTMLPart *part) 02844 { 02845 // On contenteditable nodes, don't hide the caret 02846 if (!khtml::KHTMLPartAccessor::caret(part).caretPos().node()->isContentEditable()) 02847 part->setCaretVisible(false); 02848 } 02849 02850 void KHTMLPart::setCaretMode(bool enable) 02851 { 02852 kDebug(6200) << enable; 02853 if (isCaretMode() == enable) return; 02854 d->setFlagRecursively(&KHTMLPartPrivate::m_caretMode, enable); 02855 // FIXME: this won't work on frames as expected 02856 if (!isEditable()) { 02857 if (enable) { 02858 initCaret(); 02859 setCaretVisible(true); 02860 // view()->ensureCaretVisible(); 02861 } else { 02862 setCaretInvisibleIfNeeded(this); 02863 } 02864 } 02865 } 02866 02867 bool KHTMLPart::isCaretMode() const 02868 { 02869 return d->m_caretMode; 02870 } 02871 02872 void KHTMLPart::setEditable(bool enable) 02873 { 02874 if (isEditable() == enable) return; 02875 d->setFlagRecursively(&KHTMLPartPrivate::m_designMode, enable); 02876 // FIXME: this won't work on frames as expected 02877 if (!isCaretMode()) { 02878 if (enable) { 02879 initCaret(); 02880 setCaretVisible(true); 02881 // view()->ensureCaretVisible(); 02882 } else 02883 setCaretInvisibleIfNeeded(this); 02884 } 02885 } 02886 02887 bool KHTMLPart::isEditable() const 02888 { 02889 return d->m_designMode; 02890 } 02891 02892 khtml::EditorContext *KHTMLPart::editorContext() const { 02893 return &d->editor_context; 02894 } 02895 02896 void KHTMLPart::setCaretPosition(DOM::Node node, long offset, bool extendSelection) 02897 { 02898 Q_UNUSED(node); 02899 Q_UNUSED(offset); 02900 Q_UNUSED(extendSelection); 02901 #ifndef KHTML_NO_CARET 02902 #if 0 02903 kDebug(6200) << "node: " << node.handle() << " nodeName: " 02904 << node.nodeName().string() << " offset: " << offset 02905 << " extendSelection " << extendSelection; 02906 if (view()->moveCaretTo(node.handle(), offset, !extendSelection)) 02907 emitSelectionChanged(); 02908 view()->ensureCaretVisible(); 02909 #endif 02910 #endif // KHTML_NO_CARET 02911 } 02912 02913 KHTMLPart::CaretDisplayPolicy KHTMLPart::caretDisplayPolicyNonFocused() const 02914 { 02915 #if 0 02916 #ifndef KHTML_NO_CARET 02917 return (CaretDisplayPolicy)view()->caretDisplayPolicyNonFocused(); 02918 #else // KHTML_NO_CARET 02919 return CaretInvisible; 02920 #endif // KHTML_NO_CARET 02921 #endif 02922 return CaretInvisible; 02923 } 02924 02925 void KHTMLPart::setCaretDisplayPolicyNonFocused(CaretDisplayPolicy policy) 02926 { 02927 Q_UNUSED(policy); 02928 #if 0 02929 #ifndef KHTML_NO_CARET 02930 view()->setCaretDisplayPolicyNonFocused(policy); 02931 #endif // KHTML_NO_CARET 02932 #endif 02933 } 02934 02935 void KHTMLPart::setCaretVisible(bool show) 02936 { 02937 if (show) { 02938 NodeImpl *caretNode = d->editor_context.m_selection.caretPos().node(); 02939 if (isCaretMode() || (caretNode && caretNode->isContentEditable())) { 02940 invalidateSelection(); 02941 enableFindAheadActions(false); 02942 } 02943 } else { 02944 02945 if (d->editor_context.m_caretBlinkTimer >= 0) 02946 killTimer(d->editor_context.m_caretBlinkTimer); 02947 clearCaretRectIfNeeded(); 02948 02949 } 02950 } 02951 02952 void KHTMLPart::findTextBegin() 02953 { 02954 d->m_find.findTextBegin(); 02955 } 02956 02957 bool KHTMLPart::initFindNode( bool selection, bool reverse, bool fromCursor ) 02958 { 02959 return d->m_find.initFindNode(selection, reverse, fromCursor); 02960 } 02961 02962 void KHTMLPart::slotFind() 02963 { 02964 KParts::ReadOnlyPart *part = currentFrame(); 02965 if (!part) 02966 return; 02967 if (!part->inherits("KHTMLPart") ) 02968 { 02969 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it"; 02970 return; 02971 } 02972 static_cast<KHTMLPart *>( part )->findText(); 02973 } 02974 02975 void KHTMLPart::slotFindNext() 02976 { 02977 KParts::ReadOnlyPart *part = currentFrame(); 02978 if (!part) 02979 return; 02980 if (!part->inherits("KHTMLPart") ) 02981 { 02982 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it"; 02983 return; 02984 } 02985 static_cast<KHTMLPart *>( part )->findTextNext(); 02986 } 02987 02988 void KHTMLPart::slotFindPrev() 02989 { 02990 KParts::ReadOnlyPart *part = currentFrame(); 02991 if (!part) 02992 return; 02993 if (!part->inherits("KHTMLPart") ) 02994 { 02995 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it"; 02996 return; 02997 } 02998 static_cast<KHTMLPart *>( part )->findTextNext( true ); // reverse 02999 } 03000 03001 void KHTMLPart::slotFindDone() 03002 { 03003 // ### remove me 03004 } 03005 03006 void KHTMLPart::slotFindAheadText() 03007 { 03008 KHTMLPart *part = qobject_cast<KHTMLPart*>(currentFrame()); 03009 if (!part) 03010 return; 03011 part->findText(); 03012 KHTMLFindBar* findBar = part->d->m_find.findBar(); 03013 findBar->setOptions(findBar->options() & ~FindLinksOnly); 03014 } 03015 03016 void KHTMLPart::slotFindAheadLink() 03017 { 03018 KHTMLPart *part = qobject_cast<KHTMLPart*>(currentFrame()); 03019 if (!part) 03020 return; 03021 part->findText(); 03022 KHTMLFindBar* findBar = part->d->m_find.findBar(); 03023 findBar->setOptions(findBar->options() | FindLinksOnly); 03024 } 03025 03026 void KHTMLPart::enableFindAheadActions( bool ) 03027 { 03028 // ### remove me 03029 } 03030 03031 void KHTMLPart::slotFindDialogDestroyed() 03032 { 03033 // ### remove me 03034 } 03035 03036 void KHTMLPart::findText() 03037 { 03038 if (parentPart()) 03039 return parentPart()->findText(); 03040 d->m_find.activate(); 03041 } 03042 03043 void KHTMLPart::findText( const QString &str, long options, QWidget *parent, KFindDialog *findDialog ) 03044 { 03045 if (parentPart()) 03046 return parentPart()->findText(str, options, parent, findDialog); 03047 d->m_find.createNewKFind(str, options, parent, findDialog ); 03048 } 03049 03050 // New method 03051 bool KHTMLPart::findTextNext( bool reverse ) 03052 { 03053 if (parentPart()) 03054 return parentPart()->findTextNext( reverse ); 03055 return d->m_find.findTextNext( reverse ); 03056 } 03057 03058 bool KHTMLPart::pFindTextNextInThisFrame( bool reverse ) 03059 { 03060 return d->m_find.findTextNext( reverse ); 03061 } 03062 03063 QString KHTMLPart::selectedTextAsHTML() const 03064 { 03065 const Selection &sel = d->editor_context.m_selection; 03066 if(!hasSelection()) { 03067 kDebug() << "Selection is not valid. Returning empty selection"; 03068 return QString(); 03069 } 03070 if(sel.start().offset() < 0 || sel.end().offset() < 0) { 03071 kDebug() << "invalid values for end/startOffset " << sel.start().offset() << " " << sel.end().offset(); 03072 return QString(); 03073 } 03074 DOM::Range r = selection(); 03075 if(r.isNull() || r.isDetached()) 03076 return QString(); 03077 int exceptioncode = 0; //ignore the result 03078 return r.handle()->toHTML(exceptioncode).string(); 03079 } 03080 03081 QString KHTMLPart::selectedText() const 03082 { 03083 bool hasNewLine = true; 03084 bool seenTDTag = false; 03085 QString text; 03086 const Selection &sel = d->editor_context.m_selection; 03087 DOM::Node n = sel.start().node(); 03088 while(!n.isNull()) { 03089 if(n.nodeType() == DOM::Node::TEXT_NODE && n.handle()->renderer()) { 03090 DOM::DOMStringImpl *dstr = static_cast<DOM::TextImpl*>(n.handle())->renderString(); 03091 QString str(dstr->s, dstr->l); 03092 if(!str.isEmpty()) { 03093 if(seenTDTag) { 03094 text += " "; 03095 seenTDTag = false; 03096 } 03097 hasNewLine = false; 03098 if(n == sel.start().node() && n == sel.end().node()) { 03099 int s = khtml::RenderPosition::fromDOMPosition(sel.start()).renderedOffset(); 03100 int e = khtml::RenderPosition::fromDOMPosition(sel.end()).renderedOffset(); 03101 text = str.mid(s, e-s); 03102 } else if(n == sel.start().node()) { 03103 text = str.mid(khtml::RenderPosition::fromDOMPosition(sel.start()).renderedOffset()); 03104 } else if(n == sel.end().node()) { 03105 text += str.left(khtml::RenderPosition::fromDOMPosition(sel.end()).renderedOffset()); 03106 } else 03107 text += str; 03108 } 03109 } 03110 else { 03111 // This is our simple HTML -> ASCII transformation: 03112 unsigned short id = n.elementId(); 03113 switch(id) { 03114 case ID_TEXTAREA: 03115 text += static_cast<HTMLTextAreaElementImpl*>(n.handle())->value().string(); 03116 break; 03117 case ID_INPUT: 03118 if (static_cast<HTMLInputElementImpl*>(n.handle())->inputType() != HTMLInputElementImpl::PASSWORD) 03119 text += static_cast<HTMLInputElementImpl*>(n.handle())->value().string(); 03120 break; 03121 case ID_SELECT: 03122 text += static_cast<HTMLSelectElementImpl*>(n.handle())->value().string(); 03123 break; 03124 case ID_BR: 03125 text += "\n"; 03126 hasNewLine = true; 03127 break; 03128 case ID_IMG: 03129 text += static_cast<HTMLImageElementImpl*>(n.handle())->altText().string(); 03130 break; 03131 case ID_TD: 03132 break; 03133 case ID_TH: 03134 case ID_HR: 03135 case ID_OL: 03136 case ID_UL: 03137 case ID_LI: 03138 case ID_DD: 03139 case ID_DL: 03140 case ID_DT: 03141 case ID_PRE: 03142 case ID_LISTING: 03143 case ID_BLOCKQUOTE: 03144 case ID_DIV: 03145 if (!hasNewLine) 03146 text += "\n"; 03147 hasNewLine = true; 03148 break; 03149 case ID_P: 03150 case ID_TR: 03151 case ID_H1: 03152 case ID_H2: 03153 case ID_H3: 03154 case ID_H4: 03155 case ID_H5: 03156 case ID_H6: 03157 if (!hasNewLine) 03158 text += "\n"; 03159 hasNewLine = true; 03160 break; 03161 } 03162 } 03163 if(n == sel.end().node()) break; 03164 DOM::Node next = n.firstChild(); 03165 if(next.isNull()) next = n.nextSibling(); 03166 while( next.isNull() && !n.parentNode().isNull() ) { 03167 n = n.parentNode(); 03168 next = n.nextSibling(); 03169 unsigned short id = n.elementId(); 03170 switch(id) { 03171 case ID_TD: 03172 seenTDTag = true; //Add two spaces after a td if then followed by text. 03173 break; 03174 case ID_TH: 03175 case ID_HR: 03176 case ID_OL: 03177 case ID_UL: 03178 case ID_LI: 03179 case ID_DD: 03180 case ID_DL: 03181 case ID_DT: 03182 case ID_PRE: 03183 case ID_LISTING: 03184 case ID_BLOCKQUOTE: 03185 case ID_DIV: 03186 seenTDTag = false; 03187 if (!hasNewLine) 03188 text += "\n"; 03189 hasNewLine = true; 03190 break; 03191 case ID_P: 03192 case ID_TR: 03193 case ID_H1: 03194 case ID_H2: 03195 case ID_H3: 03196 case ID_H4: 03197 case ID_H5: 03198 case ID_H6: 03199 if (!hasNewLine) 03200 text += "\n"; 03201 // text += "\n"; 03202 hasNewLine = true; 03203 break; 03204 } 03205 } 03206 03207 n = next; 03208 } 03209 03210 if(text.isEmpty()) 03211 return QString(); 03212 03213 int start = 0; 03214 int end = text.length(); 03215 03216 // Strip leading LFs 03217 while ((start < end) && (text[start] == '\n')) 03218 ++start; 03219 03220 // Strip excessive trailing LFs 03221 while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n')) 03222 --end; 03223 03224 return text.mid(start, end-start); 03225 } 03226 03227 QString KHTMLPart::simplifiedSelectedText() const 03228 { 03229 QString text = selectedText(); 03230 text.replace(QChar(0xa0), ' '); 03231 // remove leading and trailing whitespace 03232 while (!text.isEmpty() && text[0].isSpace()) 03233 text = text.mid(1); 03234 while (!text.isEmpty() && text[text.length()-1].isSpace()) 03235 text.truncate(text.length()-1); 03236 return text; 03237 } 03238 03239 bool KHTMLPart::hasSelection() const 03240 { 03241 return !d->editor_context.m_selection.isEmpty() && !d->editor_context.m_selection.isCollapsed(); 03242 } 03243 03244 DOM::Range KHTMLPart::selection() const 03245 { 03246 return d->editor_context.m_selection.toRange(); 03247 } 03248 03249 void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const 03250 { 03251 DOM::Range r = d->editor_context.m_selection.toRange(); 03252 s = r.startContainer(); 03253 so = r.startOffset(); 03254 e = r.endContainer(); 03255 eo = r.endOffset(); 03256 } 03257 03258 void KHTMLPart::setSelection( const DOM::Range &r ) 03259 { 03260 setCaret(r); 03261 } 03262 03263 const Selection &KHTMLPart::caret() const 03264 { 03265 return d->editor_context.m_selection; 03266 } 03267 03268 const Selection &KHTMLPart::dragCaret() const 03269 { 03270 return d->editor_context.m_dragCaret; 03271 } 03272 03273 void KHTMLPart::setCaret(const Selection &s, bool closeTyping) 03274 { 03275 if (d->editor_context.m_selection != s) { 03276 clearCaretRectIfNeeded(); 03277 setFocusNodeIfNeeded(s); 03278 d->editor_context.m_selection = s; 03279 notifySelectionChanged(closeTyping); 03280 } 03281 } 03282 03283 void KHTMLPart::setDragCaret(const DOM::Selection &dragCaret) 03284 { 03285 if (d->editor_context.m_dragCaret != dragCaret) { 03286 d->editor_context.m_dragCaret.needsCaretRepaint(); 03287 d->editor_context.m_dragCaret = dragCaret; 03288 d->editor_context.m_dragCaret.needsCaretRepaint(); 03289 } 03290 } 03291 03292 void KHTMLPart::clearSelection() 03293 { 03294 clearCaretRectIfNeeded(); 03295 setFocusNodeIfNeeded(d->editor_context.m_selection); 03296 #ifdef APPLE_CHANGES 03297 d->editor_context.m_selection.clear(); 03298 #else 03299 d->editor_context.m_selection.collapse(); 03300 #endif 03301 notifySelectionChanged(); 03302 } 03303 03304 void KHTMLPart::invalidateSelection() 03305 { 03306 clearCaretRectIfNeeded(); 03307 d->editor_context.m_selection.setNeedsLayout(); 03308 selectionLayoutChanged(); 03309 } 03310 03311 void KHTMLPart::setSelectionVisible(bool flag) 03312 { 03313 if (d->editor_context.m_caretVisible == flag) 03314 return; 03315 03316 clearCaretRectIfNeeded(); 03317 setFocusNodeIfNeeded(d->editor_context.m_selection); 03318 d->editor_context.m_caretVisible = flag; 03319 // notifySelectionChanged(); 03320 } 03321 03322 #if 1 03323 void KHTMLPart::slotClearSelection() 03324 { 03325 if (!isCaretMode() 03326 && d->editor_context.m_selection.state() != Selection::NONE 03327 && !d->editor_context.m_selection.caretPos().node()->isContentEditable()) 03328 clearCaretRectIfNeeded(); 03329 bool hadSelection = hasSelection(); 03330 #ifdef APPLE_CHANGES 03331 d->editor_context.m_selection.clear(); 03332 #else 03333 d->editor_context.m_selection.collapse(); 03334 #endif 03335 if (hadSelection) 03336 notifySelectionChanged(); 03337 } 03338 #endif 03339 03340 void KHTMLPart::clearCaretRectIfNeeded() 03341 { 03342 if (d->editor_context.m_caretPaint) { 03343 d->editor_context.m_caretPaint = false; 03344 d->editor_context.m_selection.needsCaretRepaint(); 03345 } 03346 } 03347 03348 void KHTMLPart::setFocusNodeIfNeeded(const Selection &s) 03349 { 03350 if (!xmlDocImpl() || s.state() == Selection::NONE) 03351 return; 03352 03353 NodeImpl *n = s.start().node(); 03354 NodeImpl *target = (n && n->isContentEditable()) ? n : 0; 03355 if (!target) { 03356 while (n && n != s.end().node()) { 03357 if (n->isContentEditable()) { 03358 target = n; 03359 break; 03360 } 03361 n = n->traverseNextNode(); 03362 } 03363 } 03364 assert(target == 0 || target->isContentEditable()); 03365 03366 if (target) { 03367 for ( ; target && !target->isFocusable(); target = target->parentNode()) 03368 {} 03369 if (target && target->isMouseFocusable()) 03370 xmlDocImpl()->setFocusNode(target); 03371 else if (!target || !target->focused()) 03372 xmlDocImpl()->setFocusNode(0); 03373 } 03374 } 03375 03376 void KHTMLPart::selectionLayoutChanged() 03377 { 03378 // kill any caret blink timer now running 03379 if (d->editor_context.m_caretBlinkTimer >= 0) { 03380 killTimer(d->editor_context.m_caretBlinkTimer); 03381 d->editor_context.m_caretBlinkTimer = -1; 03382 } 03383 03384 // see if a new caret blink timer needs to be started 03385 if (d->editor_context.m_caretVisible 03386 && d->editor_context.m_selection.state() != Selection::NONE) { 03387 d->editor_context.m_caretPaint = isCaretMode() 03388 || d->editor_context.m_selection.caretPos().node()->isContentEditable(); 03389 if (d->editor_context.m_caretBlinks && d->editor_context.m_caretPaint) 03390 d->editor_context.m_caretBlinkTimer = startTimer(qApp->cursorFlashTime() / 2); 03391 d->editor_context.m_selection.needsCaretRepaint(); 03392 // make sure that caret is visible 03393 QRect r(d->editor_context.m_selection.getRepaintRect()); 03394 if (d->editor_context.m_caretPaint) 03395 d->m_view->ensureVisible(r.x(), r.y()); 03396 } 03397 03398 if (d->m_doc) 03399 d->m_doc->updateSelection(); 03400 03401 // Always clear the x position used for vertical arrow navigation. 03402 // It will be restored by the vertical arrow navigation code if necessary. 03403 d->editor_context.m_xPosForVerticalArrowNavigation = d->editor_context.NoXPosForVerticalArrowNavigation; 03404 } 03405 03406 void KHTMLPart::notifySelectionChanged(bool closeTyping) 03407 { 03408 Editor *ed = d->editor_context.m_editor; 03409 selectionLayoutChanged(); 03410 if (ed) { 03411 ed->clearTypingStyle(); 03412 03413 if (closeTyping) 03414 ed->closeTyping(); 03415 } 03416 03417 emitSelectionChanged(); 03418 } 03419 03420 void KHTMLPart::timerEvent(QTimerEvent *e) 03421 { 03422 if (e->timerId() == d->editor_context.m_caretBlinkTimer) { 03423 if (d->editor_context.m_caretBlinks && 03424 d->editor_context.m_selection.state() != Selection::NONE) { 03425 d->editor_context.m_caretPaint = !d->editor_context.m_caretPaint; 03426 d->editor_context.m_selection.needsCaretRepaint(); 03427 } 03428 } else if (e->timerId() == d->m_DNSPrefetchTimer) { 03429 // kDebug( 6050 ) << "will lookup " << d->m_DNSPrefetchQueue.head() << d->m_numDNSPrefetchedNames; 03430 KIO::HostInfo::prefetchHost( d->m_DNSPrefetchQueue.dequeue() ); 03431 if (d->m_DNSPrefetchQueue.isEmpty()) { 03432 killTimer( d->m_DNSPrefetchTimer ); 03433 d->m_DNSPrefetchTimer = -1; 03434 } 03435 } else if (e->timerId() == d->m_DNSTTLTimer) { 03436 foreach (const QString &name, d->m_lookedupHosts) 03437 d->m_DNSPrefetchQueue.enqueue(name); 03438 if (d->m_DNSPrefetchTimer <= 0) 03439 d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay ); 03440 } 03441 } 03442 03443 bool KHTMLPart::mayPrefetchHostname( const QString& name ) 03444 { 03445 if (d->m_bDNSPrefetch == DNSPrefetchDisabled) 03446 return false; 03447 03448 if (d->m_numDNSPrefetchedNames >= sMaxDNSPrefetchPerPage) 03449 return false; 03450 03451 if (d->m_bDNSPrefetch == DNSPrefetchOnlyWWWAndSLD) { 03452 int dots = name.count('.'); 03453 if (dots > 2 || (dots == 2 && !name.startsWith("www."))) 03454 return false; 03455 } 03456 03457 if ( d->m_lookedupHosts.contains( name ) ) 03458 return false; 03459 03460 d->m_DNSPrefetchQueue.enqueue( name ); 03461 d->m_lookedupHosts.insert( name ); 03462 d->m_numDNSPrefetchedNames++; 03463 03464 if (d->m_DNSPrefetchTimer < 1) 03465 d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay ); 03466 if (d->m_DNSTTLTimer < 1) 03467 d->m_DNSTTLTimer = startTimer( sDNSTTLSeconds*1000 + 1 ); 03468 03469 return true; 03470 } 03471 03472 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const 03473 { 03474 if (d->editor_context.m_caretPaint) 03475 d->editor_context.m_selection.paintCaret(p, rect); 03476 } 03477 03478 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const 03479 { 03480 d->editor_context.m_dragCaret.paintCaret(p, rect); 03481 } 03482 03483 DOM::Editor *KHTMLPart::editor() const { 03484 if (!d->editor_context.m_editor) 03485 const_cast<KHTMLPart *>(this)->d->editor_context.m_editor = new DOM::Editor(const_cast<KHTMLPart *>(this)); 03486 return d->editor_context.m_editor; 03487 } 03488 03489 void KHTMLPart::resetHoverText() 03490 { 03491 if( !d->m_overURL.isEmpty() ) // Only if we were showing a link 03492 { 03493 d->m_overURL.clear(); 03494 d->m_overURLTarget.clear(); 03495 emit onURL( QString() ); 03496 // revert to default statusbar text 03497 setStatusBarText(QString(), BarHoverText); 03498 emit d->m_extension->mouseOverInfo(KFileItem()); 03499 } 03500 } 03501 03502 void KHTMLPart::overURL( const QString &url, const QString &target, bool /*shiftPressed*/ ) 03503 { 03504 KUrl u = completeURL(url); 03505 03506 // special case for <a href=""> 03507 if ( url.isEmpty() ) 03508 u.setFileName( url ); 03509 03510 emit onURL( url ); 03511 03512 if ( url.isEmpty() ) { 03513 setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText); 03514 return; 03515 } 03516 03517 if ( d->isJavaScriptURL(url) ) { 03518 QString jscode = d->codeForJavaScriptURL( url ); 03519 jscode = KStringHandler::rsqueeze( jscode, 80 ); // truncate if too long 03520 if (url.startsWith("javascript:window.open")) 03521 jscode += i18n(" (In new window)"); 03522 setStatusBarText( Qt::escape( jscode ), BarHoverText ); 03523 return; 03524 } 03525 03526 KFileItem item(u, QString(), KFileItem::Unknown); 03527 emit d->m_extension->mouseOverInfo(item); 03528 03529 QString com; 03530 03531 KMimeType::Ptr typ = KMimeType::findByUrl( u ); 03532 03533 if ( typ ) 03534 com = typ->comment( u ); 03535 03536 if ( !u.isValid() ) { 03537 setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText); 03538 return; 03539 } 03540 03541 if ( u.isLocalFile() ) 03542 { 03543 // TODO : use KIO::stat() and create a KFileItem out of its result, 03544 // to use KFileItem::statusBarText() 03545 const QString path = QFile::encodeName( u.toLocalFile() ); 03546 03547 KDE_struct_stat buff; 03548 bool ok = !KDE::stat( path, &buff ); 03549 03550 KDE_struct_stat lbuff; 03551 if (ok) ok = !KDE::lstat( path, &lbuff ); 03552 03553 QString text = Qt::escape(u.prettyUrl()); 03554 QString text2 = text; 03555 03556 if (ok && S_ISLNK( lbuff.st_mode ) ) 03557 { 03558 QString tmp; 03559 if ( com.isNull() ) 03560 tmp = i18n( "Symbolic Link"); 03561 else 03562 tmp = i18n("%1 (Link)", com); 03563 char buff_two[1024]; 03564 text += " -> "; 03565 int n = readlink ( path.toLocal8Bit().data(), buff_two, 1022); 03566 if (n == -1) 03567 { 03568 text2 += " "; 03569 text2 += tmp; 03570 setStatusBarText(text2, BarHoverText); 03571 return; 03572 } 03573 buff_two[n] = 0; 03574 03575 text += buff_two; 03576 text += " "; 03577 text += tmp; 03578 } 03579 else if ( ok && S_ISREG( buff.st_mode ) ) 03580 { 03581 if (buff.st_size < 1024) 03582 text = i18np("%2 (%1 byte)", "%2 (%1 bytes)", (long) buff.st_size, text2); // always put the URL last, in case it contains '%' 03583 else 03584 { 03585 float d = (float) buff.st_size/1024.0; 03586 text = i18n("%2 (%1 K)", KGlobal::locale()->formatNumber(d, 2), text2); // was %.2f 03587 } 03588 text += " "; 03589 text += com; 03590 } 03591 else if ( ok && S_ISDIR( buff.st_mode ) ) 03592 { 03593 text += " "; 03594 text += com; 03595 } 03596 else 03597 { 03598 text += " "; 03599 text += com; 03600 } 03601 setStatusBarText(text, BarHoverText); 03602 } 03603 else 03604 { 03605 QString extra; 03606 if (target.toLower() == "_blank") 03607 { 03608 extra = i18n(" (In new window)"); 03609 } 03610 else if (!target.isEmpty() && 03611 (target.toLower() != "_top") && 03612 (target.toLower() != "_self") && 03613 (target.toLower() != "_parent")) 03614 { 03615 KHTMLPart *p = this; 03616 while (p->parentPart()) 03617 p = p->parentPart(); 03618 if (!p->frameExists(target)) 03619 extra = i18n(" (In new window)"); 03620 else 03621 extra = i18n(" (In other frame)"); 03622 } 03623 03624 if (u.protocol() == QLatin1String("mailto")) { 03625 QString mailtoMsg /* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/; 03626 mailtoMsg += i18n("Email to: ") + KUrl::fromPercentEncoding(u.path().toLatin1()); 03627 const QStringList queries = u.query().mid(1).split('&'); 03628 QStringList::ConstIterator it = queries.begin(); 03629 const QStringList::ConstIterator itEnd = queries.end(); 03630 for (; it != itEnd; ++it) 03631 if ((*it).startsWith(QLatin1String("subject="))) 03632 mailtoMsg += i18n(" - Subject: ") + KUrl::fromPercentEncoding((*it).mid(8).toLatin1()); 03633 else if ((*it).startsWith(QLatin1String("cc="))) 03634 mailtoMsg += i18n(" - CC: ") + KUrl::fromPercentEncoding((*it).mid(3).toLatin1()); 03635 else if ((*it).startsWith(QLatin1String("bcc="))) 03636 mailtoMsg += i18n(" - BCC: ") + KUrl::fromPercentEncoding((*it).mid(4).toLatin1()); 03637 mailtoMsg = Qt::escape(mailtoMsg); 03638 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), QString()); 03639 setStatusBarText("<qt>"+mailtoMsg, BarHoverText); 03640 return; 03641 } 03642 // Is this check necessary at all? (Frerich) 03643 #if 0 03644 else if (u.protocol() == QLatin1String("http")) { 03645 DOM::Node hrefNode = nodeUnderMouse().parentNode(); 03646 while (hrefNode.nodeName().string() != QLatin1String("A") && !hrefNode.isNull()) 03647 hrefNode = hrefNode.parentNode(); 03648 03649 if (!hrefNode.isNull()) { 03650 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG"); 03651 if (!hreflangNode.isNull()) { 03652 QString countryCode = hreflangNode.nodeValue().string().toLower(); 03653 // Map the language code to an appropriate country code. 03654 if (countryCode == QLatin1String("en")) 03655 countryCode = QLatin1String("gb"); 03656 QString flagImg = QLatin1String("<img src=%1>").arg( 03657 locate("locale", QLatin1String("l10n/") 03658 + countryCode 03659 + QLatin1String("/flag.png"))); 03660 emit setStatusBarText(flagImg + u.prettyUrl() + extra); 03661 } 03662 } 03663 } 03664 #endif 03665 setStatusBarText(Qt::escape(u.prettyUrl()) + extra, BarHoverText); 03666 } 03667 } 03668 03669 // 03670 // This executes in the active part on a click or other url selection action in 03671 // that active part. 03672 // 03673 bool KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target, const KParts::OpenUrlArguments& _args, const KParts::BrowserArguments& _browserArgs ) 03674 { 03675 KParts::OpenUrlArguments args = _args; 03676 KParts::BrowserArguments browserArgs = _browserArgs; 03677 bool hasTarget = false; 03678 03679 QString target = _target; 03680 if ( target.isEmpty() && d->m_doc ) 03681 target = d->m_doc->baseTarget(); 03682 if ( !target.isEmpty() ) 03683 hasTarget = true; 03684 03685 if ( d->isJavaScriptURL(url) ) 03686 { 03687 crossFrameExecuteScript( target, d->codeForJavaScriptURL(url) ); 03688 return false; 03689 } 03690 03691 KUrl cURL = completeURL(url); 03692 // special case for <a href=""> (IE removes filename, mozilla doesn't) 03693 if ( url.isEmpty() ) 03694 cURL.setFileName( url ); // removes filename 03695 03696 if ( !cURL.isValid() ) 03697 // ### ERROR HANDLING 03698 return false; 03699 03700 kDebug(6050) << this << "complete URL:" << cURL.url() << "target=" << target; 03701 03702 if ( state & Qt::ControlModifier ) 03703 { 03704 emit d->m_extension->createNewWindow( cURL, args, browserArgs ); 03705 return true; 03706 } 03707 03708 if ( button == Qt::LeftButton && ( state & Qt::ShiftModifier ) ) 03709 { 03710 KIO::MetaData metaData; 03711 metaData.insert( "referrer", d->m_referrer ); 03712 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), cURL, metaData ); 03713 return false; 03714 } 03715 03716 if (!checkLinkSecurity(cURL, 03717 ki18n( "<qt>This untrusted page links to<br /><b>%1</b>.<br />Do you want to follow the link?</qt>" ), 03718 i18n( "Follow" ))) 03719 return false; 03720 03721 browserArgs.frameName = target; 03722 03723 args.metaData().insert("main_frame_request", 03724 parentPart() == 0 ? "TRUE":"FALSE"); 03725 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip); 03726 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert); 03727 args.metaData().insert("PropagateHttpHeader", "true"); 03728 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE"); 03729 args.metaData().insert("ssl_activate_warnings", "TRUE"); 03730 03731 if ( hasTarget && target != "_self" && target != "_top" && target != "_blank" && target != "_parent" ) 03732 { 03733 // unknown frame names should open in a new window. 03734 khtml::ChildFrame *frame = recursiveFrameRequest( this, cURL, args, browserArgs, false ); 03735 if ( frame ) 03736 { 03737 args.metaData()["referrer"] = d->m_referrer; 03738 requestObject( frame, cURL, args, browserArgs ); 03739 return true; 03740 } 03741 } 03742 03743 if (!d->m_referrer.isEmpty() && !args.metaData().contains("referrer")) 03744 args.metaData()["referrer"] = d->m_referrer; 03745 03746 if ( button == Qt::NoButton && (state & Qt::ShiftModifier) && (state & Qt::ControlModifier) ) 03747 { 03748 emit d->m_extension->createNewWindow( cURL, args, browserArgs ); 03749 return true; 03750 } 03751 03752 if ( state & Qt::ShiftModifier) 03753 { 03754 KParts::WindowArgs winArgs; 03755 winArgs.setLowerWindow(true); 03756 emit d->m_extension->createNewWindow( cURL, args, browserArgs, winArgs ); 03757 return true; 03758 } 03759 03760 //If we're asked to open up an anchor in the current URL, in current window, 03761 //merely gotoanchor, and do not reload the new page. Note that this does 03762 //not apply if the URL is the same page, but without a ref 03763 if (cURL.hasRef() && (!hasTarget || target == "_self")) 03764 { 03765 if (d->isLocalAnchorJump(cURL)) 03766 { 03767 d->executeAnchorJump(cURL, browserArgs.lockHistory() ); 03768 return false; // we jumped, but we didn't open a URL 03769 } 03770 } 03771 03772 if ( !d->m_bComplete && !hasTarget ) 03773 closeUrl(); 03774 03775 view()->viewport()->unsetCursor(); 03776 emit d->m_extension->openUrlRequest( cURL, args, browserArgs ); 03777 return true; 03778 } 03779 03780 void KHTMLPart::slotViewDocumentSource() 03781 { 03782 KUrl currentUrl(this->url()); 03783 bool isTempFile = false; 03784 if (!(currentUrl.isLocalFile()) && KHTMLPageCache::self()->isComplete(d->m_cacheId)) 03785 { 03786 KTemporaryFile sourceFile; 03787 sourceFile.setSuffix(defaultExtension()); 03788 sourceFile.setAutoRemove(false); 03789 if (sourceFile.open()) 03790 { 03791 QDataStream stream ( &sourceFile ); 03792 KHTMLPageCache::self()->saveData(d->m_cacheId, &stream); 03793 currentUrl = KUrl(); 03794 currentUrl.setPath(sourceFile.fileName()); 03795 isTempFile = true; 03796 } 03797 } 03798 03799 (void) KRun::runUrl( currentUrl, QLatin1String("text/plain"), view(), isTempFile ); 03800 } 03801 03802 void KHTMLPart::slotViewPageInfo() 03803 { 03804 Ui_KHTMLInfoDlg ui; 03805 03806 QDialog *dlg = new QDialog(0); 03807 dlg->setAttribute(Qt::WA_DeleteOnClose); 03808 dlg->setObjectName("KHTML Page Info Dialog"); 03809 ui.setupUi(dlg); 03810 03811 ui._close->setGuiItem(KStandardGuiItem::close()); 03812 03813 connect(ui._close, SIGNAL(clicked()), dlg, SLOT(accept())); 03814 if (d->m_doc) 03815 ui._title->setText(d->m_doc->title().string()); 03816 03817 // If it's a frame, set the caption to "Frame Information" 03818 if ( parentPart() && d->m_doc && d->m_doc->isHTMLDocument() ) { 03819 dlg->setWindowTitle(i18n("Frame Information")); 03820 } 03821 03822 QString editStr; 03823 03824 if (!d->m_pageServices.isEmpty()) 03825 editStr = i18n(" <a href=\"%1\">[Properties]</a>", d->m_pageServices); 03826 03827 QString squeezedURL = KStringHandler::csqueeze( url().prettyUrl(), 80 ); 03828 ui._url->setText("<a href=\"" + url().url() + "\">" + squeezedURL + "</a>" + editStr); 03829 if (lastModified().isEmpty()) 03830 { 03831 ui._lastModified->hide(); 03832 ui._lmLabel->hide(); 03833 } 03834 else 03835 ui._lastModified->setText(lastModified()); 03836 03837 const QString& enc = encoding(); 03838 if (enc.isEmpty()) { 03839 ui._eLabel->hide(); 03840 ui._encoding->hide(); 03841 } else { 03842 ui._encoding->setText(enc); 03843 } 03844 03845 if (!xmlDocImpl() || xmlDocImpl()->parseMode() == DOM::DocumentImpl::Unknown) { 03846 ui._mode->hide(); 03847 ui._modeLabel->hide(); 03848 } else { 03849 switch (xmlDocImpl()->parseMode()) { 03850 case DOM::DocumentImpl::Compat: 03851 ui._mode->setText(i18nc("HTML rendering mode (see http://en.wikipedia.org/wiki/Quirks_mode)", "Quirks")); 03852 break; 03853 case DOM::DocumentImpl::Transitional: 03854 ui._mode->setText(i18nc("HTML rendering mode (see http://en.wikipedia.org/wiki/Quirks_mode)", "Almost standards")); 03855 break; 03856 case DOM::DocumentImpl::Strict: 03857 default: // others handled above 03858 ui._mode->setText(i18nc("HTML rendering mode (see http://en.wikipedia.org/wiki/Quirks_mode)", "Strict")); 03859 break; 03860 } 03861 } 03862 03863 /* populate the list view now */ 03864 const QStringList headers = d->m_httpHeaders.split("\n"); 03865 03866 QStringList::ConstIterator it = headers.begin(); 03867 const QStringList::ConstIterator itEnd = headers.end(); 03868 03869 for (; it != itEnd; ++it) { 03870 const QStringList header = (*it).split(QRegExp(":[ ]+")); 03871 if (header.count() != 2) 03872 continue; 03873 QTreeWidgetItem *item = new QTreeWidgetItem(ui._headers); 03874 item->setText(0, header[0]); 03875 item->setText(1, header[1]); 03876 } 03877 03878 dlg->show(); 03879 /* put no code here */ 03880 } 03881 03882 03883 void KHTMLPart::slotViewFrameSource() 03884 { 03885 KParts::ReadOnlyPart *frame = currentFrame(); 03886 if ( !frame ) 03887 return; 03888 03889 KUrl url = frame->url(); 03890 bool isTempFile = false; 03891 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart")) 03892 { 03893 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId; 03894 03895 if (KHTMLPageCache::self()->isComplete(cacheId)) 03896 { 03897 KTemporaryFile sourceFile; 03898 sourceFile.setSuffix(defaultExtension()); 03899 sourceFile.setAutoRemove(false); 03900 if (sourceFile.open()) 03901 { 03902 QDataStream stream ( &sourceFile ); 03903 KHTMLPageCache::self()->saveData(cacheId, &stream); 03904 url = KUrl(); 03905 url.setPath(sourceFile.fileName()); 03906 isTempFile = true; 03907 } 03908 } 03909 } 03910 03911 (void) KRun::runUrl( url, QLatin1String("text/plain"), view(), isTempFile ); 03912 } 03913 03914 KUrl KHTMLPart::backgroundURL() const 03915 { 03916 // ### what about XML documents? get from CSS? 03917 if (!d->m_doc || !d->m_doc->isHTMLDocument()) 03918 return KUrl(); 03919 03920 QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string(); 03921 03922 return KUrl( url(), relURL ); 03923 } 03924 03925 void KHTMLPart::slotSaveBackground() 03926 { 03927 KIO::MetaData metaData; 03928 metaData["referrer"] = d->m_referrer; 03929 KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save Background Image As"), backgroundURL(), metaData ); 03930 } 03931 03932 void KHTMLPart::slotSaveDocument() 03933 { 03934 KUrl srcURL( url() ); 03935 03936 if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() ) 03937 srcURL.setFileName( "index" + defaultExtension() ); 03938 03939 KIO::MetaData metaData; 03940 // Referre unknown? 03941 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, "text/html", d->m_cacheId ); 03942 } 03943 03944 void KHTMLPart::slotSecurity() 03945 { 03946 // kDebug( 6050 ) << "Meta Data:" << endl 03947 // << d->m_ssl_peer_cert_subject 03948 // << endl 03949 // << d->m_ssl_peer_cert_issuer 03950 // << endl 03951 // << d->m_ssl_cipher 03952 // << endl 03953 // << d->m_ssl_cipher_desc 03954 // << endl 03955 // << d->m_ssl_cipher_version 03956 // << endl 03957 // << d->m_ssl_good_from 03958 // << endl 03959 // << d->m_ssl_good_until 03960 // << endl 03961 // << d->m_ssl_cert_state 03962 // << endl; 03963 03964 //### reenable with new signature 03965 #if 0 03966 KSslInfoDialog *kid = new KSslInfoDialog(d->m_ssl_in_use, widget(), "kssl_info_dlg", true ); 03967 03968 const QStringList sl = d->m_ssl_peer_chain.split('\n', QString::SkipEmptyParts); 03969 QList<QSslCertificate> certChain; 03970 bool certChainOk = d->m_ssl_in_use; 03971 if (certChainOk) { 03972 foreach (const QString &s, sl) { 03973 certChain.append(QSslCertificate(s.toAscii())); //or is it toLocal8Bit or whatever? 03974 if (certChain.last().isNull()) { 03975 certChainOk = false; 03976 break; 03977 } 03978 } 03979 } 03980 if (certChainOk) { 03981 kid->setup(certChain, 03982 d->m_ssl_peer_ip, 03983 url().url(), 03984 d->m_ssl_cipher, 03985 d->m_ssl_cipher_desc, 03986 d->m_ssl_cipher_version, 03987 d->m_ssl_cipher_used_bits.toInt(), 03988 d->m_ssl_cipher_bits.toInt(), 03989 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt()); 03990 } 03991 kid->exec(); 03992 //the dialog deletes itself on close 03993 #endif 03994 03995 KSslInfoDialog *kid = new KSslInfoDialog(0); 03996 //### This is boilerplate code and it's copied from SlaveInterface. 03997 QStringList sl = d->m_ssl_peer_chain.split('\x01', QString::SkipEmptyParts); 03998 QList<QSslCertificate> certChain; 03999 bool decodedOk = true; 04000 foreach (const QString &s, sl) { 04001 certChain.append(QSslCertificate(s.toAscii())); //or is it toLocal8Bit or whatever? 04002 if (certChain.last().isNull()) { 04003 decodedOk = false; 04004 break; 04005 } 04006 } 04007 04008 if (decodedOk || true /*H4X*/) { 04009 kid->setSslInfo(certChain, 04010 d->m_ssl_peer_ip, 04011 url().host(), 04012 d->m_ssl_protocol_version, 04013 d->m_ssl_cipher, 04014 d->m_ssl_cipher_used_bits.toInt(), 04015 d->m_ssl_cipher_bits.toInt(), 04016 KSslInfoDialog::errorsFromString(d->m_ssl_cert_errors)); 04017 kDebug(7024) << "Showing SSL Info dialog"; 04018 kid->exec(); 04019 kDebug(7024) << "SSL Info dialog closed"; 04020 } else { 04021 KMessageBox::information(0, i18n("The peer SSL certificate chain " 04022 "appears to be corrupt."), 04023 i18n("SSL")); 04024 } 04025 } 04026 04027 void KHTMLPart::slotSaveFrame() 04028 { 04029 KParts::ReadOnlyPart *frame = currentFrame(); 04030 if ( !frame ) 04031 return; 04032 04033 KUrl srcURL( frame->url() ); 04034 04035 if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() ) 04036 srcURL.setFileName( "index" + defaultExtension() ); 04037 04038 KIO::MetaData metaData; 04039 // Referrer unknown? 04040 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save Frame As" ), srcURL, metaData, "text/html" ); 04041 } 04042 04043 void KHTMLPart::slotSetEncoding(const QString &enc) 04044 { 04045 d->m_autoDetectLanguage=KEncodingDetector::None; 04046 setEncoding( enc, true); 04047 } 04048 04049 void KHTMLPart::slotAutomaticDetectionLanguage(KEncodingDetector::AutoDetectScript scri) 04050 { 04051 d->m_autoDetectLanguage=scri; 04052 setEncoding( QString(), false ); 04053 } 04054 04055 void KHTMLPart::slotUseStylesheet() 04056 { 04057 if (d->m_doc) 04058 { 04059 bool autoselect = (d->m_paUseStylesheet->currentItem() == 0); 04060 d->m_sheetUsed = autoselect ? QString() : d->m_paUseStylesheet->currentText(); 04061 d->m_doc->updateStyleSelector(); 04062 } 04063 } 04064 04065 void KHTMLPart::updateActions() 04066 { 04067 bool frames = false; 04068 04069 QList<khtml::ChildFrame*>::ConstIterator it = d->m_frames.constBegin(); 04070 const QList<khtml::ChildFrame*>::ConstIterator end = d->m_frames.constEnd(); 04071 for (; it != end; ++it ) 04072 if ( (*it)->m_type == khtml::ChildFrame::Frame ) 04073 { 04074 frames = true; 04075 break; 04076 } 04077 04078 if (d->m_paViewFrame) 04079 d->m_paViewFrame->setEnabled( frames ); 04080 if (d->m_paSaveFrame) 04081 d->m_paSaveFrame->setEnabled( frames ); 04082 04083 if ( frames ) 04084 d->m_paFind->setText( i18n( "&Find in Frame..." ) ); 04085 else 04086 d->m_paFind->setText( i18n( "&Find..." ) ); 04087 04088 KParts::Part *frame = 0; 04089 04090 if ( frames ) 04091 frame = currentFrame(); 04092 04093 bool enableFindAndSelectAll = true; 04094 04095 if ( frame ) 04096 enableFindAndSelectAll = frame->inherits( "KHTMLPart" ); 04097 04098 d->m_paFind->setEnabled( enableFindAndSelectAll ); 04099 d->m_paSelectAll->setEnabled( enableFindAndSelectAll ); 04100 04101 bool enablePrintFrame = false; 04102 04103 if ( frame ) 04104 { 04105 QObject *ext = KParts::BrowserExtension::childObject( frame ); 04106 if ( ext ) 04107 enablePrintFrame = ext->metaObject()->indexOfSlot( "print()" ) != -1; 04108 } 04109 04110 d->m_paPrintFrame->setEnabled( enablePrintFrame ); 04111 04112 QString bgURL; 04113 04114 // ### frames 04115 if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing ) 04116 bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string(); 04117 04118 if (d->m_paSaveBackground) 04119 d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() ); 04120 04121 if ( d->m_paDebugScript ) 04122 d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L ); 04123 } 04124 04125 KParts::ScriptableExtension *KHTMLPart::scriptableExtension( const DOM::NodeImpl *frame) { 04126 const ConstFrameIt end = d->m_objects.constEnd(); 04127 for(ConstFrameIt it = d->m_objects.constBegin(); it != end; ++it ) 04128 if ((*it)->m_partContainerElement.data() == frame) 04129 return (*it)->m_scriptable.data(); 04130 return 0L; 04131 } 04132 04133 void KHTMLPart::loadFrameElement( DOM::HTMLPartContainerElementImpl *frame, const QString &url, 04134 const QString &frameName, const QStringList ¶ms, bool isIFrame ) 04135 { 04136 //kDebug( 6050 ) << this << " requestFrame( ..., " << url << ", " << frameName << " )"; 04137 khtml::ChildFrame* child; 04138 04139 FrameIt it = d->m_frames.find( frameName ); 04140 if ( it == d->m_frames.end() ) { 04141 child = new khtml::ChildFrame; 04142 //kDebug( 6050 ) << "inserting new frame into frame map " << frameName; 04143 child->m_name = frameName; 04144 d->m_frames.insert( d->m_frames.end(), child ); 04145 } else { 04146 child = *it; 04147 } 04148 04149 child->m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame; 04150 child->m_partContainerElement = frame; 04151 child->m_params = params; 04152 04153 // If we do not have a part, make sure we create one. 04154 if (!child->m_part) { 04155 QStringList dummy; // the list of servicetypes handled by the part is now unused. 04156 QString khtml = QString::fromLatin1("khtml"); 04157 KParts::ReadOnlyPart* part = createPart(d->m_view->viewport(), this, 04158 QString::fromLatin1("text/html"), 04159 khtml, dummy, QStringList()); 04160 // We navigate it to about:blank to setup an empty one, but we do it 04161 // before hooking up the signals and extensions, so that any sync emit 04162 // of completed by the kid doesn't cause us to be marked as completed. 04163 // (async ones are discovered by the presence of the KHTMLRun) 04164 // ### load event on the kid? 04165 navigateLocalProtocol(child, part, KUrl("about:blank")); 04166 connectToChildPart(child, part, "text/html" /* mimetype of the part, not what's being loaded */); 04167 } 04168 04169 KUrl u = url.isEmpty() ? KUrl() : completeURL( url ); 04170 04171 // Since we don't specify args here a KHTMLRun will be used to determine the 04172 // mimetype, which will then be passed down at the bottom of processObjectRequest 04173 // inside URLArgs to the part. In our particular case, this means that we can 04174 // use that inside KHTMLPart::openUrl to route things appropriately. 04175 child->m_bCompleted = false; 04176 if (!requestObject( child, u ) && !child->m_run) { 04177 child->m_bCompleted = true; 04178 } 04179 } 04180 04181 QString KHTMLPart::requestFrameName() 04182 { 04183 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++); 04184 } 04185 04186 bool KHTMLPart::loadObjectElement( DOM::HTMLPartContainerElementImpl *frame, const QString &url, 04187 const QString &serviceType, const QStringList ¶ms ) 04188 { 04189 //kDebug( 6031 ) << this << "frame=" << frame; 04190 khtml::ChildFrame *child = new khtml::ChildFrame; 04191 FrameIt it = d->m_objects.insert( d->m_objects.end(), child ); 04192 (*it)->m_partContainerElement = frame; 04193 (*it)->m_type = khtml::ChildFrame::Object; 04194 (*it)->m_params = params; 04195 04196 KParts::OpenUrlArguments args; 04197 args.setMimeType(serviceType); 04198 if (!requestObject( *it, completeURL( url ), args ) && !(*it)->m_run) { 04199 (*it)->m_bCompleted = true; 04200 return false; 04201 } 04202 return true; 04203 } 04204 04205 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KUrl &url, const KParts::OpenUrlArguments &_args, 04206 const KParts::BrowserArguments& browserArgs ) 04207 { 04208 // we always permit javascript: URLs here since they're basically just 04209 // empty pages (and checkLinkSecurity/KAuthorized doesn't know what to do with them) 04210 if (!d->isJavaScriptURL(url.url()) && !checkLinkSecurity(url)) 04211 { 04212 kDebug(6031) << this << "checkLinkSecurity refused"; 04213 return false; 04214 } 04215 04216 if (d->m_bClearing) 04217 { 04218 return false; 04219 } 04220 04221 if ( child->m_bPreloaded ) 04222 { 04223 if ( child->m_partContainerElement && child->m_part ) 04224 child->m_partContainerElement.data()->setWidget( child->m_part.data()->widget() ); 04225 04226 child->m_bPreloaded = false; 04227 return true; 04228 } 04229 04230 //kDebug(6031) << "child=" << child << "child->m_part=" << child->m_part; 04231 04232 KParts::OpenUrlArguments args( _args ); 04233 04234 if ( child->m_run ) { 04235 kDebug(6031) << "navigating ChildFrame while mimetype resolution was in progress..."; 04236 child->m_run.data()->abort(); 04237 } 04238 04239 // ### Dubious -- the whole dir/ vs. img thing 04240 if ( child->m_part && !args.reload() && child->m_part.data()->url().equals( url, 04241 KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment | KUrl::AllowEmptyPath ) ) 04242 args.setMimeType(child->m_serviceType); 04243 04244 child->m_browserArgs = browserArgs; 04245 child->m_args = args; 04246 04247 // reload/soft-reload arguments are always inherited from parent 04248 child->m_args.setReload( arguments().reload() ); 04249 child->m_browserArgs.softReload = d->m_extension->browserArguments().softReload; 04250 04251 child->m_serviceName.clear(); 04252 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" )) 04253 child->m_args.metaData()["referrer"] = d->m_referrer; 04254 04255 child->m_args.metaData().insert("PropagateHttpHeader", "true"); 04256 child->m_args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip); 04257 child->m_args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert); 04258 child->m_args.metaData().insert("main_frame_request", 04259 parentPart() == 0 ? "TRUE":"FALSE"); 04260 child->m_args.metaData().insert("ssl_was_in_use", 04261 d->m_ssl_in_use ? "TRUE":"FALSE"); 04262 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE"); 04263 child->m_args.metaData().insert("cross-domain", toplevelURL().url()); 04264 04265 // We know the frame will be text/html if the HTML says <frame src=""> or <frame src="about:blank">, 04266 // no need to KHTMLRun to figure out the mimetype" 04267 // ### What if we're inside an XML document? 04268 if ((url.isEmpty() || url.url() == "about:blank" || url.protocol() == "javascript") && args.mimeType().isEmpty()) 04269 args.setMimeType(QLatin1String("text/html")); 04270 04271 if ( args.mimeType().isEmpty() ) { 04272 kDebug(6031) << "Running new KHTMLRun for" << this << "and child=" << child; 04273 child->m_run = new KHTMLRun( this, child, url, child->m_args, child->m_browserArgs, true ); 04274 d->m_bComplete = false; // ensures we stop it in checkCompleted... 04275 return false; 04276 } else { 04277 return processObjectRequest( child, url, args.mimeType() ); 04278 } 04279 } 04280 04281 void KHTMLPart::childLoadFailure( khtml::ChildFrame *child ) 04282 { 04283 child->m_bCompleted = true; 04284 if ( child->m_partContainerElement ) 04285 child->m_partContainerElement.data()->partLoadingErrorNotify(); 04286 04287 checkCompleted(); 04288 } 04289 04290 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KUrl &_url, const QString &mimetype ) 04291 { 04292 kDebug( 6031 ) << "trying to create part for" << mimetype << _url; 04293 04294 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given 04295 // by an emitting frame part (emit openUrlRequest( blahurl, ... ) . A few lines below we delete the part 04296 // though -> the reference becomes invalid -> crash is likely 04297 KUrl url( _url ); 04298 04299 // khtmlrun called us with empty url + mimetype to indicate a loading error, 04300 // we obviosuly failed; but we can return true here since we don't want it 04301 // doing anything more, while childLoadFailure is enough to notify our kid. 04302 if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) ) { 04303 childLoadFailure(child); 04304 return true; 04305 } 04306 04307 // we also want to ignore any spurious requests due to closing when parser is being cleared. These should be 04308 // ignored entirely --- the tail end of ::clear will clean things up. 04309 if (d->m_bClearing) 04310 return false; 04311 04312 if (child->m_bNotify) { 04313 child->m_bNotify = false; 04314 if ( !child->m_browserArgs.lockHistory() ) 04315 emit d->m_extension->openUrlNotify(); 04316 } 04317 04318 // Now, depending on mimetype and current state of the world, we may have 04319 // to create a new part or ask the user to save things, etc. 04320 // 04321 // We need a new part if there isn't one at all (doh) or the one that's there 04322 // is not for the mimetype we're loading. 04323 // 04324 // For these new types, we may have to ask the user to save it or not 04325 // (we don't if it's navigating the same type). 04326 // Further, we will want to ask if content-disposition suggests we ask for 04327 // saving, even if we're re-navigating. 04328 if ( !child->m_part || child->m_serviceType != mimetype || 04329 (child->m_run && child->m_run.data()->serverSuggestsSave())) { 04330 // We often get here if we didn't know the mimetype in advance, and had to rely 04331 // on KRun to figure it out. In this case, we let the element check if it wants to 04332 // handle this mimetype itself, for e.g. objects containing images. 04333 if ( child->m_partContainerElement && 04334 child->m_partContainerElement.data()->mimetypeHandledInternally(mimetype) ) { 04335 child->m_bCompleted = true; 04336 checkCompleted(); 04337 return true; 04338 } 04339 04340 // Before attempting to load a part, check if the user wants that. 04341 // Many don't like getting ZIP files embedded. 04342 // However we don't want to ask for flash and other plugin things. 04343 // 04344 // Note: this is fine for frames, since we will merely effectively ignore 04345 // the navigation if this happens 04346 if ( child->m_type != khtml::ChildFrame::Object && child->m_type != khtml::ChildFrame::IFrame ) { 04347 QString suggestedFileName; 04348 int disposition = 0; 04349 if ( KHTMLRun* run = child->m_run.data() ) { 04350 suggestedFileName = run->suggestedFileName(); 04351 disposition = run->serverSuggestsSave() ? 04352 KParts::BrowserRun::AttachmentDisposition : 04353 KParts::BrowserRun::InlineDisposition; 04354 } 04355 04356 KParts::BrowserOpenOrSaveQuestion dlg( widget(), url, mimetype ); 04357 dlg.setSuggestedFileName( suggestedFileName ); 04358 const KParts::BrowserOpenOrSaveQuestion::Result res = dlg.askEmbedOrSave( disposition ); 04359 04360 switch( res ) { 04361 case KParts::BrowserOpenOrSaveQuestion::Save: 04362 KHTMLPopupGUIClient::saveURL( widget(), i18n( "Save As" ), url, child->m_args.metaData(), QString(), 0, suggestedFileName ); 04363 // fall-through 04364 case KParts::BrowserOpenOrSaveQuestion::Cancel: 04365 child->m_bCompleted = true; 04366 checkCompleted(); 04367 return true; // done 04368 default: // Embed 04369 break; 04370 } 04371 } 04372 04373 // Now, for frames and iframes, we always create a KHTMLPart anyway, 04374 // doing it in advance when registering the frame. So we want the 04375 // actual creation only for objects here. 04376 if ( child->m_type == khtml::ChildFrame::Object ) { 04377 KMimeType::Ptr mime = KMimeType::mimeType(mimetype); 04378 if (mime) { 04379 // Even for objects, however, we want to force a KHTMLPart for 04380 // html & xml, even if the normally preferred part is another one, 04381 // so that we can script the target natively via contentDocument method. 04382 if (mime->is("text/html") 04383 || mime->is("application/xml")) { // this includes xhtml and svg 04384 child->m_serviceName = "khtml"; 04385 } 04386 } 04387 04388 QStringList dummy; // the list of servicetypes handled by the part is now unused. 04389 KParts::ReadOnlyPart *part = createPart( d->m_view->viewport(), this, mimetype, child->m_serviceName, dummy, child->m_params ); 04390 04391 if ( !part ) { 04392 childLoadFailure(child); 04393 return false; 04394 } 04395 04396 connectToChildPart( child, part, mimetype ); 04397 } 04398 } 04399 04400 checkEmitLoadEvent(); 04401 04402 // Some JS code in the load event may have destroyed the part 04403 // In that case, abort 04404 if ( !child->m_part ) 04405 return false; 04406 04407 if ( child->m_bPreloaded ) { 04408 if ( child->m_partContainerElement && child->m_part ) 04409 child->m_partContainerElement.data()->setWidget( child->m_part.data()->widget() ); 04410 04411 child->m_bPreloaded = false; 04412 return true; 04413 } 04414 04415 // reload/soft-reload arguments are always inherited from parent 04416 child->m_args.setReload( arguments().reload() ); 04417 child->m_browserArgs.softReload = d->m_extension->browserArguments().softReload; 04418 04419 // make sure the part has a way to find out about the mimetype. 04420 // we actually set it in child->m_args in requestObject already, 04421 // but it's useless if we had to use a KHTMLRun instance, as the 04422 // point the run object is to find out exactly the mimetype. 04423 child->m_args.setMimeType(mimetype); 04424 child->m_part.data()->setArguments( child->m_args ); 04425 04426 // if not a frame set child as completed 04427 // ### dubious. 04428 child->m_bCompleted = child->m_type == khtml::ChildFrame::Object; 04429 04430 if ( child->m_extension ) 04431 child->m_extension.data()->setBrowserArguments( child->m_browserArgs ); 04432 04433 return navigateChild( child, url ); 04434 } 04435 04436 bool KHTMLPart::navigateLocalProtocol( khtml::ChildFrame* /*child*/, KParts::ReadOnlyPart *inPart, 04437 const KUrl& url ) 04438 { 04439 if (!qobject_cast<KHTMLPart*>(inPart)) 04440 return false; 04441 04442 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(inPart)); 04443 04444 p->begin(); 04445 04446 // We may have to re-propagate the domain here if we go here due to navigation 04447 d->propagateInitialDomainAndBaseTo(p); 04448 04449 // Support for javascript: sources 04450 if (d->isJavaScriptURL(url.url())) { 04451 // See if we want to replace content with javascript: output.. 04452 QVariant res = p->executeScript( DOM::Node(), 04453 d->codeForJavaScriptURL(url.url())); 04454 if (res.type() == QVariant::String && p->d->m_redirectURL.isEmpty()) { 04455 p->begin(); 04456 p->setAlwaysHonourDoctype(); // Disable public API compat; it messes with doctype 04457 // We recreated the document, so propagate domain again. 04458 d->propagateInitialDomainAndBaseTo(p); 04459 p->write( res.toString() ); 04460 p->end(); 04461 } 04462 } else { 04463 p->setUrl(url); 04464 // we need a body element. testcase: <iframe id="a"></iframe><script>alert(a.document.body);</script> 04465 p->write("<HTML><TITLE></TITLE><BODY></BODY></HTML>"); 04466 } 04467 p->end(); 04468 // we don't need to worry about child completion explicitly for KHTMLPart... 04469 // or do we? 04470 return true; 04471 } 04472 04473 bool KHTMLPart::navigateChild( khtml::ChildFrame *child, const KUrl& url ) 04474 { 04475 if (url.protocol() == "javascript" || url.url() == "about:blank") { 04476 return navigateLocalProtocol(child, child->m_part.data(), url); 04477 } else if ( !url.isEmpty() ) { 04478 kDebug( 6031 ) << "opening" << url << "in frame" << child->m_part; 04479 bool b = child->m_part.data()->openUrl( url ); 04480 if (child->m_bCompleted) 04481 checkCompleted(); 04482 return b; 04483 } else { 04484 // empty URL -> no need to navigate 04485 child->m_bCompleted = true; 04486 checkCompleted(); 04487 return true; 04488 } 04489 } 04490 04491 void KHTMLPart::connectToChildPart( khtml::ChildFrame *child, KParts::ReadOnlyPart *part, 04492 const QString& mimetype) 04493 { 04494 kDebug(6031) << "we:" << this << "kid:" << child << part << mimetype; 04495 04496 part->setObjectName( child->m_name ); 04497 04498 // Cleanup any previous part for this childframe and its connections 04499 if ( KParts::ReadOnlyPart* p = child->m_part.data() ) { 04500 if (!qobject_cast<KHTMLPart*>(p) && child->m_jscript) 04501 child->m_jscript->clear(); 04502 partManager()->removePart( p ); 04503 delete p; 04504 child->m_scriptable.clear(); 04505 } 04506 04507 child->m_part = part; 04508 04509 child->m_serviceType = mimetype; 04510 if ( child->m_partContainerElement && part->widget() ) 04511 child->m_partContainerElement.data()->setWidget( part->widget() ); 04512 04513 if ( child->m_type != khtml::ChildFrame::Object ) 04514 partManager()->addPart( part, false ); 04515 // else 04516 // kDebug(6031) << "AH! NO FRAME!!!!!"; 04517 04518 if (qobject_cast<KHTMLPart*>(part)) { 04519 static_cast<KHTMLPart*>(part)->d->m_frame = child; 04520 } else if (child->m_partContainerElement) { 04521 // See if this can be scripted.. 04522 KParts::ScriptableExtension* scriptExt = KParts::ScriptableExtension::childObject(part); 04523 if (!scriptExt) { 04524 // Try to fall back to LiveConnectExtension compat 04525 KParts::LiveConnectExtension* lc = KParts::LiveConnectExtension::childObject(part); 04526 if (lc) 04527 scriptExt = KParts::ScriptableExtension::adapterFromLiveConnect(part, lc); 04528 } 04529 04530 if (scriptExt) 04531 scriptExt->setHost(d->m_scriptableExtension); 04532 child->m_scriptable = scriptExt; 04533 } 04534 KParts::StatusBarExtension *sb = KParts::StatusBarExtension::childObject(part); 04535 if (sb) 04536 sb->setStatusBar( d->m_statusBarExtension->statusBar() ); 04537 04538 connect( part, SIGNAL( started( KIO::Job *) ), 04539 this, SLOT( slotChildStarted( KIO::Job *) ) ); 04540 connect( part, SIGNAL( completed() ), 04541 this, SLOT( slotChildCompleted() ) ); 04542 connect( part, SIGNAL( completed(bool) ), 04543 this, SLOT( slotChildCompleted(bool) ) ); 04544 connect( part, SIGNAL( setStatusBarText( const QString & ) ), 04545 this, SIGNAL( setStatusBarText( const QString & ) ) ); 04546 if ( part->inherits( "KHTMLPart" ) ) 04547 { 04548 connect( this, SIGNAL( completed() ), 04549 part, SLOT( slotParentCompleted() ) ); 04550 connect( this, SIGNAL( completed(bool) ), 04551 part, SLOT( slotParentCompleted() ) ); 04552 // As soon as the child's document is created, we need to set its domain 04553 // (but we do so only once, so it can't be simply done in the child) 04554 connect( part, SIGNAL( docCreated() ), 04555 this, SLOT( slotChildDocCreated() ) ); 04556 } 04557 04558 child->m_extension = KParts::BrowserExtension::childObject( part ); 04559 04560 if ( KParts::BrowserExtension* kidBrowserExt = child->m_extension.data() ) 04561 { 04562 connect( kidBrowserExt, SIGNAL( openUrlNotify() ), 04563 d->m_extension, SIGNAL( openUrlNotify() ) ); 04564 04565 connect( kidBrowserExt, SIGNAL( openUrlRequestDelayed( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments & ) ), 04566 this, SLOT( slotChildURLRequest( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments & ) ) ); 04567 04568 connect( kidBrowserExt, SIGNAL( createNewWindow( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments &, const KParts::WindowArgs &, KParts::ReadOnlyPart ** ) ), 04569 d->m_extension, SIGNAL( createNewWindow( const KUrl &, const KParts::OpenUrlArguments&, const KParts::BrowserArguments & , const KParts::WindowArgs &, KParts::ReadOnlyPart **) ) ); 04570 04571 connect( kidBrowserExt, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), 04572 d->m_extension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) ); 04573 connect( kidBrowserExt, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), 04574 d->m_extension, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) ); 04575 04576 connect( kidBrowserExt, SIGNAL( infoMessage( const QString & ) ), 04577 d->m_extension, SIGNAL( infoMessage( const QString & ) ) ); 04578 04579 connect( kidBrowserExt, SIGNAL( requestFocus( KParts::ReadOnlyPart * ) ), 04580 this, SLOT( slotRequestFocus( KParts::ReadOnlyPart * ) ) ); 04581 04582 kidBrowserExt->setBrowserInterface( d->m_extension->browserInterface() ); 04583 } 04584 } 04585 04586 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget, 04587 QObject *parent, const QString &mimetype, 04588 QString &serviceName, QStringList &serviceTypes, 04589 const QStringList ¶ms ) 04590 { 04591 QString constr; 04592 if ( !serviceName.isEmpty() ) 04593 constr.append( QString::fromLatin1( "DesktopEntryName == '%1'" ).arg( serviceName ) ); 04594 04595 KService::List offers = KMimeTypeTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr ); 04596 04597 if ( offers.isEmpty() ) { 04598 int pos = mimetype.indexOf( "-plugin" ); 04599 if (pos < 0) 04600 return 0L; 04601 QString stripped_mime = mimetype.left( pos ); 04602 offers = KMimeTypeTrader::self()->query( stripped_mime, "KParts/ReadOnlyPart", constr ); 04603 if ( offers.isEmpty() ) 04604 return 0L; 04605 } 04606 04607 KService::List::ConstIterator it = offers.constBegin(); 04608 const KService::List::ConstIterator itEnd = offers.constEnd(); 04609 for ( ; it != itEnd; ++it ) 04610 { 04611 KService::Ptr service = (*it); 04612 04613 KPluginLoader loader( *service, KHTMLGlobal::componentData() ); 04614 KPluginFactory* const factory = loader.factory(); 04615 if ( factory ) { 04616 // Turn params into a QVariantList as expected by KPluginFactory 04617 QVariantList variantlist; 04618 Q_FOREACH(const QString& str, params) 04619 variantlist << QVariant(str); 04620 04621 if ( service->serviceTypes().contains( "Browser/View" ) ) 04622 variantlist << QString("Browser/View"); 04623 04624 KParts::ReadOnlyPart* part = factory->create<KParts::ReadOnlyPart>(parentWidget, parent, QString(), variantlist); 04625 if ( part ) { 04626 serviceTypes = service->serviceTypes(); 04627 serviceName = service->name(); 04628 return part; 04629 } 04630 } else { 04631 // TODO KMessageBox::error and i18n, like in KonqFactory::createView? 04632 kWarning() << QString("There was an error loading the module %1.\nThe diagnostics is:\n%2") 04633 .arg(service->name()).arg(loader.errorString()); 04634 } 04635 } 04636 return 0; 04637 } 04638 04639 KParts::PartManager *KHTMLPart::partManager() 04640 { 04641 if ( !d->m_manager && d->m_view ) 04642 { 04643 d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this ); 04644 d->m_manager->setObjectName( "khtml part manager" ); 04645 d->m_manager->setAllowNestedParts( true ); 04646 connect( d->m_manager, SIGNAL( activePartChanged( KParts::Part * ) ), 04647 this, SLOT( slotActiveFrameChanged( KParts::Part * ) ) ); 04648 connect( d->m_manager, SIGNAL( partRemoved( KParts::Part * ) ), 04649 this, SLOT( slotPartRemoved( KParts::Part * ) ) ); 04650 } 04651 04652 return d->m_manager; 04653 } 04654 04655 void KHTMLPart::submitFormAgain() 04656 { 04657 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain())); 04658 if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm) 04659 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 ); 04660 04661 delete d->m_submitForm; 04662 d->m_submitForm = 0; 04663 } 04664 04665 void KHTMLPart::submitFormProxy( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary ) 04666 { 04667 submitForm(action, url, formData, _target, contentType, boundary); 04668 } 04669 04670 void KHTMLPart::submitForm( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary ) 04671 { 04672 kDebug(6000) << this << "target=" << _target << "url=" << url; 04673 if (d->m_formNotification == KHTMLPart::Only) { 04674 emit formSubmitNotification(action, url, formData, _target, contentType, boundary); 04675 return; 04676 } else if (d->m_formNotification == KHTMLPart::Before) { 04677 emit formSubmitNotification(action, url, formData, _target, contentType, boundary); 04678 } 04679 04680 KUrl u = completeURL( url ); 04681 04682 if ( !u.isValid() ) 04683 { 04684 // ### ERROR HANDLING! 04685 return; 04686 } 04687 04688 // Form security checks 04689 // 04690 /* 04691 * If these form security checks are still in this place in a month or two 04692 * I'm going to simply delete them. 04693 */ 04694 04695 /* This is separate for a reason. It has to be _before_ all script, etc, 04696 * AND I don't want to break anything that uses checkLinkSecurity() in 04697 * other places. 04698 */ 04699 04700 if (!d->m_submitForm) { 04701 if (u.protocol() != "https" && u.protocol() != "mailto") { 04702 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL 04703 int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted." 04704 "\nA third party may be able to intercept and view this information." 04705 "\nAre you sure you wish to continue?"), 04706 i18n("Network Transmission"),KGuiItem(i18n("&Send Unencrypted"))); 04707 if (rc == KMessageBox::Cancel) 04708 return; 04709 } else { // Going from nonSSL -> nonSSL 04710 KSSLSettings kss(true); 04711 if (kss.warnOnUnencrypted()) { 04712 int rc = KMessageBox::warningContinueCancel(NULL, 04713 i18n("Warning: Your data is about to be transmitted across the network unencrypted." 04714 "\nAre you sure you wish to continue?"), 04715 i18n("Network Transmission"), 04716 KGuiItem(i18n("&Send Unencrypted")), 04717 KStandardGuiItem::cancel(), 04718 "WarnOnUnencryptedForm"); 04719 // Move this setting into KSSL instead 04720 QString grpNotifMsgs = QLatin1String("Notification Messages"); 04721 KConfigGroup cg( KGlobal::config(), grpNotifMsgs ); 04722 04723 if (!cg.readEntry("WarnOnUnencryptedForm", true)) { 04724 cg.deleteEntry("WarnOnUnencryptedForm"); 04725 cg.sync(); 04726 kss.setWarnOnUnencrypted(false); 04727 kss.save(); 04728 } 04729 if (rc == KMessageBox::Cancel) 04730 return; 04731 } 04732 } 04733 } 04734 04735 if (u.protocol() == "mailto") { 04736 int rc = KMessageBox::warningContinueCancel(NULL, 04737 i18n("This site is attempting to submit form data via email.\n" 04738 "Do you want to continue?"), 04739 i18n("Network Transmission"), 04740 KGuiItem(i18n("&Send Email")), 04741 KStandardGuiItem::cancel(), 04742 "WarnTriedEmailSubmit"); 04743 04744 if (rc == KMessageBox::Cancel) { 04745 return; 04746 } 04747 } 04748 } 04749 04750 // End form security checks 04751 // 04752 04753 QString urlstring = u.url(); 04754 04755 if ( d->isJavaScriptURL(urlstring) ) { 04756 crossFrameExecuteScript( _target, d->codeForJavaScriptURL(urlstring) ); 04757 return; 04758 } 04759 04760 if (!checkLinkSecurity(u, 04761 ki18n( "<qt>The form will be submitted to <br /><b>%1</b><br />on your local filesystem.<br />Do you want to submit the form?</qt>" ), 04762 i18n( "Submit" ))) 04763 return; 04764 04765 // OK. We're actually going to submit stuff. Clear any redirections, 04766 // we should win over them 04767 d->clearRedirection(); 04768 04769 KParts::OpenUrlArguments args; 04770 04771 if (!d->m_referrer.isEmpty()) 04772 args.metaData()["referrer"] = d->m_referrer; 04773 04774 args.metaData().insert("PropagateHttpHeader", "true"); 04775 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip); 04776 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert); 04777 args.metaData().insert("main_frame_request", 04778 parentPart() == 0 ? "TRUE":"FALSE"); 04779 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE"); 04780 args.metaData().insert("ssl_activate_warnings", "TRUE"); 04781 //WABA: When we post a form we should treat it as the main url 04782 //the request should never be considered cross-domain 04783 //args.metaData().insert("cross-domain", toplevelURL().url()); 04784 KParts::BrowserArguments browserArgs; 04785 browserArgs.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ; 04786 04787 // Handle mailto: forms 04788 if (u.protocol() == "mailto") { 04789 // 1) Check for attach= and strip it 04790 QString q = u.query().mid(1); 04791 QStringList nvps = q.split("&"); 04792 bool triedToAttach = false; 04793 04794 QStringList::Iterator nvp = nvps.begin(); 04795 const QStringList::Iterator nvpEnd = nvps.end(); 04796 04797 // cannot be a for loop as if something is removed we don't want to do ++nvp, as 04798 // remove returns an iterator pointing to the next item 04799 04800 while (nvp != nvpEnd) { 04801 const QStringList pair = (*nvp).split("="); 04802 if (pair.count() >= 2) { 04803 if (pair.first().toLower() == "attach") { 04804 nvp = nvps.erase(nvp); 04805 triedToAttach = true; 04806 } else { 04807 ++nvp; 04808 } 04809 } else { 04810 ++nvp; 04811 } 04812 } 04813 04814 if (triedToAttach) 04815 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"); 04816 04817 // 2) Append body= 04818 QString bodyEnc; 04819 if (contentType.toLower() == "multipart/form-data") { 04820 // FIXME: is this correct? I suspect not 04821 bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(), 04822 formData.size()))); 04823 } else if (contentType.toLower() == "text/plain") { 04824 // Convention seems to be to decode, and s/&/\n/ 04825 QString tmpbody = QString::fromLatin1(formData.data(), 04826 formData.size()); 04827 tmpbody.replace(QRegExp("[&]"), "\n"); 04828 tmpbody.replace(QRegExp("[+]"), " "); 04829 tmpbody = KUrl::fromPercentEncoding(tmpbody.toLatin1()); // Decode the rest of it 04830 bodyEnc = QLatin1String( KUrl::toPercentEncoding(tmpbody) ); // Recode for the URL 04831 } else { 04832 bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(), 04833 formData.size())) ); 04834 } 04835 04836 nvps.append(QString("body=%1").arg(bodyEnc)); 04837 q = nvps.join("&"); 04838 u.setQuery(q); 04839 } 04840 04841 if ( strcmp( action, "get" ) == 0 ) { 04842 if (u.protocol() != "mailto") 04843 u.setQuery( QString::fromLatin1( formData.data(), formData.size() ) ); 04844 browserArgs.setDoPost( false ); 04845 } 04846 else { 04847 browserArgs.postData = formData; 04848 browserArgs.setDoPost( true ); 04849 04850 // construct some user headers if necessary 04851 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded") 04852 browserArgs.setContentType( "Content-Type: application/x-www-form-urlencoded" ); 04853 else // contentType must be "multipart/form-data" 04854 browserArgs.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary ); 04855 } 04856 04857 if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) { 04858 if( d->m_submitForm ) { 04859 kDebug(6000) << "ABORTING!"; 04860 return; 04861 } 04862 d->m_submitForm = new KHTMLPartPrivate::SubmitForm; 04863 d->m_submitForm->submitAction = action; 04864 d->m_submitForm->submitUrl = url; 04865 d->m_submitForm->submitFormData = formData; 04866 d->m_submitForm->target = _target; 04867 d->m_submitForm->submitContentType = contentType; 04868 d->m_submitForm->submitBoundary = boundary; 04869 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain())); 04870 } 04871 else 04872 { 04873 emit d->m_extension->openUrlRequest( u, args, browserArgs ); 04874 } 04875 } 04876 04877 void KHTMLPart::popupMenu( const QString &linkUrl ) 04878 { 04879 KUrl popupURL; 04880 KUrl linkKUrl; 04881 KParts::OpenUrlArguments args; 04882 KParts::BrowserArguments browserArgs; 04883 QString referrer; 04884 KParts::BrowserExtension::PopupFlags itemflags=KParts::BrowserExtension::ShowBookmark | KParts::BrowserExtension::ShowReload; 04885 04886 if ( linkUrl.isEmpty() ) { // click on background 04887 KHTMLPart* khtmlPart = this; 04888 while ( khtmlPart->parentPart() ) 04889 { 04890 khtmlPart=khtmlPart->parentPart(); 04891 } 04892 popupURL = khtmlPart->url(); 04893 referrer = khtmlPart->pageReferrer(); 04894 if (hasSelection()) 04895 itemflags = KParts::BrowserExtension::ShowTextSelectionItems; 04896 else 04897 itemflags |= KParts::BrowserExtension::ShowNavigationItems; 04898 } else { // click on link 04899 popupURL = completeURL( linkUrl ); 04900 linkKUrl = popupURL; 04901 referrer = this->referrer(); 04902 itemflags |= KParts::BrowserExtension::IsLink; 04903 04904 if (!(d->m_strSelectedURLTarget).isEmpty() && 04905 (d->m_strSelectedURLTarget.toLower() != "_top") && 04906 (d->m_strSelectedURLTarget.toLower() != "_self") && 04907 (d->m_strSelectedURLTarget.toLower() != "_parent")) { 04908 if (d->m_strSelectedURLTarget.toLower() == "_blank") 04909 browserArgs.setForcesNewWindow(true); 04910 else { 04911 KHTMLPart *p = this; 04912 while (p->parentPart()) 04913 p = p->parentPart(); 04914 if (!p->frameExists(d->m_strSelectedURLTarget)) 04915 browserArgs.setForcesNewWindow(true); 04916 } 04917 } 04918 } 04919 04920 // Danger, Will Robinson. The Popup might stay around for a much 04921 // longer time than KHTMLPart. Deal with it. 04922 KHTMLPopupGUIClient* client = new KHTMLPopupGUIClient( this, linkKUrl ); 04923 QPointer<QObject> guard( client ); 04924 04925 QString mimetype = QLatin1String( "text/html" ); 04926 args.metaData()["referrer"] = referrer; 04927 04928 if (!linkUrl.isEmpty()) // over a link 04929 { 04930 if (popupURL.isLocalFile()) // safe to do this 04931 { 04932 mimetype = KMimeType::findByUrl(popupURL,0,true,false)->name(); 04933 } 04934 else // look at "extension" of link 04935 { 04936 const QString fname(popupURL.fileName(KUrl::ObeyTrailingSlash)); 04937 if (!fname.isEmpty() && !popupURL.hasRef() && popupURL.query().isEmpty()) 04938 { 04939 KMimeType::Ptr pmt = KMimeType::findByPath(fname,0,true); 04940 04941 // Further check for mime types guessed from the extension which, 04942 // on a web page, are more likely to be a script delivering content 04943 // of undecidable type. If the mime type from the extension is one 04944 // of these, don't use it. Retain the original type 'text/html'. 04945 if (pmt->name() != KMimeType::defaultMimeType() && 04946 !pmt->is("application/x-perl") && 04947 !pmt->is("application/x-perl-module") && 04948 !pmt->is("application/x-php") && 04949 !pmt->is("application/x-python-bytecode") && 04950 !pmt->is("application/x-python") && 04951 !pmt->is("application/x-shellscript")) 04952 mimetype = pmt->name(); 04953 } 04954 } 04955 } 04956 04957 args.setMimeType(mimetype); 04958 04959 emit d->m_extension->popupMenu( QCursor::pos(), popupURL, S_IFREG /*always a file*/, 04960 args, browserArgs, itemflags, 04961 client->actionGroups() ); 04962 04963 if ( !guard.isNull() ) { 04964 delete client; 04965 emit popupMenu(linkUrl, QCursor::pos()); 04966 d->m_strSelectedURL.clear(); 04967 d->m_strSelectedURLTarget.clear(); 04968 } 04969 } 04970 04971 void KHTMLPart::slotParentCompleted() 04972 { 04973 //kDebug(6050) << this; 04974 if ( !d->m_redirectURL.isEmpty() && !d->m_redirectionTimer.isActive() ) 04975 { 04976 //kDebug(6050) << this << ": starting timer for child redirection -> " << d->m_redirectURL; 04977 d->m_redirectionTimer.setSingleShot( true ); 04978 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) ); 04979 } 04980 } 04981 04982 void KHTMLPart::slotChildStarted( KIO::Job *job ) 04983 { 04984 khtml::ChildFrame *child = frame( sender() ); 04985 04986 assert( child ); 04987 04988 child->m_bCompleted = false; 04989 04990 if ( d->m_bComplete ) 04991 { 04992 #if 0 04993 // WABA: Looks like this belongs somewhere else 04994 if ( !parentPart() ) // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes 04995 { 04996 emit d->m_extension->openURLNotify(); 04997 } 04998 #endif 04999 d->m_bComplete = false; 05000 emit started( job ); 05001 } 05002 } 05003 05004 void KHTMLPart::slotChildCompleted() 05005 { 05006 slotChildCompleted( false ); 05007 } 05008 05009 void KHTMLPart::slotChildCompleted( bool pendingAction ) 05010 { 05011 khtml::ChildFrame *child = frame( sender() ); 05012 05013 if ( child ) { 05014 kDebug(6031) << this << "child=" << child << "m_partContainerElement=" << child->m_partContainerElement; 05015 child->m_bCompleted = true; 05016 child->m_bPendingRedirection = pendingAction; 05017 child->m_args = KParts::OpenUrlArguments(); 05018 child->m_browserArgs = KParts::BrowserArguments(); 05019 // dispatch load event. We don't do that for KHTMLPart's since their internal 05020 // load will be forwarded inside NodeImpl::dispatchWindowEvent 05021 if (!qobject_cast<KHTMLPart*>(child->m_part)) 05022 QTimer::singleShot(0, child->m_partContainerElement.data(), SLOT(slotEmitLoadEvent())); 05023 } 05024 checkCompleted(); 05025 } 05026 05027 void KHTMLPart::slotChildDocCreated() 05028 { 05029 // Set domain to the frameset's domain 05030 // This must only be done when loading the frameset initially (#22039), 05031 // not when following a link in a frame (#44162). 05032 if (KHTMLPart* htmlFrame = qobject_cast<KHTMLPart*>(sender())) 05033 d->propagateInitialDomainAndBaseTo(htmlFrame); 05034 05035 // So it only happens once 05036 disconnect( sender(), SIGNAL( docCreated() ), this, SLOT( slotChildDocCreated() ) ); 05037 } 05038 05039 void KHTMLPartPrivate::propagateInitialDomainAndBaseTo(KHTMLPart* kid) 05040 { 05041 // This method is used to propagate our domain and base information for 05042 // child frames, to provide them for about: or JavaScript: URLs 05043 if ( m_doc && kid->d->m_doc ) { 05044 DocumentImpl* kidDoc = kid->d->m_doc; 05045 if ( kidDoc->origin()->isEmpty() ) { 05046 kidDoc->setOrigin ( m_doc->origin() ); 05047 kidDoc->setBaseURL( m_doc->baseURL() ); 05048 } 05049 } 05050 } 05051 05052 void KHTMLPart::slotChildURLRequest( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs ) 05053 { 05054 khtml::ChildFrame *child = frame( sender()->parent() ); 05055 KHTMLPart *callingHtmlPart = const_cast<KHTMLPart *>(dynamic_cast<const KHTMLPart *>(sender()->parent())); 05056 05057 // TODO: handle child target correctly! currently the script are always executed for the parent 05058 QString urlStr = url.url(); 05059 if ( d->isJavaScriptURL(urlStr) ) { 05060 executeScript( DOM::Node(), d->codeForJavaScriptURL(urlStr) ); 05061 return; 05062 } 05063 05064 QString frameName = browserArgs.frameName.toLower(); 05065 if ( !frameName.isEmpty() ) { 05066 if ( frameName == QLatin1String( "_top" ) ) 05067 { 05068 emit d->m_extension->openUrlRequest( url, args, browserArgs ); 05069 return; 05070 } 05071 else if ( frameName == QLatin1String( "_blank" ) ) 05072 { 05073 emit d->m_extension->createNewWindow( url, args, browserArgs ); 05074 return; 05075 } 05076 else if ( frameName == QLatin1String( "_parent" ) ) 05077 { 05078 KParts::BrowserArguments newBrowserArgs( browserArgs ); 05079 newBrowserArgs.frameName.clear(); 05080 emit d->m_extension->openUrlRequest( url, args, newBrowserArgs ); 05081 return; 05082 } 05083 else if ( frameName != QLatin1String( "_self" ) ) 05084 { 05085 khtml::ChildFrame *_frame = recursiveFrameRequest( callingHtmlPart, url, args, browserArgs ); 05086 05087 if ( !_frame ) 05088 { 05089 emit d->m_extension->openUrlRequest( url, args, browserArgs ); 05090 return; 05091 } 05092 05093 child = _frame; 05094 } 05095 } 05096 05097 if ( child && child->m_type != khtml::ChildFrame::Object ) { 05098 // Inform someone that we are about to show something else. 05099 child->m_bNotify = true; 05100 requestObject( child, url, args, browserArgs ); 05101 } else if ( frameName== "_self" ) // this is for embedded objects (via <object>) which want to replace the current document 05102 { 05103 KParts::BrowserArguments newBrowserArgs( browserArgs ); 05104 newBrowserArgs.frameName.clear(); 05105 emit d->m_extension->openUrlRequest( url, args, newBrowserArgs ); 05106 } 05107 } 05108 05109 void KHTMLPart::slotRequestFocus( KParts::ReadOnlyPart * ) 05110 { 05111 emit d->m_extension->requestFocus(this); 05112 } 05113 05114 khtml::ChildFrame *KHTMLPart::frame( const QObject *obj ) 05115 { 05116 assert( obj->inherits( "KParts::ReadOnlyPart" ) ); 05117 const KParts::ReadOnlyPart* const part = static_cast<const KParts::ReadOnlyPart *>( obj ); 05118 05119 FrameIt it = d->m_frames.begin(); 05120 const FrameIt end = d->m_frames.end(); 05121 for (; it != end; ++it ) { 05122 if ((*it)->m_part.data() == part ) 05123 return *it; 05124 } 05125 05126 FrameIt oi = d->m_objects.begin(); 05127 const FrameIt oiEnd = d->m_objects.end(); 05128 for (; oi != oiEnd; ++oi ) { 05129 if ((*oi)->m_part.data() == part) 05130 return *oi; 05131 } 05132 05133 return 0L; 05134 } 05135 05136 //#define DEBUG_FINDFRAME 05137 05138 bool KHTMLPart::checkFrameAccess(KHTMLPart *callingHtmlPart) 05139 { 05140 if (callingHtmlPart == this) 05141 return true; // trivial 05142 05143 if (!xmlDocImpl()) { 05144 #ifdef DEBUG_FINDFRAME 05145 kDebug(6050) << "Empty part" << this << "URL = " << url(); 05146 #endif 05147 return false; // we are empty? 05148 } 05149 05150 // now compare the domains 05151 if (callingHtmlPart && callingHtmlPart->xmlDocImpl() && xmlDocImpl()) { 05152 khtml::SecurityOrigin* actDomain = callingHtmlPart->xmlDocImpl()->origin(); 05153 khtml::SecurityOrigin* destDomain = xmlDocImpl()->origin(); 05154 05155 if (actDomain->canAccess(destDomain)) 05156 return true; 05157 } 05158 #ifdef DEBUG_FINDFRAME 05159 else 05160 { 05161 kDebug(6050) << "Unknown part/domain" << callingHtmlPart << "tries to access part" << this; 05162 } 05163 #endif 05164 return false; 05165 } 05166 05167 KHTMLPart * 05168 KHTMLPart::findFrameParent( KParts::ReadOnlyPart *callingPart, const QString &f, khtml::ChildFrame **childFrame ) 05169 { 05170 return d->findFrameParent(callingPart, f, childFrame, false); 05171 } 05172 05173 KHTMLPart* KHTMLPartPrivate::findFrameParent(KParts::ReadOnlyPart* callingPart, 05174 const QString& f, khtml::ChildFrame **childFrame, bool checkForNavigation) 05175 { 05176 #ifdef DEBUG_FINDFRAME 05177 kDebug(6050) << q << "URL =" << q->url() << "name =" << q->objectName() << "findFrameParent(" << f << ")"; 05178 #endif 05179 // Check access 05180 KHTMLPart* const callingHtmlPart = dynamic_cast<KHTMLPart *>(callingPart); 05181 05182 if (!checkForNavigation && !q->checkFrameAccess(callingHtmlPart)) 05183 return 0; 05184 05185 if (!childFrame && !q->parentPart() && (q->objectName() == f)) { 05186 if (!checkForNavigation || callingHtmlPart->d->canNavigate(q)) 05187 return q; 05188 } 05189 05190 FrameIt it = m_frames.find( f ); 05191 const FrameIt end = m_frames.end(); 05192 if ( it != end ) 05193 { 05194 #ifdef DEBUG_FINDFRAME 05195 kDebug(6050) << "FOUND!"; 05196 #endif 05197 if (!checkForNavigation || callingHtmlPart->d->canNavigate((*it)->m_part.data())) { 05198 if (childFrame) 05199 *childFrame = *it; 05200 return q; 05201 } 05202 } 05203 05204 it = m_frames.begin(); 05205 for (; it != end; ++it ) 05206 { 05207 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) ) 05208 { 05209 KHTMLPart* const frameParent = p->d->findFrameParent(callingPart, f, childFrame, checkForNavigation); 05210 if (frameParent) 05211 return frameParent; 05212 } 05213 } 05214 return 0; 05215 } 05216 05217 KHTMLPart* KHTMLPartPrivate::top() 05218 { 05219 KHTMLPart* t = q; 05220 while (t->parentPart()) 05221 t = t->parentPart(); 05222 return t; 05223 } 05224 05225 bool KHTMLPartPrivate::canNavigate(KParts::ReadOnlyPart* bCand) 05226 { 05227 KHTMLPart* b = qobject_cast<KHTMLPart*>(bCand); 05228 assert(b); 05229 05230 // HTML5 gives conditions for this (a) being able to navigate b 05231 05232 // 1) Same domain 05233 if (q->checkFrameAccess(b)) 05234 return true; 05235 05236 // 2) A is nested, with B its top 05237 if (q->parentPart() && top() == b) 05238 return true; 05239 05240 // 3) B is 'auxilary' -- window.open with opener, 05241 // and A can navigate B's opener 05242 if (b->opener() && canNavigate(b->opener())) 05243 return true; 05244 05245 // 4) B is not top-level, but an ancestor of it has same origin as A 05246 for (KHTMLPart* anc = b->parentPart(); anc; anc = anc->parentPart()) { 05247 if (anc->checkFrameAccess(q)) 05248 return true; 05249 } 05250 05251 return false; 05252 } 05253 05254 KHTMLPart *KHTMLPart::findFrame( const QString &f ) 05255 { 05256 khtml::ChildFrame *childFrame; 05257 KHTMLPart *parentFrame = findFrameParent(this, f, &childFrame); 05258 if (parentFrame) 05259 return qobject_cast<KHTMLPart*>(childFrame->m_part.data()); 05260 05261 return 0; 05262 } 05263 05264 KParts::ReadOnlyPart *KHTMLPart::findFramePart(const QString &f) 05265 { 05266 khtml::ChildFrame *childFrame; 05267 return findFrameParent(this, f, &childFrame) ? childFrame->m_part.data() : 0L; 05268 } 05269 05270 KParts::ReadOnlyPart *KHTMLPart::currentFrame() const 05271 { 05272 KParts::ReadOnlyPart* part = (KParts::ReadOnlyPart*)(this); 05273 // Find active part in our frame manager, in case we are a frameset 05274 // and keep doing that (in case of nested framesets). 05275 // Just realized we could also do this recursively, calling part->currentFrame()... 05276 while ( part && part->inherits("KHTMLPart") && 05277 static_cast<KHTMLPart *>(part)->d->m_frames.count() > 0 ) { 05278 KHTMLPart* frameset = static_cast<KHTMLPart *>(part); 05279 part = static_cast<KParts::ReadOnlyPart *>(frameset->partManager()->activePart()); 05280 if ( !part ) return frameset; 05281 } 05282 return part; 05283 } 05284 05285 bool KHTMLPart::frameExists( const QString &frameName ) 05286 { 05287 FrameIt it = d->m_frames.find( frameName ); 05288 if ( it == d->m_frames.end() ) 05289 return false; 05290 05291 // WABA: We only return true if the child actually has a frame 05292 // set. Otherwise we might find our preloaded-selve. 05293 // This happens when we restore the frameset. 05294 return (!(*it)->m_partContainerElement.isNull()); 05295 } 05296 05297 void KHTMLPartPrivate::renameFrameForContainer(DOM::HTMLPartContainerElementImpl* cont, 05298 const QString& newName) 05299 { 05300 for (int i = 0; i < m_frames.size(); ++i) { 05301 khtml::ChildFrame* f = m_frames[i]; 05302 if (f->m_partContainerElement.data() == cont) 05303 f->m_name = newName; 05304 } 05305 } 05306 05307 KJSProxy *KHTMLPart::framejScript(KParts::ReadOnlyPart *framePart) 05308 { 05309 KHTMLPart* const kp = qobject_cast<KHTMLPart*>(framePart); 05310 if (kp) 05311 return kp->jScript(); 05312 05313 FrameIt it = d->m_frames.begin(); 05314 const FrameIt itEnd = d->m_frames.end(); 05315 05316 for (; it != itEnd; ++it) { 05317 khtml::ChildFrame* frame = *it; 05318 if (framePart == frame->m_part.data()) { 05319 if (!frame->m_jscript) 05320 frame->m_jscript = new KJSProxy(frame); 05321 return frame->m_jscript; 05322 } 05323 } 05324 return 0L; 05325 } 05326 05327 KHTMLPart *KHTMLPart::parentPart() 05328 { 05329 return qobject_cast<KHTMLPart*>( parent() ); 05330 } 05331 05332 khtml::ChildFrame *KHTMLPart::recursiveFrameRequest( KHTMLPart *callingHtmlPart, const KUrl &url, 05333 const KParts::OpenUrlArguments &args, 05334 const KParts::BrowserArguments &browserArgs, bool callParent ) 05335 { 05336 #ifdef DEBUG_FINDFRAME 05337 kDebug( 6050 ) << this << "frame = " << args.frameName << "url = " << url; 05338 #endif 05339 khtml::ChildFrame *childFrame; 05340 KHTMLPart *childPart = findFrameParent(callingHtmlPart, browserArgs.frameName, &childFrame); 05341 if (childPart) 05342 { 05343 if (childPart == this) 05344 return childFrame; 05345 05346 childPart->requestObject( childFrame, url, args, browserArgs ); 05347 return 0; 05348 } 05349 05350 if ( parentPart() && callParent ) 05351 { 05352 khtml::ChildFrame *res = parentPart()->recursiveFrameRequest( callingHtmlPart, url, args, browserArgs, callParent ); 05353 05354 if ( res ) 05355 parentPart()->requestObject( res, url, args, browserArgs ); 05356 } 05357 05358 return 0L; 05359 } 05360 05361 #ifdef DEBUG_SAVESTATE 05362 static int s_saveStateIndentLevel = 0; 05363 #endif 05364 05365 void KHTMLPart::saveState( QDataStream &stream ) 05366 { 05367 #ifdef DEBUG_SAVESTATE 05368 QString indent= QString().leftJustified( s_saveStateIndentLevel * 4, ' ' ); 05369 const int indentLevel = s_saveStateIndentLevel++; 05370 kDebug( 6050 ) << indent << "saveState this=" << this << " '" << objectName() << "' saving URL " << url().url(); 05371 #endif 05372 05373 stream << url() << (qint32)d->m_view->contentsX() << (qint32)d->m_view->contentsY() 05374 << (qint32) d->m_view->contentsWidth() << (qint32) d->m_view->contentsHeight() << (qint32) d->m_view->marginWidth() << (qint32) d->m_view->marginHeight(); 05375 05376 // save link cursor position 05377 int focusNodeNumber; 05378 if (!d->m_focusNodeRestored) 05379 focusNodeNumber = d->m_focusNodeNumber; 05380 else if (d->m_doc && d->m_doc->focusNode()) 05381 focusNodeNumber = d->m_doc->nodeAbsIndex(d->m_doc->focusNode()); 05382 else 05383 focusNodeNumber = -1; 05384 stream << focusNodeNumber; 05385 05386 // Save the doc's cache id. 05387 stream << d->m_cacheId; 05388 05389 // Save the state of the document (Most notably the state of any forms) 05390 QStringList docState; 05391 if (d->m_doc) 05392 { 05393 docState = d->m_doc->docState(); 05394 } 05395 stream << d->m_encoding << d->m_sheetUsed << docState; 05396 05397 stream << d->m_zoomFactor; 05398 stream << d->m_fontScaleFactor; 05399 05400 stream << d->m_httpHeaders; 05401 stream << d->m_pageServices; 05402 stream << d->m_pageReferrer; 05403 05404 // Save ssl data 05405 stream << d->m_ssl_in_use 05406 << d->m_ssl_peer_chain 05407 << d->m_ssl_peer_ip 05408 << d->m_ssl_cipher 05409 << d->m_ssl_protocol_version 05410 << d->m_ssl_cipher_used_bits 05411 << d->m_ssl_cipher_bits 05412 << d->m_ssl_cert_errors 05413 << d->m_ssl_parent_ip 05414 << d->m_ssl_parent_cert; 05415 05416 05417 QStringList frameNameLst, frameServiceTypeLst, frameServiceNameLst; 05418 KUrl::List frameURLLst; 05419 QList<QByteArray> frameStateBufferLst; 05420 QList<int> frameTypeLst; 05421 05422 ConstFrameIt it = d->m_frames.constBegin(); 05423 const ConstFrameIt end = d->m_frames.constEnd(); 05424 for (; it != end; ++it ) 05425 { 05426 if ( !(*it)->m_part ) 05427 continue; 05428 05429 frameNameLst << (*it)->m_name; 05430 frameServiceTypeLst << (*it)->m_serviceType; 05431 frameServiceNameLst << (*it)->m_serviceName; 05432 frameURLLst << (*it)->m_part.data()->url(); 05433 05434 QByteArray state; 05435 QDataStream frameStream( &state, QIODevice::WriteOnly ); 05436 05437 if ( (*it)->m_extension ) 05438 (*it)->m_extension.data()->saveState( frameStream ); 05439 05440 frameStateBufferLst << state; 05441 05442 frameTypeLst << int( (*it)->m_type ); 05443 } 05444 05445 // Save frame data 05446 stream << (quint32) frameNameLst.count(); 05447 stream << frameNameLst << frameServiceTypeLst << frameServiceNameLst << frameURLLst << frameStateBufferLst << frameTypeLst; 05448 #ifdef DEBUG_SAVESTATE 05449 s_saveStateIndentLevel = indentLevel; 05450 #endif 05451 } 05452 05453 void KHTMLPart::restoreState( QDataStream &stream ) 05454 { 05455 KUrl u; 05456 qint32 xOffset, yOffset, wContents, hContents, mWidth, mHeight; 05457 quint32 frameCount; 05458 QStringList frameNames, frameServiceTypes, docState, frameServiceNames; 05459 QList<int> frameTypes; 05460 KUrl::List frameURLs; 05461 QList<QByteArray> frameStateBuffers; 05462 QList<int> fSizes; 05463 QString encoding, sheetUsed; 05464 long old_cacheId = d->m_cacheId; 05465 05466 stream >> u >> xOffset >> yOffset >> wContents >> hContents >> mWidth >> mHeight; 05467 05468 d->m_view->setMarginWidth( mWidth ); 05469 d->m_view->setMarginHeight( mHeight ); 05470 05471 // restore link cursor position 05472 // nth node is active. value is set in checkCompleted() 05473 stream >> d->m_focusNodeNumber; 05474 d->m_focusNodeRestored = false; 05475 05476 stream >> d->m_cacheId; 05477 05478 stream >> encoding >> sheetUsed >> docState; 05479 05480 d->m_encoding = encoding; 05481 d->m_sheetUsed = sheetUsed; 05482 05483 int zoomFactor; 05484 stream >> zoomFactor; 05485 setZoomFactor(zoomFactor); 05486 05487 int fontScaleFactor; 05488 stream >> fontScaleFactor; 05489 setFontScaleFactor(fontScaleFactor); 05490 05491 stream >> d->m_httpHeaders; 05492 stream >> d->m_pageServices; 05493 stream >> d->m_pageReferrer; 05494 05495 // Restore ssl data 05496 stream >> d->m_ssl_in_use 05497 >> d->m_ssl_peer_chain 05498 >> d->m_ssl_peer_ip 05499 >> d->m_ssl_cipher 05500 >> d->m_ssl_protocol_version 05501 >> d->m_ssl_cipher_used_bits 05502 >> d->m_ssl_cipher_bits 05503 >> d->m_ssl_cert_errors 05504 >> d->m_ssl_parent_ip 05505 >> d->m_ssl_parent_cert; 05506 05507 setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted ); 05508 05509 stream >> frameCount >> frameNames >> frameServiceTypes >> frameServiceNames 05510 >> frameURLs >> frameStateBuffers >> frameTypes; 05511 05512 d->m_bComplete = false; 05513 d->m_bLoadEventEmitted = false; 05514 05515 // kDebug( 6050 ) << "docState.count() = " << docState.count(); 05516 // kDebug( 6050 ) << "m_url " << url().url() << " <-> " << u.url(); 05517 // kDebug( 6050 ) << "m_frames.count() " << d->m_frames.count() << " <-> " << frameCount; 05518 05519 if (d->m_cacheId == old_cacheId && signed(frameCount) == d->m_frames.count()) 05520 { 05521 // Partial restore 05522 d->m_redirectionTimer.stop(); 05523 05524 FrameIt fIt = d->m_frames.begin(); 05525 const FrameIt fEnd = d->m_frames.end(); 05526 05527 for (; fIt != fEnd; ++fIt ) 05528 (*fIt)->m_bCompleted = false; 05529 05530 fIt = d->m_frames.begin(); 05531 05532 QStringList::ConstIterator fNameIt = frameNames.constBegin(); 05533 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin(); 05534 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin(); 05535 KUrl::List::ConstIterator fURLIt = frameURLs.constBegin(); 05536 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin(); 05537 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin(); 05538 05539 for (; fIt != fEnd; ++fIt, ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt ) 05540 { 05541 khtml::ChildFrame* const child = *fIt; 05542 05543 // kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt; 05544 05545 if ( child->m_name != *fNameIt || child->m_serviceType != *fServiceTypeIt ) 05546 { 05547 child->m_bPreloaded = true; 05548 child->m_name = *fNameIt; 05549 child->m_serviceName = *fServiceNameIt; 05550 child->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt); 05551 processObjectRequest( child, *fURLIt, *fServiceTypeIt ); 05552 } 05553 if ( child->m_part ) 05554 { 05555 child->m_bCompleted = false; 05556 if ( child->m_extension && !(*fBufferIt).isEmpty() ) 05557 { 05558 QDataStream frameStream( *fBufferIt ); 05559 child->m_extension.data()->restoreState( frameStream ); 05560 } 05561 else 05562 child->m_part.data()->openUrl( *fURLIt ); 05563 } 05564 } 05565 05566 KParts::OpenUrlArguments args( arguments() ); 05567 args.setXOffset(xOffset); 05568 args.setYOffset(yOffset); 05569 setArguments(args); 05570 05571 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() ); 05572 browserArgs.docState = docState; 05573 d->m_extension->setBrowserArguments(browserArgs); 05574 05575 d->m_view->resizeContents( wContents, hContents ); 05576 d->m_view->setContentsPos( xOffset, yOffset ); 05577 05578 setUrl(u); 05579 } 05580 else 05581 { 05582 // Full restore. 05583 closeUrl(); 05584 // We must force a clear because we want to be sure to delete all 05585 // frames. 05586 d->m_bCleared = false; 05587 clear(); 05588 d->m_encoding = encoding; 05589 d->m_sheetUsed = sheetUsed; 05590 05591 QStringList::ConstIterator fNameIt = frameNames.constBegin(); 05592 const QStringList::ConstIterator fNameEnd = frameNames.constEnd(); 05593 05594 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin(); 05595 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin(); 05596 KUrl::List::ConstIterator fURLIt = frameURLs.constBegin(); 05597 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin(); 05598 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin(); 05599 05600 for (; fNameIt != fNameEnd; ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt ) 05601 { 05602 khtml::ChildFrame* const newChild = new khtml::ChildFrame; 05603 newChild->m_bPreloaded = true; 05604 newChild->m_name = *fNameIt; 05605 newChild->m_serviceName = *fServiceNameIt; 05606 newChild->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt); 05607 05608 // kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt; 05609 05610 const FrameIt childFrame = d->m_frames.insert( d->m_frames.end(), newChild ); 05611 05612 processObjectRequest( *childFrame, *fURLIt, *fServiceTypeIt ); 05613 05614 (*childFrame)->m_bPreloaded = true; 05615 05616 if ( (*childFrame)->m_part ) 05617 { 05618 if ( (*childFrame)->m_extension && !(*fBufferIt).isEmpty() ) 05619 { 05620 QDataStream frameStream( *fBufferIt ); 05621 (*childFrame)->m_extension.data()->restoreState( frameStream ); 05622 } 05623 else 05624 (*childFrame)->m_part.data()->openUrl( *fURLIt ); 05625 } 05626 } 05627 05628 KParts::OpenUrlArguments args( arguments() ); 05629 args.setXOffset(xOffset); 05630 args.setYOffset(yOffset); 05631 setArguments(args); 05632 05633 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() ); 05634 browserArgs.docState = docState; 05635 d->m_extension->setBrowserArguments(browserArgs); 05636 05637 if (!KHTMLPageCache::self()->isComplete(d->m_cacheId)) 05638 { 05639 d->m_restored = true; 05640 openUrl( u ); 05641 d->m_restored = false; 05642 } 05643 else 05644 { 05645 restoreURL( u ); 05646 } 05647 } 05648 05649 } 05650 05651 void KHTMLPart::show() 05652 { 05653 if ( widget() ) 05654 widget()->show(); 05655 } 05656 05657 void KHTMLPart::hide() 05658 { 05659 if ( widget() ) 05660 widget()->hide(); 05661 } 05662 05663 DOM::Node KHTMLPart::nodeUnderMouse() const 05664 { 05665 return d->m_view->nodeUnderMouse(); 05666 } 05667 05668 DOM::Node KHTMLPart::nonSharedNodeUnderMouse() const 05669 { 05670 return d->m_view->nonSharedNodeUnderMouse(); 05671 } 05672 05673 void KHTMLPart::emitSelectionChanged() 05674 { 05675 // Don't emit signals about our selection if this is a frameset; 05676 // the active frame has the selection (#187403) 05677 if (!d->m_activeFrame) 05678 { 05679 emit d->m_extension->enableAction( "copy", hasSelection() ); 05680 emit d->m_extension->selectionInfo( selectedText() ); 05681 emit selectionChanged(); 05682 } 05683 } 05684 05685 int KHTMLPart::zoomFactor() const 05686 { 05687 return d->m_zoomFactor; 05688 } 05689 05690 // ### make the list configurable ? 05691 static const int zoomSizes[] = { 20, 40, 60, 80, 90, 95, 100, 105, 110, 120, 140, 160, 180, 200, 250, 300 }; 05692 static const int zoomSizeCount = (sizeof(zoomSizes) / sizeof(int)); 05693 static const int minZoom = 20; 05694 static const int maxZoom = 300; 05695 05696 // My idea of useful stepping ;-) (LS) 05697 extern const int KDE_NO_EXPORT fastZoomSizes[] = { 20, 50, 75, 90, 100, 120, 150, 200, 300 }; 05698 extern const int KDE_NO_EXPORT fastZoomSizeCount = sizeof fastZoomSizes / sizeof fastZoomSizes[0]; 05699 05700 void KHTMLPart::slotIncZoom() 05701 { 05702 zoomIn(zoomSizes, zoomSizeCount); 05703 } 05704 05705 void KHTMLPart::slotDecZoom() 05706 { 05707 zoomOut(zoomSizes, zoomSizeCount); 05708 } 05709 05710 void KHTMLPart::slotIncZoomFast() 05711 { 05712 zoomIn(fastZoomSizes, fastZoomSizeCount); 05713 } 05714 05715 void KHTMLPart::slotDecZoomFast() 05716 { 05717 zoomOut(fastZoomSizes, fastZoomSizeCount); 05718 } 05719 05720 void KHTMLPart::zoomIn(const int stepping[], int count) 05721 { 05722 int zoomFactor = d->m_zoomFactor; 05723 05724 if (zoomFactor < maxZoom) { 05725 // find the entry nearest to the given zoomsizes 05726 for (int i = 0; i < count; ++i) 05727 if (stepping[i] > zoomFactor) { 05728 zoomFactor = stepping[i]; 05729 break; 05730 } 05731 setZoomFactor(zoomFactor); 05732 } 05733 } 05734 05735 void KHTMLPart::zoomOut(const int stepping[], int count) 05736 { 05737 int zoomFactor = d->m_zoomFactor; 05738 if (zoomFactor > minZoom) { 05739 // find the entry nearest to the given zoomsizes 05740 for (int i = count-1; i >= 0; --i) 05741 if (stepping[i] < zoomFactor) { 05742 zoomFactor = stepping[i]; 05743 break; 05744 } 05745 setZoomFactor(zoomFactor); 05746 } 05747 } 05748 05749 void KHTMLPart::setZoomFactor (int percent) 05750 { 05751 // ### zooming under 100% is majorly botched, 05752 // so disable that for now. 05753 if (percent < 100) percent = 100; 05754 // ### if (percent < minZoom) percent = minZoom; 05755 05756 if (percent > maxZoom) percent = maxZoom; 05757 if (d->m_zoomFactor == percent) return; 05758 d->m_zoomFactor = percent; 05759 05760 updateZoomFactor(); 05761 } 05762 05763 05764 void KHTMLPart::updateZoomFactor () 05765 { 05766 if(d->m_view) { 05767 QApplication::setOverrideCursor( Qt::WaitCursor ); 05768 d->m_view->setZoomLevel( d->m_zoomFactor ); 05769 QApplication::restoreOverrideCursor(); 05770 } 05771 05772 ConstFrameIt it = d->m_frames.constBegin(); 05773 const ConstFrameIt end = d->m_frames.constEnd(); 05774 for (; it != end; ++it ) { 05775 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) ) 05776 p->setZoomFactor(d->m_zoomFactor); 05777 } 05778 05779 if ( d->m_guiProfile == BrowserViewGUI ) { 05780 d->m_paDecZoomFactor->setEnabled( d->m_zoomFactor > minZoom ); 05781 d->m_paIncZoomFactor->setEnabled( d->m_zoomFactor < maxZoom ); 05782 } 05783 } 05784 05785 void KHTMLPart::slotIncFontSize() 05786 { 05787 incFontSize(zoomSizes, zoomSizeCount); 05788 } 05789 05790 void KHTMLPart::slotDecFontSize() 05791 { 05792 decFontSize(zoomSizes, zoomSizeCount); 05793 } 05794 05795 void KHTMLPart::slotIncFontSizeFast() 05796 { 05797 incFontSize(fastZoomSizes, fastZoomSizeCount); 05798 } 05799 05800 void KHTMLPart::slotDecFontSizeFast() 05801 { 05802 decFontSize(fastZoomSizes, fastZoomSizeCount); 05803 } 05804 05805 void KHTMLPart::incFontSize(const int stepping[], int count) 05806 { 05807 int zoomFactor = d->m_fontScaleFactor; 05808 05809 if (zoomFactor < maxZoom) { 05810 // find the entry nearest to the given zoomsizes 05811 for (int i = 0; i < count; ++i) 05812 if (stepping[i] > zoomFactor) { 05813 zoomFactor = stepping[i]; 05814 break; 05815 } 05816 setFontScaleFactor(zoomFactor); 05817 } 05818 } 05819 05820 void KHTMLPart::decFontSize(const int stepping[], int count) 05821 { 05822 int zoomFactor = d->m_fontScaleFactor; 05823 if (zoomFactor > minZoom) { 05824 // find the entry nearest to the given zoomsizes 05825 for (int i = count-1; i >= 0; --i) 05826 if (stepping[i] < zoomFactor) { 05827 zoomFactor = stepping[i]; 05828 break; 05829 } 05830 setFontScaleFactor(zoomFactor); 05831 } 05832 } 05833 05834 void KHTMLPart::setFontScaleFactor(int percent) 05835 { 05836 if (percent < minZoom) percent = minZoom; 05837 if (percent > maxZoom) percent = maxZoom; 05838 if (d->m_fontScaleFactor == percent) return; 05839 d->m_fontScaleFactor = percent; 05840 05841 if (d->m_view && d->m_doc) { 05842 QApplication::setOverrideCursor( Qt::WaitCursor ); 05843 if (d->m_doc->styleSelector()) 05844 d->m_doc->styleSelector()->computeFontSizes(d->m_doc->logicalDpiY(), d->m_fontScaleFactor); 05845 d->m_doc->recalcStyle( NodeImpl::Force ); 05846 QApplication::restoreOverrideCursor(); 05847 } 05848 05849 ConstFrameIt it = d->m_frames.constBegin(); 05850 const ConstFrameIt end = d->m_frames.constEnd(); 05851 for (; it != end; ++it ) { 05852 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) ) 05853 p->setFontScaleFactor(d->m_fontScaleFactor); 05854 } 05855 } 05856 05857 int KHTMLPart::fontScaleFactor() const 05858 { 05859 return d->m_fontScaleFactor; 05860 } 05861 05862 void KHTMLPart::slotZoomView( int delta ) 05863 { 05864 if ( delta < 0 ) 05865 slotIncZoom(); 05866 else 05867 slotDecZoom(); 05868 } 05869 05870 void KHTMLPart::setStatusBarText( const QString& text, StatusBarPriority p) 05871 { 05872 if (!d->m_statusMessagesEnabled) 05873 return; 05874 05875 d->m_statusBarText[p] = text; 05876 05877 // shift handling ? 05878 QString tobe = d->m_statusBarText[BarHoverText]; 05879 if (tobe.isEmpty()) 05880 tobe = d->m_statusBarText[BarOverrideText]; 05881 if (tobe.isEmpty()) { 05882 tobe = d->m_statusBarText[BarDefaultText]; 05883 if (!tobe.isEmpty() && d->m_jobspeed) 05884 tobe += " "; 05885 if (d->m_jobspeed) 05886 tobe += i18n( "(%1/s)" , KIO::convertSize( d->m_jobspeed ) ); 05887 } 05888 tobe = "<qt>"+tobe; 05889 05890 emit ReadOnlyPart::setStatusBarText(tobe); 05891 } 05892 05893 05894 void KHTMLPart::setJSStatusBarText( const QString &text ) 05895 { 05896 setStatusBarText(text, BarOverrideText); 05897 } 05898 05899 void KHTMLPart::setJSDefaultStatusBarText( const QString &text ) 05900 { 05901 setStatusBarText(text, BarDefaultText); 05902 } 05903 05904 QString KHTMLPart::jsStatusBarText() const 05905 { 05906 return d->m_statusBarText[BarOverrideText]; 05907 } 05908 05909 QString KHTMLPart::jsDefaultStatusBarText() const 05910 { 05911 return d->m_statusBarText[BarDefaultText]; 05912 } 05913 05914 QString KHTMLPart::referrer() const 05915 { 05916 return d->m_referrer; 05917 } 05918 05919 QString KHTMLPart::pageReferrer() const 05920 { 05921 KUrl referrerURL = KUrl( d->m_pageReferrer ); 05922 if (referrerURL.isValid()) 05923 { 05924 QString protocol = referrerURL.protocol(); 05925 05926 if ((protocol == "http") || 05927 ((protocol == "https") && (url().protocol() == "https"))) 05928 { 05929 referrerURL.setRef(QString()); 05930 referrerURL.setUser(QString()); 05931 referrerURL.setPass(QString()); 05932 return referrerURL.url(); 05933 } 05934 } 05935 05936 return QString(); 05937 } 05938 05939 05940 QString KHTMLPart::lastModified() const 05941 { 05942 if ( d->m_lastModified.isEmpty() && url().isLocalFile() ) { 05943 // Local file: set last-modified from the file's mtime. 05944 // Done on demand to save time when this isn't needed - but can lead 05945 // to slightly wrong results if updating the file on disk w/o reloading. 05946 QDateTime lastModif = QFileInfo( url().toLocalFile() ).lastModified(); 05947 d->m_lastModified = lastModif.toString( Qt::LocalDate ); 05948 } 05949 //kDebug(6050) << d->m_lastModified; 05950 return d->m_lastModified; 05951 } 05952 05953 void KHTMLPart::slotLoadImages() 05954 { 05955 if (d->m_doc ) 05956 d->m_doc->docLoader()->setAutoloadImages( !d->m_doc->docLoader()->autoloadImages() ); 05957 05958 ConstFrameIt it = d->m_frames.constBegin(); 05959 const ConstFrameIt end = d->m_frames.constEnd(); 05960 for (; it != end; ++it ) { 05961 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) ) 05962 p->slotLoadImages(); 05963 } 05964 } 05965 05966 void KHTMLPart::reparseConfiguration() 05967 { 05968 KHTMLSettings *settings = KHTMLGlobal::defaultHTMLSettings(); 05969 settings->init(); 05970 05971 setAutoloadImages( settings->autoLoadImages() ); 05972 if (d->m_doc) 05973 d->m_doc->docLoader()->setShowAnimations( settings->showAnimations() ); 05974 05975 d->m_bOpenMiddleClick = settings->isOpenMiddleClickEnabled(); 05976 d->m_bJScriptEnabled = settings->isJavaScriptEnabled(url().host()); 05977 setDebugScript( settings->isJavaScriptDebugEnabled() ); 05978 d->m_bJavaEnabled = settings->isJavaEnabled(url().host()); 05979 d->m_bPluginsEnabled = settings->isPluginsEnabled(url().host()); 05980 d->m_metaRefreshEnabled = settings->isAutoDelayedActionsEnabled (); 05981 05982 delete d->m_settings; 05983 d->m_settings = new KHTMLSettings(*KHTMLGlobal::defaultHTMLSettings()); 05984 05985 QApplication::setOverrideCursor( Qt::WaitCursor ); 05986 khtml::CSSStyleSelector::reparseConfiguration(); 05987 if(d->m_doc) d->m_doc->updateStyleSelector(); 05988 QApplication::restoreOverrideCursor(); 05989 05990 if (d->m_view) { 05991 KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling(); 05992 if (ssm == KHTMLSettings::KSmoothScrollingDisabled) 05993 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled); 05994 else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient) 05995 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient); 05996 else 05997 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled); 05998 } 05999 06000 if (KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled()) 06001 runAdFilter(); 06002 } 06003 06004 QStringList KHTMLPart::frameNames() const 06005 { 06006 QStringList res; 06007 06008 ConstFrameIt it = d->m_frames.constBegin(); 06009 const ConstFrameIt end = d->m_frames.constEnd(); 06010 for (; it != end; ++it ) 06011 if (!(*it)->m_bPreloaded && (*it)->m_part) 06012 res += (*it)->m_name; 06013 06014 return res; 06015 } 06016 06017 QList<KParts::ReadOnlyPart*> KHTMLPart::frames() const 06018 { 06019 QList<KParts::ReadOnlyPart*> res; 06020 06021 ConstFrameIt it = d->m_frames.constBegin(); 06022 const ConstFrameIt end = d->m_frames.constEnd(); 06023 for (; it != end; ++it ) 06024 if (!(*it)->m_bPreloaded && (*it)->m_part) // ### TODO: make sure that we always create an empty 06025 // KHTMLPart for frames so this never happens. 06026 res.append( (*it)->m_part.data() ); 06027 06028 return res; 06029 } 06030 06031 bool KHTMLPart::openUrlInFrame( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs) 06032 { 06033 kDebug( 6031 ) << this << url; 06034 FrameIt it = d->m_frames.find( browserArgs.frameName ); 06035 06036 if ( it == d->m_frames.end() ) 06037 return false; 06038 06039 // Inform someone that we are about to show something else. 06040 if ( !browserArgs.lockHistory() ) 06041 emit d->m_extension->openUrlNotify(); 06042 06043 requestObject( *it, url, args, browserArgs ); 06044 06045 return true; 06046 } 06047 06048 void KHTMLPart::setDNDEnabled( bool b ) 06049 { 06050 d->m_bDnd = b; 06051 } 06052 06053 bool KHTMLPart::dndEnabled() const 06054 { 06055 return d->m_bDnd; 06056 } 06057 06058 void KHTMLPart::customEvent( QEvent *event ) 06059 { 06060 if ( khtml::MousePressEvent::test( event ) ) 06061 { 06062 khtmlMousePressEvent( static_cast<khtml::MousePressEvent *>( event ) ); 06063 return; 06064 } 06065 06066 if ( khtml::MouseDoubleClickEvent::test( event ) ) 06067 { 06068 khtmlMouseDoubleClickEvent( static_cast<khtml::MouseDoubleClickEvent *>( event ) ); 06069 return; 06070 } 06071 06072 if ( khtml::MouseMoveEvent::test( event ) ) 06073 { 06074 khtmlMouseMoveEvent( static_cast<khtml::MouseMoveEvent *>( event ) ); 06075 return; 06076 } 06077 06078 if ( khtml::MouseReleaseEvent::test( event ) ) 06079 { 06080 khtmlMouseReleaseEvent( static_cast<khtml::MouseReleaseEvent *>( event ) ); 06081 return; 06082 } 06083 06084 if ( khtml::DrawContentsEvent::test( event ) ) 06085 { 06086 khtmlDrawContentsEvent( static_cast<khtml::DrawContentsEvent *>( event ) ); 06087 return; 06088 } 06089 06090 KParts::ReadOnlyPart::customEvent( event ); 06091 } 06092 06093 bool KHTMLPart::isPointInsideSelection(int x, int y) 06094 { 06095 // Treat a collapsed selection like no selection. 06096 if (d->editor_context.m_selection.state() == Selection::CARET) 06097 return false; 06098 if (!xmlDocImpl()->renderer()) 06099 return false; 06100 06101 khtml::RenderObject::NodeInfo nodeInfo(true, true); 06102 xmlDocImpl()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y); 06103 NodeImpl *innerNode = nodeInfo.innerNode(); 06104 if (!innerNode || !innerNode->renderer()) 06105 return false; 06106 06107 return innerNode->isPointInsideSelection(x, y, d->editor_context.m_selection); 06108 } 06109 06115 static bool firstRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset) 06116 { 06117 for (khtml::RenderObject *n = renderNode; n; n = n->nextSibling()) { 06118 if (n->isText()) { 06119 khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n); 06120 for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { 06121 if (box->m_y == y && textRenderer->element()) { 06122 startNode = textRenderer->element(); 06123 startOffset = box->m_start; 06124 return true; 06125 } 06126 } 06127 } 06128 06129 if (firstRunAt(n->firstChild(), y, startNode, startOffset)) { 06130 return true; 06131 } 06132 } 06133 06134 return false; 06135 } 06136 06142 static bool lastRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset) 06143 { 06144 khtml::RenderObject *n = renderNode; 06145 if (!n) { 06146 return false; 06147 } 06148 khtml::RenderObject *next; 06149 while ((next = n->nextSibling())) { 06150 n = next; 06151 } 06152 06153 while (1) { 06154 if (lastRunAt(n->firstChild(), y, endNode, endOffset)) { 06155 return true; 06156 } 06157 06158 if (n->isText()) { 06159 khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n); 06160 for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { 06161 if (box->m_y == y && textRenderer->element()) { 06162 endNode = textRenderer->element(); 06163 endOffset = box->m_start + box->m_len; 06164 return true; 06165 } 06166 } 06167 } 06168 06169 if (n == renderNode) { 06170 return false; 06171 } 06172 06173 n = n->previousSibling(); 06174 } 06175 } 06176 06177 void KHTMLPart::handleMousePressEventDoubleClick(khtml::MouseDoubleClickEvent *event) 06178 { 06179 QMouseEvent *mouse = event->qmouseEvent(); 06180 DOM::Node innerNode = event->innerNode(); 06181 06182 Selection selection; 06183 06184 if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() && 06185 innerNode.handle()->renderer()->shouldSelect()) { 06186 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()).position()); 06187 if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) { 06188 selection.moveTo(pos); 06189 selection.expandUsingGranularity(Selection::WORD); 06190 } 06191 } 06192 06193 if (selection.state() != Selection::CARET) { 06194 d->editor_context.beginSelectingText(Selection::WORD); 06195 } 06196 06197 setCaret(selection); 06198 startAutoScroll(); 06199 } 06200 06201 void KHTMLPart::handleMousePressEventTripleClick(khtml::MouseDoubleClickEvent *event) 06202 { 06203 QMouseEvent *mouse = event->qmouseEvent(); 06204 DOM::Node innerNode = event->innerNode(); 06205 06206 Selection selection; 06207 06208 if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() && 06209 innerNode.handle()->renderer()->shouldSelect()) { 06210 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()).position()); 06211 if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) { 06212 selection.moveTo(pos); 06213 selection.expandUsingGranularity(Selection::LINE); 06214 } 06215 } 06216 06217 if (selection.state() != Selection::CARET) { 06218 d->editor_context.beginSelectingText(Selection::LINE); 06219 } 06220 06221 setCaret(selection); 06222 startAutoScroll(); 06223 } 06224 06225 void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event) 06226 { 06227 QMouseEvent *mouse = event->qmouseEvent(); 06228 DOM::Node innerNode = event->innerNode(); 06229 06230 if (mouse->button() == Qt::LeftButton) { 06231 Selection sel; 06232 06233 if (!innerNode.isNull() && innerNode.handle()->renderer() && 06234 innerNode.handle()->renderer()->shouldSelect()) { 06235 bool extendSelection = mouse->modifiers() & Qt::ShiftModifier; 06236 06237 // Don't restart the selection when the mouse is pressed on an 06238 // existing selection so we can allow for text dragging. 06239 if (!extendSelection && isPointInsideSelection(event->x(), event->y())) { 06240 return; 06241 } 06242 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()).position()); 06243 if (pos.isEmpty()) 06244 pos = Position(innerNode.handle(), innerNode.handle()->caretMinOffset()); 06245 kDebug(6050) << event->x() << event->y() << pos << endl; 06246 06247 sel = caret(); 06248 if (extendSelection && sel.notEmpty()) { 06249 sel.clearModifyBias(); 06250 sel.setExtent(pos); 06251 if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) { 06252 sel.expandUsingGranularity(d->editor_context.m_selectionGranularity); 06253 } 06254 d->editor_context.m_beganSelectingText = true; 06255 } else { 06256 sel = pos; 06257 d->editor_context.m_selectionGranularity = Selection::CHARACTER; 06258 } 06259 } 06260 06261 setCaret(sel); 06262 startAutoScroll(); 06263 } 06264 } 06265 06266 void KHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent *event ) 06267 { 06268 DOM::DOMString url = event->url(); 06269 QMouseEvent *_mouse = event->qmouseEvent(); 06270 DOM::Node innerNode = event->innerNode(); 06271 d->m_mousePressNode = innerNode; 06272 06273 d->m_dragStartPos = QPoint(event->x(), event->y()); 06274 06275 if ( !event->url().isNull() ) { 06276 d->m_strSelectedURL = event->url().string(); 06277 d->m_strSelectedURLTarget = event->target().string(); 06278 } 06279 else { 06280 d->m_strSelectedURL.clear(); 06281 d->m_strSelectedURLTarget.clear(); 06282 } 06283 06284 if ( _mouse->button() == Qt::LeftButton || 06285 _mouse->button() == Qt::MidButton ) 06286 { 06287 d->m_bMousePressed = true; 06288 06289 #ifdef KHTML_NO_SELECTION 06290 d->m_dragLastPos = _mouse->globalPos(); 06291 #else 06292 if ( _mouse->button() == Qt::LeftButton ) 06293 { 06294 if ( (!d->m_strSelectedURL.isNull() && !isEditable()) 06295 || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) ) 06296 return; 06297 06298 d->editor_context.m_beganSelectingText = false; 06299 06300 handleMousePressEventSingleClick(event); 06301 } 06302 #endif 06303 } 06304 06305 if ( _mouse->button() == Qt::RightButton ) 06306 { 06307 popupMenu( d->m_strSelectedURL ); 06308 // might be deleted, don't touch "this" 06309 } 06310 } 06311 06312 void KHTMLPart::khtmlMouseDoubleClickEvent( khtml::MouseDoubleClickEvent *event ) 06313 { 06314 QMouseEvent *_mouse = event->qmouseEvent(); 06315 if ( _mouse->button() == Qt::LeftButton ) 06316 { 06317 d->m_bMousePressed = true; 06318 d->editor_context.m_beganSelectingText = false; 06319 06320 if (event->clickCount() == 2) { 06321 handleMousePressEventDoubleClick(event); 06322 return; 06323 } 06324 06325 if (event->clickCount() >= 3) { 06326 handleMousePressEventTripleClick(event); 06327 return; 06328 } 06329 } 06330 } 06331 06332 #ifndef KHTML_NO_SELECTION 06333 bool KHTMLPart::isExtendingSelection() const 06334 { 06335 // This is it, the whole detection. khtmlMousePressEvent only sets this 06336 // on LMB or MMB, but never on RMB. As text selection doesn't work for MMB, 06337 // it's sufficient to only rely on this flag to detect selection extension. 06338 return d->editor_context.m_beganSelectingText; 06339 } 06340 06341 void KHTMLPart::extendSelectionTo(int x, int y, const DOM::Node &innerNode) 06342 { 06343 // handle making selection 06344 Position pos(innerNode.handle()->positionForCoordinates(x, y).position()); 06345 06346 // Don't modify the selection if we're not on a node. 06347 if (pos.isEmpty()) 06348 return; 06349 06350 // Restart the selection if this is the first mouse move. This work is usually 06351 // done in khtmlMousePressEvent, but not if the mouse press was on an existing selection. 06352 Selection sel = caret(); 06353 sel.clearModifyBias(); 06354 if (!d->editor_context.m_beganSelectingText) { 06355 // We are beginning a selection during press-drag, when the original click 06356 // wasn't appropriate for one. Make sure to set the granularity. 06357 d->editor_context.beginSelectingText(Selection::CHARACTER); 06358 sel.moveTo(pos); 06359 } 06360 06361 sel.setExtent(pos); 06362 if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) { 06363 sel.expandUsingGranularity(d->editor_context.m_selectionGranularity); 06364 } 06365 setCaret(sel); 06366 06367 } 06368 #endif // KHTML_NO_SELECTION 06369 06370 bool KHTMLPart::handleMouseMoveEventDrag(khtml::MouseMoveEvent *event) 06371 { 06372 #ifdef QT_NO_DRAGANDDROP 06373 return false; 06374 #else 06375 if (!dndEnabled()) 06376 return false; 06377 06378 DOM::Node innerNode = event->innerNode(); 06379 06380 if( (d->m_bMousePressed && 06381 ( (!d->m_strSelectedURL.isEmpty() && !isEditable()) 06382 || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) ) ) 06383 && ( d->m_dragStartPos - QPoint(event->x(), event->y()) ).manhattanLength() > KGlobalSettings::dndEventDelay() ) { 06384 06385 DOM::DOMString url = event->url(); 06386 06387 QPixmap pix; 06388 HTMLImageElementImpl *img = 0L; 06389 KUrl u; 06390 06391 // qDebug("****************** Event URL: %s", url.string().toLatin1().constData()); 06392 // qDebug("****************** Event Target: %s", target.string().toLatin1().constData()); 06393 06394 // Normal image... 06395 if ( url.length() == 0 && innerNode.handle() && innerNode.handle()->id() == ID_IMG ) 06396 { 06397 img = static_cast<HTMLImageElementImpl *>(innerNode.handle()); 06398 u = KUrl( completeURL( khtml::parseURL(img->getAttribute(ATTR_SRC)).string() ) ); 06399 pix = KIconLoader::global()->loadIcon("image-x-generic", KIconLoader::Desktop); 06400 } 06401 else 06402 { 06403 // Text or image link... 06404 u = completeURL( d->m_strSelectedURL ); 06405 pix = KIO::pixmapForUrl(u, 0, KIconLoader::Desktop, KIconLoader::SizeMedium); 06406 } 06407 06408 u.setPass(QString()); 06409 06410 QDrag *drag = new QDrag( d->m_view->viewport() ); 06411 QMap<QString, QString> metaDataMap; 06412 if ( !d->m_referrer.isEmpty() ) 06413 metaDataMap.insert( "referrer", d->m_referrer ); 06414 QMimeData* mimeData = new QMimeData(); 06415 u.populateMimeData( mimeData, metaDataMap ); 06416 drag->setMimeData( mimeData ); 06417 06418 if( img && img->complete() ) 06419 drag->mimeData()->setImageData( img->currentImage() ); 06420 06421 if ( !pix.isNull() ) 06422 drag->setPixmap( pix ); 06423 06424 stopAutoScroll(); 06425 drag->start(); 06426 06427 // when we finish our drag, we need to undo our mouse press 06428 d->m_bMousePressed = false; 06429 d->m_strSelectedURL.clear(); 06430 d->m_strSelectedURLTarget.clear(); 06431 return true; 06432 } 06433 return false; 06434 #endif // QT_NO_DRAGANDDROP 06435 } 06436 06437 bool KHTMLPart::handleMouseMoveEventOver(khtml::MouseMoveEvent *event) 06438 { 06439 // Mouse clicked -> do nothing 06440 if ( d->m_bMousePressed ) return false; 06441 06442 DOM::DOMString url = event->url(); 06443 06444 // The mouse is over something 06445 if ( url.length() ) 06446 { 06447 DOM::DOMString target = event->target(); 06448 QMouseEvent *_mouse = event->qmouseEvent(); 06449 DOM::Node innerNode = event->innerNode(); 06450 06451 bool shiftPressed = ( _mouse->modifiers() & Qt::ShiftModifier ); 06452 06453 // Image map 06454 if ( !innerNode.isNull() && innerNode.elementId() == ID_IMG ) 06455 { 06456 HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle()); 06457 if ( i && i->isServerMap() ) 06458 { 06459 khtml::RenderObject *r = i->renderer(); 06460 if(r) 06461 { 06462 int absx, absy; 06463 r->absolutePosition(absx, absy); 06464 int x(event->x() - absx), y(event->y() - absy); 06465 06466 d->m_overURL = url.string() + QString("?%1,%2").arg(x).arg(y); 06467 d->m_overURLTarget = target.string(); 06468 overURL( d->m_overURL, target.string(), shiftPressed ); 06469 return true; 06470 } 06471 } 06472 } 06473 06474 // normal link 06475 if ( d->m_overURL.isEmpty() || d->m_overURL != url || d->m_overURLTarget != target ) 06476 { 06477 d->m_overURL = url.string(); 06478 d->m_overURLTarget = target.string(); 06479 overURL( d->m_overURL, target.string(), shiftPressed ); 06480 } 06481 } 06482 else // Not over a link... 06483 { 06484 if( !d->m_overURL.isEmpty() ) // and we were over a link -> reset to "default statusbar text" 06485 { 06486 // reset to "default statusbar text" 06487 resetHoverText(); 06488 } 06489 } 06490 return true; 06491 } 06492 06493 void KHTMLPart::handleMouseMoveEventSelection(khtml::MouseMoveEvent *event) 06494 { 06495 // Mouse not pressed. Do nothing. 06496 if (!d->m_bMousePressed) 06497 return; 06498 06499 #ifdef KHTML_NO_SELECTION 06500 if (d->m_doc && d->m_view) { 06501 QPoint diff( mouse->globalPos() - d->m_dragLastPos ); 06502 06503 if (abs(diff.x()) > 64 || abs(diff.y()) > 64) { 06504 d->m_view->scrollBy(-diff.x(), -diff.y()); 06505 d->m_dragLastPos = mouse->globalPos(); 06506 } 06507 } 06508 #else 06509 06510 QMouseEvent *mouse = event->qmouseEvent(); 06511 DOM::Node innerNode = event->innerNode(); 06512 06513 if ( (mouse->buttons() & Qt::LeftButton) == 0 || !innerNode.handle() || !innerNode.handle()->renderer() || 06514 !innerNode.handle()->renderer()->shouldSelect()) 06515 return; 06516 06517 // handle making selection 06518 extendSelectionTo(event->x(), event->y(), innerNode); 06519 #endif // KHTML_NO_SELECTION 06520 } 06521 06522 void KHTMLPart::khtmlMouseMoveEvent( khtml::MouseMoveEvent *event ) 06523 { 06524 if (handleMouseMoveEventDrag(event)) 06525 return; 06526 06527 if (handleMouseMoveEventOver(event)) 06528 return; 06529 06530 handleMouseMoveEventSelection(event); 06531 } 06532 06533 void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event ) 06534 { 06535 DOM::Node innerNode = event->innerNode(); 06536 d->m_mousePressNode = DOM::Node(); 06537 06538 if ( d->m_bMousePressed ) { 06539 setStatusBarText(QString(), BarHoverText); 06540 stopAutoScroll(); 06541 } 06542 06543 // Used to prevent mouseMoveEvent from initiating a drag before 06544 // the mouse is pressed again. 06545 d->m_bMousePressed = false; 06546 06547 QMouseEvent *_mouse = event->qmouseEvent(); 06548 #ifndef QT_NO_CLIPBOARD 06549 if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == Qt::MidButton) && (event->url().isNull())) { 06550 kDebug( 6050 ) << "MMB shouldOpen=" << d->m_bOpenMiddleClick; 06551 06552 if (d->m_bOpenMiddleClick) { 06553 KHTMLPart *p = this; 06554 while (p->parentPart()) p = p->parentPart(); 06555 p->d->m_extension->pasteRequest(); 06556 } 06557 } 06558 #endif 06559 06560 #ifndef KHTML_NO_SELECTION 06561 { 06562 06563 // Clear the selection if the mouse didn't move after the last mouse press. 06564 // We do this so when clicking on the selection, the selection goes away. 06565 // However, if we are editing, place the caret. 06566 if (!d->editor_context.m_beganSelectingText 06567 && d->m_dragStartPos.x() == event->x() 06568 && d->m_dragStartPos.y() == event->y() 06569 && d->editor_context.m_selection.state() == Selection::RANGE) { 06570 Selection selection; 06571 #ifdef APPLE_CHANGES 06572 if (d->editor_context.m_selection.base().node()->isContentEditable()) 06573 #endif 06574 selection.moveTo(d->editor_context.m_selection.base().node()->positionForCoordinates(event->x(), event->y()).position()); 06575 setCaret(selection); 06576 } 06577 // get selected text and paste to the clipboard 06578 #ifndef QT_NO_CLIPBOARD 06579 QString text = selectedText(); 06580 text.replace(QChar(0xa0), ' '); 06581 if (!text.isEmpty()) { 06582 disconnect( qApp->clipboard(), SIGNAL( selectionChanged()), this, SLOT( slotClearSelection())); 06583 qApp->clipboard()->setText(text,QClipboard::Selection); 06584 connect( qApp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection())); 06585 } 06586 #endif 06587 //kDebug( 6000 ) << "selectedText = " << text; 06588 emitSelectionChanged(); 06589 //kDebug(6000) << "rel2: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << "), caretOfs " << d->caretOffset(); 06590 } 06591 #endif 06592 } 06593 06594 void KHTMLPart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * ) 06595 { 06596 } 06597 06598 void KHTMLPart::guiActivateEvent( KParts::GUIActivateEvent *event ) 06599 { 06600 if ( event->activated() ) 06601 { 06602 emitSelectionChanged(); 06603 emit d->m_extension->enableAction( "print", d->m_doc != 0 ); 06604 06605 if ( !d->m_settings->autoLoadImages() && d->m_paLoadImages ) 06606 { 06607 QList<QAction*> lst; 06608 lst.append( d->m_paLoadImages ); 06609 plugActionList( "loadImages", lst ); 06610 } 06611 } 06612 } 06613 06614 void KHTMLPart::slotPrintFrame() 06615 { 06616 if ( d->m_frames.count() == 0 ) 06617 return; 06618 06619 KParts::ReadOnlyPart *frame = currentFrame(); 06620 if (!frame) 06621 return; 06622 06623 KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject( frame ); 06624 06625 if ( !ext ) 06626 return; 06627 06628 06629 const QMetaObject *mo = ext->metaObject(); 06630 06631 06632 if (mo->indexOfSlot( "print()") != -1) 06633 QMetaObject::invokeMethod(ext, "print()", Qt::DirectConnection); 06634 } 06635 06636 void KHTMLPart::slotSelectAll() 06637 { 06638 KParts::ReadOnlyPart *part = currentFrame(); 06639 if (part && part->inherits("KHTMLPart")) 06640 static_cast<KHTMLPart *>(part)->selectAll(); 06641 } 06642 06643 void KHTMLPart::startAutoScroll() 06644 { 06645 connect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() )); 06646 d->m_scrollTimer.setSingleShot(false); 06647 d->m_scrollTimer.start(100); 06648 } 06649 06650 void KHTMLPart::stopAutoScroll() 06651 { 06652 disconnect(&d->m_scrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScroll() )); 06653 if (d->m_scrollTimer.isActive()) 06654 d->m_scrollTimer.stop(); 06655 } 06656 06657 06658 void KHTMLPart::slotAutoScroll() 06659 { 06660 if (d->m_view) 06661 d->m_view->doAutoScroll(); 06662 else 06663 stopAutoScroll(); // Safety 06664 } 06665 06666 void KHTMLPart::runAdFilter() 06667 { 06668 if ( parentPart() ) 06669 parentPart()->runAdFilter(); 06670 06671 if ( !d->m_doc ) 06672 return; 06673 06674 QSetIterator<khtml::CachedObject*> it( d->m_doc->docLoader()->m_docObjects ); 06675 while (it.hasNext()) 06676 { 06677 khtml::CachedObject* obj = it.next(); 06678 if ( obj->type() == khtml::CachedObject::Image ) { 06679 khtml::CachedImage *image = static_cast<khtml::CachedImage *>(obj); 06680 bool wasBlocked = image->m_wasBlocked; 06681 image->m_wasBlocked = KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( image->url().string() ) ); 06682 if ( image->m_wasBlocked != wasBlocked ) 06683 image->do_notify(QRect(QPoint(0,0), image->pixmap_size())); 06684 } 06685 } 06686 06687 if ( KHTMLGlobal::defaultHTMLSettings()->isHideAdsEnabled() ) { 06688 for ( NodeImpl *nextNode, *node = d->m_doc; node; node = nextNode ) { 06689 06690 // We might be deleting 'node' shortly. 06691 nextNode = node->traverseNextNode(); 06692 06693 if ( node->id() == ID_IMG || 06694 node->id() == ID_IFRAME || 06695 (node->id() == ID_INPUT && static_cast<HTMLInputElementImpl *>(node)->inputType() == HTMLInputElementImpl::IMAGE )) 06696 { 06697 if ( KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( static_cast<ElementImpl *>(node)->getAttribute(ATTR_SRC).string() ) ) ) 06698 { 06699 // Since any kids of node will be deleted, too, fastforward nextNode 06700 // until we get outside of node. 06701 while (nextNode && nextNode->isAncestor(node)) 06702 nextNode = nextNode->traverseNextNode(); 06703 06704 node->ref(); 06705 NodeImpl *parent = node->parent(); 06706 if( parent ) 06707 { 06708 int exception = 0; 06709 parent->removeChild(node, exception); 06710 } 06711 node->deref(); 06712 } 06713 } 06714 } 06715 } 06716 } 06717 06718 void KHTMLPart::selectAll() 06719 { 06720 if (!d->m_doc) return; 06721 06722 NodeImpl *first; 06723 if (d->m_doc->isHTMLDocument()) 06724 first = static_cast<HTMLDocumentImpl*>(d->m_doc)->body(); 06725 else 06726 first = d->m_doc; 06727 NodeImpl *next; 06728 06729 // Look for first text/cdata node that has a renderer, 06730 // or first childless replaced element 06731 while ( first && !(first->renderer() 06732 && ((first->nodeType() == Node::TEXT_NODE || first->nodeType() == Node::CDATA_SECTION_NODE) 06733 || (first->renderer()->isReplaced() && !first->renderer()->firstChild())))) 06734 { 06735 next = first->firstChild(); 06736 if ( !next ) next = first->nextSibling(); 06737 while( first && !next ) 06738 { 06739 first = first->parentNode(); 06740 if ( first ) 06741 next = first->nextSibling(); 06742 } 06743 first = next; 06744 } 06745 06746 NodeImpl *last; 06747 if (d->m_doc->isHTMLDocument()) 06748 last = static_cast<HTMLDocumentImpl*>(d->m_doc)->body(); 06749 else 06750 last = d->m_doc; 06751 // Look for last text/cdata node that has a renderer, 06752 // or last childless replaced element 06753 // ### Instead of changing this loop, use findLastSelectableNode 06754 // in render_table.cpp (LS) 06755 while ( last && !(last->renderer() 06756 && ((last->nodeType() == Node::TEXT_NODE || last->nodeType() == Node::CDATA_SECTION_NODE) 06757 || (last->renderer()->isReplaced() && !last->renderer()->lastChild())))) 06758 { 06759 next = last->lastChild(); 06760 if ( !next ) next = last->previousSibling(); 06761 while ( last && !next ) 06762 { 06763 last = last->parentNode(); 06764 if ( last ) 06765 next = last->previousSibling(); 06766 } 06767 last = next; 06768 } 06769 06770 if ( !first || !last ) 06771 return; 06772 Q_ASSERT(first->renderer()); 06773 Q_ASSERT(last->renderer()); 06774 d->editor_context.m_selection.moveTo(Position(first, 0), Position(last, last->nodeValue().length())); 06775 d->m_doc->updateSelection(); 06776 06777 emitSelectionChanged(); 06778 } 06779 06780 bool KHTMLPart::checkLinkSecurity(const KUrl &linkURL,const KLocalizedString &message, const QString &button) 06781 { 06782 bool linkAllowed = true; 06783 06784 if ( d->m_doc ) 06785 linkAllowed = KAuthorized::authorizeUrlAction("redirect", url(), linkURL); 06786 06787 if ( !linkAllowed ) { 06788 khtml::Tokenizer *tokenizer = d->m_doc->tokenizer(); 06789 if (tokenizer) 06790 tokenizer->setOnHold(true); 06791 06792 int response = KMessageBox::Cancel; 06793 if (!message.isEmpty()) 06794 { 06795 // Dangerous flag makes the Cancel button the default 06796 response = KMessageBox::warningContinueCancel( 0, 06797 message.subs(Qt::escape(linkURL.prettyUrl())).toString(), 06798 i18n( "Security Warning" ), 06799 KGuiItem(button), 06800 KStandardGuiItem::cancel(), 06801 QString(), // no don't ask again info 06802 KMessageBox::Notify | KMessageBox::Dangerous ); 06803 } 06804 else 06805 { 06806 KMessageBox::error( 0, 06807 i18n( "<qt>Access by untrusted page to<br /><b>%1</b><br /> denied.</qt>", Qt::escape(linkURL.prettyUrl())), 06808 i18n( "Security Alert" )); 06809 } 06810 06811 if (tokenizer) 06812 tokenizer->setOnHold(false); 06813 return (response==KMessageBox::Continue); 06814 } 06815 return true; 06816 } 06817 06818 void KHTMLPart::slotPartRemoved( KParts::Part *part ) 06819 { 06820 // kDebug(6050) << part; 06821 if ( part == d->m_activeFrame ) 06822 { 06823 d->m_activeFrame = 0L; 06824 if ( !part->inherits( "KHTMLPart" ) ) 06825 { 06826 if (factory()) { 06827 factory()->removeClient( part ); 06828 } 06829 if (childClients().contains(part)) { 06830 removeChildClient( part ); 06831 } 06832 } 06833 } 06834 } 06835 06836 void KHTMLPart::slotActiveFrameChanged( KParts::Part *part ) 06837 { 06838 // kDebug(6050) << this << "part=" << part; 06839 if ( part == this ) 06840 { 06841 kError(6050) << "strange error! we activated ourselves"; 06842 assert( false ); 06843 return; 06844 } 06845 // kDebug(6050) << "d->m_activeFrame=" << d->m_activeFrame; 06846 if ( d->m_activeFrame && d->m_activeFrame->widget() && d->m_activeFrame->widget()->inherits( "QFrame" ) ) 06847 { 06848 QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() ); 06849 if (frame->frameStyle() != QFrame::NoFrame) 06850 { 06851 frame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken); 06852 frame->repaint(); 06853 } 06854 } 06855 06856 if( d->m_activeFrame && !d->m_activeFrame->inherits( "KHTMLPart" ) ) 06857 { 06858 if (factory()) { 06859 factory()->removeClient( d->m_activeFrame ); 06860 } 06861 removeChildClient( d->m_activeFrame ); 06862 } 06863 if( part && !part->inherits( "KHTMLPart" ) ) 06864 { 06865 if (factory()) { 06866 factory()->addClient( part ); 06867 } 06868 insertChildClient( part ); 06869 } 06870 06871 06872 d->m_activeFrame = part; 06873 06874 if ( d->m_activeFrame && d->m_activeFrame->widget()->inherits( "QFrame" ) ) 06875 { 06876 QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() ); 06877 if (frame->frameStyle() != QFrame::NoFrame) 06878 { 06879 frame->setFrameStyle( QFrame::StyledPanel | QFrame::Plain); 06880 frame->repaint(); 06881 } 06882 kDebug(6050) << "new active frame " << d->m_activeFrame; 06883 } 06884 06885 updateActions(); 06886 06887 // (note: childObject returns 0 if the argument is 0) 06888 d->m_extension->setExtensionProxy( KParts::BrowserExtension::childObject( d->m_activeFrame ) ); 06889 } 06890 06891 void KHTMLPart::setActiveNode(const DOM::Node &node) 06892 { 06893 if (!d->m_doc || !d->m_view) 06894 return; 06895 06896 // Set the document's active node 06897 d->m_doc->setFocusNode(node.handle()); 06898 06899 // Scroll the view if necessary to ensure that the new focus node is visible 06900 QRect rect = node.handle()->getRect(); 06901 d->m_view->ensureVisible(rect.right(), rect.bottom()); 06902 d->m_view->ensureVisible(rect.left(), rect.top()); 06903 } 06904 06905 DOM::Node KHTMLPart::activeNode() const 06906 { 06907 return DOM::Node(d->m_doc?d->m_doc->focusNode():0); 06908 } 06909 06910 DOM::EventListener *KHTMLPart::createHTMLEventListener( QString code, QString name, NodeImpl* node, bool svg ) 06911 { 06912 KJSProxy *proxy = jScript(); 06913 06914 if (!proxy) 06915 return 0; 06916 06917 return proxy->createHTMLEventHandler( url().url(), name, code, node, svg ); 06918 } 06919 06920 KHTMLPart *KHTMLPart::opener() 06921 { 06922 return d->m_opener; 06923 } 06924 06925 void KHTMLPart::setOpener(KHTMLPart *_opener) 06926 { 06927 d->m_opener = _opener; 06928 } 06929 06930 bool KHTMLPart::openedByJS() 06931 { 06932 return d->m_openedByJS; 06933 } 06934 06935 void KHTMLPart::setOpenedByJS(bool _openedByJS) 06936 { 06937 d->m_openedByJS = _openedByJS; 06938 } 06939 06940 void KHTMLPart::preloadStyleSheet(const QString &url, const QString &stylesheet) 06941 { 06942 khtml::Cache::preloadStyleSheet(url, stylesheet); 06943 } 06944 06945 void KHTMLPart::preloadScript(const QString &url, const QString &script) 06946 { 06947 khtml::Cache::preloadScript(url, script); 06948 } 06949 06950 long KHTMLPart::cacheId() const 06951 { 06952 return d->m_cacheId; 06953 } 06954 06955 bool KHTMLPart::restored() const 06956 { 06957 return d->m_restored; 06958 } 06959 06960 bool KHTMLPart::pluginPageQuestionAsked(const QString& mimetype) const 06961 { 06962 // parentPart() should be const! 06963 KHTMLPart* parent = const_cast<KHTMLPart *>(this)->parentPart(); 06964 if ( parent ) 06965 return parent->pluginPageQuestionAsked(mimetype); 06966 06967 return d->m_pluginPageQuestionAsked.contains(mimetype); 06968 } 06969 06970 void KHTMLPart::setPluginPageQuestionAsked(const QString& mimetype) 06971 { 06972 if ( parentPart() ) 06973 parentPart()->setPluginPageQuestionAsked(mimetype); 06974 06975 d->m_pluginPageQuestionAsked.append(mimetype); 06976 } 06977 06978 KEncodingDetector *KHTMLPart::createDecoder() 06979 { 06980 KEncodingDetector *dec = new KEncodingDetector(); 06981 if( !d->m_encoding.isNull() ) 06982 dec->setEncoding( d->m_encoding.toLatin1().constData(), 06983 d->m_haveEncoding ? KEncodingDetector::UserChosenEncoding : KEncodingDetector::EncodingFromHTTPHeader); 06984 else { 06985 // Inherit the default encoding from the parent frame if there is one. 06986 QByteArray defaultEncoding = (parentPart() && parentPart()->d->m_decoder) 06987 ? QByteArray( parentPart()->d->m_decoder->encoding() ) : settings()->encoding().toLatin1(); 06988 dec->setEncoding(defaultEncoding.constData(), KEncodingDetector::DefaultEncoding); 06989 } 06990 06991 if (d->m_doc) 06992 d->m_doc->setDecoder(dec); 06993 dec->setAutoDetectLanguage( d->m_autoDetectLanguage ); 06994 return dec; 06995 } 06996 06997 void KHTMLPart::emitCaretPositionChanged(const DOM::Position &pos) { 06998 // pos must not be already converted to range-compliant coordinates 06999 Position rng_pos = pos.equivalentRangeCompliantPosition(); 07000 Node node = rng_pos.node(); 07001 emit caretPositionChanged(node, rng_pos.offset()); 07002 } 07003 07004 void KHTMLPart::restoreScrollPosition() 07005 { 07006 const KParts::OpenUrlArguments args( arguments() ); 07007 07008 if ( url().hasRef() && !d->m_restoreScrollPosition && !args.reload()) { 07009 if ( !d->m_doc || !d->m_doc->parsing() ) 07010 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 07011 if ( !gotoAnchor(url().encodedHtmlRef()) ) 07012 gotoAnchor(url().htmlRef()); 07013 return; 07014 } 07015 07016 // Check whether the viewport has become large enough to encompass the stored 07017 // offsets. If the document has been fully loaded, force the new coordinates, 07018 // even if the canvas is too short (can happen when user resizes the window 07019 // during loading). 07020 if (d->m_view->contentsHeight() - d->m_view->visibleHeight() >= args.yOffset() 07021 || d->m_bComplete) { 07022 d->m_view->setContentsPos(args.xOffset(), args.yOffset()); 07023 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 07024 } 07025 } 07026 07027 07028 void KHTMLPart::openWallet(DOM::HTMLFormElementImpl *form) 07029 { 07030 #ifndef KHTML_NO_WALLET 07031 KHTMLPart *p; 07032 07033 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) { 07034 } 07035 07036 if (p) { 07037 p->openWallet(form); 07038 return; 07039 } 07040 07041 if (onlyLocalReferences()) { // avoid triggering on local apps, thumbnails 07042 return; 07043 } 07044 07045 if (d->m_wallet) { 07046 if (d->m_bWalletOpened) { 07047 if (d->m_wallet->isOpen()) { 07048 form->walletOpened(d->m_wallet); 07049 return; 07050 } 07051 d->m_wallet->deleteLater(); 07052 d->m_wallet = 0L; 07053 d->m_bWalletOpened = false; 07054 } 07055 } 07056 07057 if (!d->m_wq) { 07058 KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous); 07059 d->m_wq = new KHTMLWalletQueue(this); 07060 d->m_wq->wallet = wallet; 07061 connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool))); 07062 connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*))); 07063 } 07064 assert(form); 07065 d->m_wq->callers.append(KHTMLWalletQueue::Caller(form, form->document())); 07066 #endif // KHTML_NO_WALLET 07067 } 07068 07069 07070 void KHTMLPart::saveToWallet(const QString& key, const QMap<QString,QString>& data) 07071 { 07072 #ifndef KHTML_NO_WALLET 07073 KHTMLPart *p; 07074 07075 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) { 07076 } 07077 07078 if (p) { 07079 p->saveToWallet(key, data); 07080 return; 07081 } 07082 07083 if (d->m_wallet) { 07084 if (d->m_bWalletOpened) { 07085 if (d->m_wallet->isOpen()) { 07086 if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder())) { 07087 d->m_wallet->createFolder(KWallet::Wallet::FormDataFolder()); 07088 } 07089 d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder()); 07090 d->m_wallet->writeMap(key, data); 07091 return; 07092 } 07093 d->m_wallet->deleteLater(); 07094 d->m_wallet = 0L; 07095 d->m_bWalletOpened = false; 07096 } 07097 } 07098 07099 if (!d->m_wq) { 07100 KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous); 07101 d->m_wq = new KHTMLWalletQueue(this); 07102 d->m_wq->wallet = wallet; 07103 connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool))); 07104 connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*))); 07105 } 07106 d->m_wq->savers.append(qMakePair(key, data)); 07107 #endif // KHTML_NO_WALLET 07108 } 07109 07110 07111 void KHTMLPart::dequeueWallet(DOM::HTMLFormElementImpl *form) { 07112 #ifndef KHTML_NO_WALLET 07113 KHTMLPart *p; 07114 07115 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) { 07116 } 07117 07118 if (p) { 07119 p->dequeueWallet(form); 07120 return; 07121 } 07122 07123 if (d->m_wq) { 07124 d->m_wq->callers.removeAll(KHTMLWalletQueue::Caller(form, form->document())); 07125 } 07126 #endif // KHTML_NO_WALLET 07127 } 07128 07129 07130 void KHTMLPart::walletOpened(KWallet::Wallet *wallet) { 07131 #ifndef KHTML_NO_WALLET 07132 assert(!d->m_wallet); 07133 assert(d->m_wq); 07134 07135 d->m_wq->deleteLater(); // safe? 07136 d->m_wq = 0L; 07137 07138 if (!wallet) { 07139 d->m_bWalletOpened = false; 07140 return; 07141 } 07142 07143 d->m_wallet = wallet; 07144 d->m_bWalletOpened = true; 07145 connect(d->m_wallet, SIGNAL(walletClosed()), SLOT(slotWalletClosed())); 07146 d->m_walletForms.clear(); 07147 if (!d->m_statusBarWalletLabel) { 07148 d->m_statusBarWalletLabel = new KUrlLabel(d->m_statusBarExtension->statusBar()); 07149 d->m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); 07150 d->m_statusBarWalletLabel->setUseCursor(false); 07151 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarWalletLabel, 0, false); 07152 d->m_statusBarWalletLabel->setPixmap(SmallIcon("wallet-open")); 07153 connect(d->m_statusBarWalletLabel, SIGNAL(leftClickedUrl()), SLOT(launchWalletManager())); 07154 connect(d->m_statusBarWalletLabel, SIGNAL(rightClickedUrl()), SLOT(walletMenu())); 07155 } 07156 d->m_statusBarWalletLabel->setToolTip(i18n("The wallet '%1' is open and being used for form data and passwords.", KWallet::Wallet::NetworkWallet())); 07157 #endif // KHTML_NO_WALLET 07158 } 07159 07160 07161 KWallet::Wallet *KHTMLPart::wallet() 07162 { 07163 #ifndef KHTML_NO_WALLET 07164 KHTMLPart *p; 07165 07166 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) 07167 ; 07168 07169 if (p) 07170 return p->wallet(); 07171 07172 return d->m_wallet; 07173 #else 07174 return 0; 07175 #endif // !KHTML_NO_WALLET 07176 } 07177 07178 07179 void KHTMLPart::slotWalletClosed() 07180 { 07181 #ifndef KHTML_NO_WALLET 07182 if (d->m_wallet) { 07183 d->m_wallet->deleteLater(); 07184 d->m_wallet = 0L; 07185 } 07186 d->m_bWalletOpened = false; 07187 if (d->m_statusBarWalletLabel) { 07188 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarWalletLabel); 07189 delete d->m_statusBarWalletLabel; 07190 d->m_statusBarWalletLabel = 0L; 07191 } 07192 #endif // KHTML_NO_WALLET 07193 } 07194 07195 void KHTMLPart::launchWalletManager() 07196 { 07197 #ifndef KHTML_NO_WALLET 07198 QDBusInterface r("org.kde.kwalletmanager", "/kwalletmanager/MainWindow_1", 07199 "org.kde.KMainWindow"); 07200 if (!r.isValid()) { 07201 KToolInvocation::startServiceByDesktopName("kwalletmanager_show"); 07202 } else { 07203 r.call(QDBus::NoBlock, "show"); 07204 r.call(QDBus::NoBlock, "raise"); 07205 } 07206 #endif // KHTML_NO_WALLET 07207 } 07208 07209 void KHTMLPart::walletMenu() 07210 { 07211 #ifndef KHTML_NO_WALLET 07212 KMenu *menu = new KMenu(0L); 07213 QActionGroup *menuActionGroup = new QActionGroup(menu); 07214 connect( menuActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(removeStoredPasswordForm(QAction*)) ); 07215 07216 menu->addAction(i18n("&Close Wallet"), this, SLOT(slotWalletClosed())); 07217 07218 if (d->m_view && d->m_view->nonPasswordStorableSite(toplevelURL().host())) { 07219 menu->addAction(i18n("&Allow storing passwords for this site"), this, SLOT(delNonPasswordStorableSite())); 07220 } 07221 07222 // List currently removable form passwords 07223 for ( QStringList::ConstIterator it = d->m_walletForms.constBegin(); it != d->m_walletForms.constEnd(); ++it ) { 07224 QAction* action = menu->addAction( i18n("Remove password for form %1", *it) ); 07225 action->setActionGroup(menuActionGroup); 07226 QVariant var(*it); 07227 action->setData(var); 07228 } 07229 07230 KAcceleratorManager::manage(menu); 07231 menu->popup(QCursor::pos()); 07232 #endif // KHTML_NO_WALLET 07233 } 07234 07235 void KHTMLPart::removeStoredPasswordForm(QAction* action) 07236 { 07237 #ifndef KHTML_NO_WALLET 07238 assert(action); 07239 assert(d->m_wallet); 07240 QVariant var(action->data()); 07241 07242 if(var.isNull() || !var.isValid() || var.type() != QVariant::String) 07243 return; 07244 07245 QString key = var.toString(); 07246 if (KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(), 07247 KWallet::Wallet::FormDataFolder(), 07248 key)) 07249 return; // failed 07250 07251 07252 if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder())) 07253 return; // failed 07254 07255 d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder()); 07256 if (d->m_wallet->removeEntry(key)) 07257 return; // failed 07258 07259 d->m_walletForms.removeAll(key); 07260 #endif // KHTML_NO_WALLET 07261 } 07262 07263 void KHTMLPart::addWalletFormKey(const QString& walletFormKey) 07264 { 07265 #ifndef KHTML_NO_WALLET 07266 07267 if (parentPart()) { 07268 parentPart()->addWalletFormKey(walletFormKey); 07269 return; 07270 } 07271 07272 if(!d->m_walletForms.contains(walletFormKey)) 07273 d->m_walletForms.append(walletFormKey); 07274 #endif // KHTML_NO_WALLET 07275 } 07276 07277 void KHTMLPart::delNonPasswordStorableSite() 07278 { 07279 #ifndef KHTML_NO_WALLET 07280 if (d->m_view) 07281 d->m_view->delNonPasswordStorableSite(toplevelURL().host()); 07282 #endif // KHTML_NO_WALLET 07283 } 07284 void KHTMLPart::saveLoginInformation(const QString& host, const QString& key, const QMap<QString, QString>& walletMap) 07285 { 07286 #ifndef KHTML_NO_WALLET 07287 d->m_storePass.saveLoginInformation(host, key, walletMap); 07288 #endif // KHTML_NO_WALLET 07289 } 07290 07291 void KHTMLPart::slotToggleCaretMode() 07292 { 07293 setCaretMode(d->m_paToggleCaretMode->isChecked()); 07294 } 07295 07296 void KHTMLPart::setFormNotification(KHTMLPart::FormNotification fn) { 07297 d->m_formNotification = fn; 07298 } 07299 07300 KHTMLPart::FormNotification KHTMLPart::formNotification() const { 07301 return d->m_formNotification; 07302 } 07303 07304 KUrl KHTMLPart::toplevelURL() 07305 { 07306 KHTMLPart* part = this; 07307 while (part->parentPart()) 07308 part = part->parentPart(); 07309 07310 if (!part) 07311 return KUrl(); 07312 07313 return part->url(); 07314 } 07315 07316 bool KHTMLPart::isModified() const 07317 { 07318 if ( !d->m_doc ) 07319 return false; 07320 07321 return d->m_doc->unsubmittedFormChanges(); 07322 } 07323 07324 void KHTMLPart::setDebugScript( bool enable ) 07325 { 07326 unplugActionList( "debugScriptList" ); 07327 if ( enable ) { 07328 if (!d->m_paDebugScript) { 07329 d->m_paDebugScript = new KAction( i18n( "JavaScript &Debugger" ), this ); 07330 actionCollection()->addAction( "debugScript", d->m_paDebugScript ); 07331 connect( d->m_paDebugScript, SIGNAL( triggered( bool ) ), this, SLOT( slotDebugScript() ) ); 07332 } 07333 d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L ); 07334 QList<QAction*> lst; 07335 lst.append( d->m_paDebugScript ); 07336 plugActionList( "debugScriptList", lst ); 07337 } 07338 d->m_bJScriptDebugEnabled = enable; 07339 } 07340 07341 void KHTMLPart::setSuppressedPopupIndicator( bool enable, KHTMLPart *originPart ) 07342 { 07343 if ( parentPart() ) { 07344 parentPart()->setSuppressedPopupIndicator( enable, originPart ); 07345 return; 07346 } 07347 07348 if ( enable && originPart ) { 07349 d->m_openableSuppressedPopups++; 07350 if ( d->m_suppressedPopupOriginParts.indexOf( originPart ) == -1 ) 07351 d->m_suppressedPopupOriginParts.append( originPart ); 07352 } 07353 07354 if ( enable && !d->m_statusBarPopupLabel ) { 07355 d->m_statusBarPopupLabel = new KUrlLabel( d->m_statusBarExtension->statusBar() ); 07356 d->m_statusBarPopupLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum )); 07357 d->m_statusBarPopupLabel->setUseCursor( false ); 07358 d->m_statusBarExtension->addStatusBarItem( d->m_statusBarPopupLabel, 0, false ); 07359 d->m_statusBarPopupLabel->setPixmap( SmallIcon( "window-suppressed") ); 07360 07361 d->m_statusBarPopupLabel->setToolTip(i18n("This page was prevented from opening a new window via JavaScript." ) ); 07362 07363 connect(d->m_statusBarPopupLabel, SIGNAL(leftClickedUrl()), SLOT(suppressedPopupMenu())); 07364 if (d->m_settings->jsPopupBlockerPassivePopup()) { 07365 QPixmap px; 07366 px = MainBarIcon( "window-suppressed" ); 07367 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); 07368 } 07369 } else if ( !enable && d->m_statusBarPopupLabel ) { 07370 d->m_statusBarPopupLabel->setToolTip("" ); 07371 d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarPopupLabel ); 07372 delete d->m_statusBarPopupLabel; 07373 d->m_statusBarPopupLabel = 0L; 07374 } 07375 } 07376 07377 void KHTMLPart::suppressedPopupMenu() { 07378 KMenu *m = new KMenu(0L); 07379 if ( d->m_openableSuppressedPopups ) 07380 m->addAction(i18np("&Show Blocked Popup Window","&Show %1 Blocked Popup Windows", d->m_openableSuppressedPopups), this, SLOT(showSuppressedPopups())); 07381 QAction *a = m->addAction(i18n("Show Blocked Window Passive Popup &Notification"), this, SLOT(togglePopupPassivePopup())); 07382 a->setChecked(d->m_settings->jsPopupBlockerPassivePopup()); 07383 m->addAction(i18n("&Configure JavaScript New Window Policies..."), this, SLOT(launchJSConfigDialog())); 07384 m->popup(QCursor::pos()); 07385 } 07386 07387 void KHTMLPart::togglePopupPassivePopup() { 07388 // Same hack as in disableJSErrorExtension() 07389 d->m_settings->setJSPopupBlockerPassivePopup( !d->m_settings->jsPopupBlockerPassivePopup() ); 07390 emit configurationChanged(); 07391 } 07392 07393 void KHTMLPart::showSuppressedPopups() { 07394 foreach ( KHTMLPart* part, d->m_suppressedPopupOriginParts ) { 07395 if (part) { 07396 KJS::Window *w = KJS::Window::retrieveWindow( part ); 07397 if (w) { 07398 w->showSuppressedWindows(); 07399 w->forgetSuppressedWindows(); 07400 } 07401 } 07402 } 07403 setSuppressedPopupIndicator( false ); 07404 d->m_openableSuppressedPopups = 0; 07405 d->m_suppressedPopupOriginParts.clear(); 07406 } 07407 07408 // Extension to use for "view document source", "save as" etc. 07409 // Using the right extension can help the viewer get into the right mode (#40496) 07410 QString KHTMLPart::defaultExtension() const 07411 { 07412 if ( !d->m_doc ) 07413 return ".html"; 07414 if ( !d->m_doc->isHTMLDocument() ) 07415 return ".xml"; 07416 return d->m_doc->htmlMode() == DOM::DocumentImpl::XHtml ? ".xhtml" : ".html"; 07417 } 07418 07419 bool KHTMLPart::inProgress() const 07420 { 07421 if (!d->m_bComplete || d->m_runningScripts || (d->m_doc && d->m_doc->parsing())) 07422 return true; 07423 07424 // Any frame that hasn't completed yet ? 07425 ConstFrameIt it = d->m_frames.constBegin(); 07426 const ConstFrameIt end = d->m_frames.constEnd(); 07427 for (; it != end; ++it ) { 07428 if ((*it)->m_run || !(*it)->m_bCompleted) 07429 return true; 07430 } 07431 07432 return d->m_submitForm || !d->m_redirectURL.isEmpty() || d->m_redirectionTimer.isActive() || d->m_job; 07433 } 07434 07435 using namespace KParts; 07436 #include "khtml_part.moc" 07437 #include "khtmlpart_p.moc" 07438 #ifndef KHTML_NO_WALLET 07439 #include "khtml_wallet_p.moc" 07440 #endif 07441 07442 // kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;
KDE 4.7 API Reference