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