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