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