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