1/* This file is part of the KDE project
2 *
3 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4 * 1999 Lars Knoll <knoll@kde.org>
5 * 1999 Antti Koivisto <koivisto@kde.org>
6 * 2000 Simon Hausmann <hausmann@kde.org>
7 * 2000 Stefan Schimanski <1Stein@gmx.de>
8 * 2001-2005 George Staikos <staikos@kde.org>
9 * 2001-2003 Dirk Mueller <mueller@kde.org>
10 * 2000-2005 David Faure <faure@kde.org>
11 * 2002 Apple Computer, Inc.
12 * 2010 Maksim Orlovich (maksim@kde.org)
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public License
25 * along with this library; see the file COPYING.LIB. If not, write to
26 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
28 */
29
30//#define SPEED_DEBUG
31#include "khtml_part.h"
32
33#include "ui_htmlpageinfo.h"
34
35#include "khtmlviewbar.h"
36#include "khtml_pagecache.h"
37
38#include "dom/dom_string.h"
39#include "dom/dom_element.h"
40#include "dom/dom_exception.h"
41#include "dom/html_document.h"
42#include "dom/dom2_range.h"
43#include "editing/editor.h"
44#include "html/html_documentimpl.h"
45#include "html/html_baseimpl.h"
46#include "html/html_objectimpl.h"
47#include "html/html_miscimpl.h"
48#include "html/html_imageimpl.h"
49#include "imload/imagemanager.h"
50#include "rendering/render_text.h"
51#include "rendering/render_frames.h"
52#include "rendering/render_layer.h"
53#include "rendering/render_position.h"
54#include "misc/loader.h"
55#include "misc/khtml_partaccessor.h"
56#include "xml/dom2_eventsimpl.h"
57#include "xml/dom2_rangeimpl.h"
58#include "xml/xml_tokenizer.h"
59#include "css/cssstyleselector.h"
60#include "css/csshelper.h"
61using namespace DOM;
62
63#include "khtmlview.h"
64#include <kparts/partmanager.h>
65#include <kparts/browseropenorsavequestion.h>
66#include <kacceleratormanager.h>
67#include "ecma/kjs_proxy.h"
68#include "ecma/kjs_window.h"
69#include "ecma/kjs_events.h"
70#include "khtml_settings.h"
71#include "kjserrordlg.h"
72
73#include <kjs/function.h>
74#include <kjs/interpreter.h>
75
76#include <sys/types.h>
77#include <assert.h>
78#include <unistd.h>
79
80#include <config.h>
81
82#include <kstandarddirs.h>
83#include <kstringhandler.h>
84#include <kio/job.h>
85#include <kio/jobuidelegate.h>
86#include <kio/global.h>
87#include <kio/netaccess.h>
88#include <kio/hostinfo_p.h>
89#include <kprotocolmanager.h>
90#include <kdebug.h>
91#include <kicon.h>
92#include <kiconloader.h>
93#include <klocale.h>
94#include <kmessagebox.h>
95#include <kstandardaction.h>
96#include <kstandardguiitem.h>
97#include <kactioncollection.h>
98#include <kfiledialog.h>
99#include <kmimetypetrader.h>
100#include <ktemporaryfile.h>
101#include <kglobalsettings.h>
102#include <ktoolinvocation.h>
103#include <kauthorized.h>
104#include <kparts/browserinterface.h>
105#include <kparts/scriptableextension.h>
106#include <kde_file.h>
107#include <kactionmenu.h>
108#include <ktoggleaction.h>
109#include <kcodecaction.h>
110#include <kselectaction.h>
111
112#include <ksslinfodialog.h>
113#include <ksslsettings.h>
114
115#include <kfileitem.h>
116#include <kurifilter.h>
117#include <kstatusbar.h>
118#include <kurllabel.h>
119
120#include <QtGui/QClipboard>
121#include <QtGui/QToolTip>
122#include <QtCore/QFile>
123#include <QtCore/QMetaEnum>
124#include <QtGui/QTextDocument>
125#include <QtCore/QDate>
126#include <QtNetwork/QSslCertificate>
127
128#include "khtmlpart_p.h"
129#include "khtml_iface.h"
130#include "kpassivepopup.h"
131#include "kmenu.h"
132#include "rendering/render_form.h"
133#include <kwindowsystem.h>
134#include <kconfiggroup.h>
135
136#include "ecma/debugger/debugwindow.h"
137
138// SVG
139#include <svg/SVGDocument.h>
140
141bool KHTMLPartPrivate::s_dnsInitialised = false;
142
143// DNS prefetch settings
144static const int sMaxDNSPrefetchPerPage = 42;
145static const int sDNSPrefetchTimerDelay = 200;
146static const int sDNSTTLSeconds = 400;
147static const int sDNSCacheSize = 500;
148
149
150namespace khtml {
151
152 class PartStyleSheetLoader : public CachedObjectClient
153 {
154 public:
155 PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
156 {
157 m_part = part;
158 m_cachedSheet = dl->requestStyleSheet(url, QString(), "text/css",
159 true /* "user sheet" */);
160 if (m_cachedSheet)
161 m_cachedSheet->ref( this );
162 }
163 virtual ~PartStyleSheetLoader()
164 {
165 if ( m_cachedSheet ) m_cachedSheet->deref(this);
166 }
167 virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet, const DOM::DOMString &, const DOM::DOMString &/*mimetype*/)
168 {
169 if ( m_part )
170 m_part->setUserStyleSheet( sheet.string() );
171
172 delete this;
173 }
174 virtual void error( int, const QString& ) {
175 delete this;
176 }
177 QPointer<KHTMLPart> m_part;
178 khtml::CachedCSSStyleSheet *m_cachedSheet;
179 };
180}
181
182KHTMLPart::KHTMLPart( QWidget *parentWidget, QObject *parent, GUIProfile prof )
183: KParts::ReadOnlyPart( parent )
184{
185 d = 0;
186 KHTMLGlobal::registerPart( this );
187 setComponentData( KHTMLGlobal::componentData(), false );
188 init( new KHTMLView( this, parentWidget ), prof );
189}
190
191KHTMLPart::KHTMLPart( KHTMLView *view, QObject *parent, GUIProfile prof )
192: KParts::ReadOnlyPart( parent )
193{
194 d = 0;
195 KHTMLGlobal::registerPart( this );
196 setComponentData( KHTMLGlobal::componentData(), false );
197 assert( view );
198 if (!view->part())
199 view->setPart( this );
200 init( view, prof );
201}
202
203void KHTMLPart::init( KHTMLView *view, GUIProfile prof )
204{
205 if ( prof == DefaultGUI )
206 setXMLFile( "khtml.rc" );
207 else if ( prof == BrowserViewGUI )
208 setXMLFile( "khtml_browser.rc" );
209
210 d = new KHTMLPartPrivate(this, parent());
211
212 d->m_view = view;
213
214 if (!parentPart()) {
215 QWidget *widget = new QWidget( view->parentWidget() );
216 widget->setObjectName("khtml_part_widget");
217 QVBoxLayout *layout = new QVBoxLayout( widget );
218 layout->setContentsMargins( 0, 0, 0, 0 );
219 layout->setSpacing( 0 );
220 widget->setLayout( layout );
221
222 d->m_topViewBar = new KHTMLViewBar( KHTMLViewBar::Top, d->m_view, widget );
223 d->m_bottomViewBar = new KHTMLViewBar( KHTMLViewBar::Bottom, d->m_view, widget );
224
225 layout->addWidget( d->m_topViewBar );
226 layout->addWidget( d->m_view );
227 layout->addWidget( d->m_bottomViewBar );
228 setWidget( widget );
229 widget->setFocusProxy( d->m_view );
230 } else {
231 setWidget( view );
232 }
233
234 d->m_guiProfile = prof;
235 d->m_extension = new KHTMLPartBrowserExtension( this );
236 d->m_extension->setObjectName( "KHTMLBrowserExtension" );
237 d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
238 d->m_statusBarExtension = new KParts::StatusBarExtension( this );
239 d->m_scriptableExtension = new KJS::KHTMLPartScriptable( this );
240 new KHTMLTextExtension( this );
241 new KHTMLHtmlExtension( this );
242 d->m_statusBarPopupLabel = 0L;
243 d->m_openableSuppressedPopups = 0;
244
245 d->m_paLoadImages = 0;
246 d->m_paDebugScript = 0;
247 d->m_bMousePressed = false;
248 d->m_bRightMousePressed = false;
249 d->m_bCleared = false;
250
251 if ( prof == BrowserViewGUI ) {
252 d->m_paViewDocument = new KAction( i18n( "View Do&cument Source" ), this );
253 actionCollection()->addAction( "viewDocumentSource", d->m_paViewDocument );
254 connect( d->m_paViewDocument, SIGNAL(triggered(bool)), this, SLOT(slotViewDocumentSource()) );
255 if (!parentPart()) {
256 d->m_paViewDocument->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_U) );
257 }
258
259 d->m_paViewFrame = new KAction( i18n( "View Frame Source" ), this );
260 actionCollection()->addAction( "viewFrameSource", d->m_paViewFrame );
261 connect( d->m_paViewFrame, SIGNAL(triggered(bool)), this, SLOT(slotViewFrameSource()) );
262 if (!parentPart()) {
263 d->m_paViewFrame->setShortcut( QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_U) );
264 }
265
266 d->m_paViewInfo = new KAction( i18n( "View Document Information" ), this );
267 actionCollection()->addAction( "viewPageInfo", d->m_paViewInfo );
268 if (!parentPart()) {
269 d->m_paViewInfo->setShortcut( QKeySequence(Qt::CTRL+Qt::Key_I) );
270 }
271 connect( d->m_paViewInfo, SIGNAL(triggered(bool)), this, SLOT(slotViewPageInfo()) );
272
273 d->m_paSaveBackground = new KAction( i18n( "Save &Background Image As..." ), this );
274 actionCollection()->addAction( "saveBackground", d->m_paSaveBackground );
275 connect( d->m_paSaveBackground, SIGNAL(triggered(bool)), this, SLOT(slotSaveBackground()) );
276
277 d->m_paSaveDocument = actionCollection()->addAction( KStandardAction::SaveAs, "saveDocument",
278 this, SLOT(slotSaveDocument()) );
279 if ( parentPart() )
280 d->m_paSaveDocument->setShortcuts( KShortcut() ); // avoid clashes
281
282 d->m_paSaveFrame = new KAction( i18n( "Save &Frame As..." ), this );
283 actionCollection()->addAction( "saveFrame", d->m_paSaveFrame );
284 connect( d->m_paSaveFrame, SIGNAL(triggered(bool)), this, SLOT(slotSaveFrame()) );
285 } else {
286 d->m_paViewDocument = 0;
287 d->m_paViewFrame = 0;
288 d->m_paViewInfo = 0;
289 d->m_paSaveBackground = 0;
290 d->m_paSaveDocument = 0;
291 d->m_paSaveFrame = 0;
292 }
293
294 d->m_paSecurity = new KAction( i18n( "SSL" ), this );
295 actionCollection()->addAction( "security", d->m_paSecurity );
296 connect( d->m_paSecurity, SIGNAL(triggered(bool)), this, SLOT(slotSecurity()) );
297
298 d->m_paDebugRenderTree = new KAction( i18n( "Print Rendering Tree to STDOUT" ), this );
299 actionCollection()->addAction( "debugRenderTree", d->m_paDebugRenderTree );
300 connect( d->m_paDebugRenderTree, SIGNAL(triggered(bool)), this, SLOT(slotDebugRenderTree()) );
301
302 d->m_paDebugDOMTree = new KAction( i18n( "Print DOM Tree to STDOUT" ), this );
303 actionCollection()->addAction( "debugDOMTree", d->m_paDebugDOMTree );
304 connect( d->m_paDebugDOMTree, SIGNAL(triggered(bool)), this, SLOT(slotDebugDOMTree()) );
305
306 KAction* paDebugFrameTree = new KAction( i18n( "Print frame tree to STDOUT" ), this );
307 actionCollection()->addAction( "debugFrameTree", paDebugFrameTree );
308 connect( paDebugFrameTree, SIGNAL(triggered(bool)), this, SLOT(slotDebugFrameTree()) );
309
310 d->m_paStopAnimations = new KAction( i18n( "Stop Animated Images" ), this );
311 actionCollection()->addAction( "stopAnimations", d->m_paStopAnimations );
312 connect( d->m_paStopAnimations, SIGNAL(triggered(bool)), this, SLOT(slotStopAnimations()) );
313
314 d->m_paSetEncoding = new KCodecAction( KIcon("character-set"), i18n( "Set &Encoding" ), this, true );
315 actionCollection()->addAction( "setEncoding", d->m_paSetEncoding );
316// d->m_paSetEncoding->setDelayed( false );
317
318 connect( d->m_paSetEncoding, SIGNAL(triggered(QString)), this, SLOT(slotSetEncoding(QString)));
319 connect( d->m_paSetEncoding, SIGNAL(triggered(KEncodingDetector::AutoDetectScript)), this, SLOT(slotAutomaticDetectionLanguage(KEncodingDetector::AutoDetectScript)));
320
321 if ( KGlobal::config()->hasGroup( "HTML Settings" ) ) {
322 KConfigGroup config( KGlobal::config(), "HTML Settings" );
323
324 d->m_autoDetectLanguage = static_cast<KEncodingDetector::AutoDetectScript>(config.readEntry( "AutomaticDetectionLanguage", /*static_cast<int>(language) */0));
325 if (d->m_autoDetectLanguage==KEncodingDetector::None) {
326 const QByteArray name = KGlobal::locale()->encoding().toLower();
327// kWarning() << "00000000 ";
328 if (name.endsWith("1251")||name.startsWith("koi")||name=="iso-8859-5")
329 d->m_autoDetectLanguage=KEncodingDetector::Cyrillic;
330 else if (name.endsWith("1256")||name=="iso-8859-6")
331 d->m_autoDetectLanguage=KEncodingDetector::Arabic;
332 else if (name.endsWith("1257")||name=="iso-8859-13"||name=="iso-8859-4")
333 d->m_autoDetectLanguage=KEncodingDetector::Baltic;
334 else if (name.endsWith("1250")|| name=="ibm852" || name=="iso-8859-2" || name=="iso-8859-3" )
335 d->m_autoDetectLanguage=KEncodingDetector::CentralEuropean;
336 else if (name.endsWith("1253")|| name=="iso-8859-7" )
337 d->m_autoDetectLanguage=KEncodingDetector::Greek;
338 else if (name.endsWith("1255")|| name=="iso-8859-8" || name=="iso-8859-8-i" )
339 d->m_autoDetectLanguage=KEncodingDetector::Hebrew;
340 else if (name=="jis7" || name=="eucjp" || name=="sjis" )
341 d->m_autoDetectLanguage=KEncodingDetector::Japanese;
342 else if (name.endsWith("1254")|| name=="iso-8859-9" )
343 d->m_autoDetectLanguage=KEncodingDetector::Turkish;
344 else if (name.endsWith("1252")|| name=="iso-8859-1" || name=="iso-8859-15" )
345 d->m_autoDetectLanguage=KEncodingDetector::WesternEuropean;
346 else
347 d->m_autoDetectLanguage=KEncodingDetector::SemiautomaticDetection;
348// kWarning() << "0000000end " << d->m_autoDetectLanguage << " " << KGlobal::locale()->encodingMib();
349 }
350 d->m_paSetEncoding->setCurrentAutoDetectScript(d->m_autoDetectLanguage);
351 }
352
353 d->m_paUseStylesheet = new KSelectAction( i18n( "Use S&tylesheet"), this );
354 actionCollection()->addAction( "useStylesheet", d->m_paUseStylesheet );
355 connect( d->m_paUseStylesheet, SIGNAL(triggered(int)), this, SLOT(slotUseStylesheet()) );
356
357 if ( prof == BrowserViewGUI ) {
358 d->m_paIncZoomFactor = new KHTMLZoomFactorAction( this, true, "format-font-size-more", i18n( "Enlarge Font" ), this );
359 actionCollection()->addAction( "incFontSizes", d->m_paIncZoomFactor );
360 connect(d->m_paIncZoomFactor, SIGNAL(triggered(bool)), SLOT(slotIncFontSizeFast()));
361 d->m_paIncZoomFactor->setWhatsThis( i18n( "<qt>Enlarge Font<br /><br />"
362 "Make the font in this window bigger. "
363 "Click and hold down the mouse button for a menu with all available font sizes.</qt>" ) );
364
365 d->m_paDecZoomFactor = new KHTMLZoomFactorAction( this, false, "format-font-size-less", i18n( "Shrink Font" ), this );
366 actionCollection()->addAction( "decFontSizes", d->m_paDecZoomFactor );
367 connect(d->m_paDecZoomFactor, SIGNAL(triggered(bool)), SLOT(slotDecFontSizeFast()));
368 d->m_paDecZoomFactor->setWhatsThis( i18n( "<qt>Shrink Font<br /><br />"
369 "Make the font in this window smaller. "
370 "Click and hold down the mouse button for a menu with all available font sizes.</qt>" ) );
371 if (!parentPart()) {
372 // For framesets, this action also affects frames, so only
373 // the frameset needs to define a shortcut for the action.
374
375 // TODO: Why also CTRL+=? Because of http://trolltech.com/developer/knowledgebase/524/?
376 // Nobody else does it...
377 d->m_paIncZoomFactor->setShortcut( KShortcut("CTRL++; CTRL+=") );
378 d->m_paDecZoomFactor->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_Minus) );
379 }
380 }
381
382 d->m_paFind = actionCollection()->addAction( KStandardAction::Find, "find", this, SLOT(slotFind()) );
383 d->m_paFind->setWhatsThis( i18n( "<qt>Find text<br /><br />"
384 "Shows a dialog that allows you to find text on the displayed page.</qt>" ) );
385
386 d->m_paFindNext = actionCollection()->addAction( KStandardAction::FindNext, "findNext", this, SLOT(slotFindNext()) );
387 d->m_paFindNext->setWhatsThis( i18n( "<qt>Find next<br /><br />"
388 "Find the next occurrence of the text that you "
389 "have found using the <b>Find Text</b> function.</qt>" ) );
390
391 d->m_paFindPrev = actionCollection()->addAction( KStandardAction::FindPrev, "findPrevious",
392 this, SLOT(slotFindPrev()) );
393 d->m_paFindPrev->setWhatsThis( i18n( "<qt>Find previous<br /><br />"
394 "Find the previous occurrence of the text that you "
395 "have found using the <b>Find Text</b> function.</qt>" ) );
396
397 // These two actions aren't visible in the menus, but exist for the (configurable) shortcut
398 d->m_paFindAheadText = new KAction( i18n("Find Text as You Type"), this );
399 actionCollection()->addAction( "findAheadText", d->m_paFindAheadText );
400 d->m_paFindAheadText->setShortcuts( KShortcut( '/' ) );
401 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."));
402 connect( d->m_paFindAheadText, SIGNAL(triggered(bool)), this, SLOT(slotFindAheadText()) );
403
404 d->m_paFindAheadLinks = new KAction( i18n("Find Links as You Type"), this );
405 actionCollection()->addAction( "findAheadLink", d->m_paFindAheadLinks );
406 // The issue is that it sets the (sticky) option FindLinksOnly, so
407 // if you trigger this shortcut once by mistake, Esc and Ctrl+F will still have the option set.
408 // Better let advanced users configure a shortcut for this advanced option
409 //d->m_paFindAheadLinks->setShortcuts( KShortcut( '\'' ) );
410 d->m_paFindAheadLinks->setHelpText(i18n("This shortcut shows the find bar, and sets the option \"Find links only\"."));
411 connect( d->m_paFindAheadLinks, SIGNAL(triggered(bool)), this, SLOT(slotFindAheadLink()) );
412
413 if ( parentPart() )
414 {
415 d->m_paFind->setShortcuts( KShortcut() ); // avoid clashes
416 d->m_paFindNext->setShortcuts( KShortcut() ); // avoid clashes
417 d->m_paFindPrev->setShortcuts( KShortcut() ); // avoid clashes
418 d->m_paFindAheadText->setShortcuts( KShortcut());
419 d->m_paFindAheadLinks->setShortcuts( KShortcut());
420 }
421
422 d->m_paPrintFrame = new KAction( i18n( "Print Frame..." ), this );
423 actionCollection()->addAction( "printFrame", d->m_paPrintFrame );
424 d->m_paPrintFrame->setIcon( KIcon( "document-print-frame" ) );
425 connect( d->m_paPrintFrame, SIGNAL(triggered(bool)), this, SLOT(slotPrintFrame()) );
426 d->m_paPrintFrame->setWhatsThis( i18n( "<qt>Print Frame<br /><br />"
427 "Some pages have several frames. To print only a single frame, click "
428 "on it and then use this function.</qt>" ) );
429
430 // Warning: The name selectAll is used hardcoded by some 3rd parties to remove the
431 // shortcut for selectAll so they do not get ambigous shortcuts. Renaming it
432 // will either crash or render useless that workaround. It would be better
433 // to use the name KStandardAction::name(KStandardAction::SelectAll) but we
434 // can't for the same reason.
435 d->m_paSelectAll = actionCollection()->addAction( KStandardAction::SelectAll, "selectAll",
436 this, SLOT(slotSelectAll()) );
437 if ( parentPart() ) // Only the frameset has the shortcut, but the slot uses the current frame.
438 d->m_paSelectAll->setShortcuts( KShortcut() ); // avoid clashes
439
440 d->m_paToggleCaretMode = new KToggleAction(i18n("Toggle Caret Mode"), this );
441 actionCollection()->addAction( "caretMode", d->m_paToggleCaretMode );
442 d->m_paToggleCaretMode->setShortcut( QKeySequence(Qt::Key_F7) );
443 connect( d->m_paToggleCaretMode, SIGNAL(triggered(bool)), this, SLOT(slotToggleCaretMode()) );
444 d->m_paToggleCaretMode->setChecked(isCaretMode());
445 if (parentPart())
446 d->m_paToggleCaretMode->setShortcut(KShortcut()); // avoid clashes
447
448 // set the default java(script) flags according to the current host.
449 d->m_bOpenMiddleClick = d->m_settings->isOpenMiddleClickEnabled();
450 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
451 setDebugScript( d->m_settings->isJavaScriptDebugEnabled() );
452 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
453 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
454
455 // Set the meta-refresh flag...
456 d->m_metaRefreshEnabled = d->m_settings->isAutoDelayedActionsEnabled ();
457
458 KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling();
459 if (ssm == KHTMLSettings::KSmoothScrollingDisabled)
460 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled);
461 else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient)
462 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient);
463 else
464 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled);
465
466 if (d->m_bDNSPrefetchIsDefault && !onlyLocalReferences()) {
467 KHTMLSettings::KDNSPrefetch dpm = d->m_settings->dnsPrefetch();
468 if (dpm == KHTMLSettings::KDNSPrefetchDisabled)
469 d->m_bDNSPrefetch = DNSPrefetchDisabled;
470 else if (dpm == KHTMLSettings::KDNSPrefetchOnlyWWWAndSLD)
471 d->m_bDNSPrefetch = DNSPrefetchOnlyWWWAndSLD;
472 else
473 d->m_bDNSPrefetch = DNSPrefetchEnabled;
474 }
475
476 if (!KHTMLPartPrivate::s_dnsInitialised && d->m_bDNSPrefetch != DNSPrefetchDisabled) {
477 KIO::HostInfo::setCacheSize( sDNSCacheSize );
478 KIO::HostInfo::setTTL( sDNSTTLSeconds );
479 KHTMLPartPrivate::s_dnsInitialised = true;
480 }
481
482 // all shortcuts should only be active, when this part has focus
483 foreach ( QAction *action, actionCollection ()->actions () ) {
484 action->setShortcutContext ( Qt::WidgetWithChildrenShortcut );
485 }
486 actionCollection()->associateWidget(view);
487
488 connect( view, SIGNAL(zoomView(int)), SLOT(slotZoomView(int)) );
489
490 connect( this, SIGNAL(completed()),
491 this, SLOT(updateActions()) );
492 connect( this, SIGNAL(completed(bool)),
493 this, SLOT(updateActions()) );
494 connect( this, SIGNAL(started(KIO::Job*)),
495 this, SLOT(updateActions()) );
496
497 // #### FIXME: the process wide loader is going to signal every part about every loaded object.
498 // That's quite inefficient. Should be per-document-tree somehow. Even signaling to
499 // child parts that a request from an ancestor has loaded is inefficent..
500 connect( khtml::Cache::loader(), SIGNAL(requestStarted(khtml::DocLoader*,khtml::CachedObject*)),
501 this, SLOT(slotLoaderRequestStarted(khtml::DocLoader*,khtml::CachedObject*)) );
502 connect( khtml::Cache::loader(), SIGNAL(requestDone(khtml::DocLoader*,khtml::CachedObject*)),
503 this, SLOT(slotLoaderRequestDone(khtml::DocLoader*,khtml::CachedObject*)) );
504 connect( khtml::Cache::loader(), SIGNAL(requestFailed(khtml::DocLoader*,khtml::CachedObject*)),
505 this, SLOT(slotLoaderRequestDone(khtml::DocLoader*,khtml::CachedObject*)) );
506
507 connect ( &d->m_progressUpdateTimer, SIGNAL(timeout()), this, SLOT(slotProgressUpdate()) );
508
509 findTextBegin(); //reset find variables
510
511 connect( &d->m_redirectionTimer, SIGNAL(timeout()),
512 this, SLOT(slotRedirect()) );
513
514 if (QDBusConnection::sessionBus().isConnected()) {
515 new KHTMLPartIface(this); // our "adaptor"
516 for (int i = 1; ; ++i)
517 if (QDBusConnection::sessionBus().registerObject(QString("/KHTML/%1/widget").arg(i), this))
518 break;
519 else if (i == 0xffff)
520 kFatal() << "Something is very wrong in KHTMLPart!";
521 }
522
523 if (prof == BrowserViewGUI && !parentPart())
524 loadPlugins();
525
526 // "khtml" catalog does not exist, our translations are in kdelibs.
527 // removing this catalog from KGlobal::locale() prevents problems
528 // with changing the language in applications at runtime -Thomas Reitelbach
529 // DF: a better fix would be to set the right catalog name in the KComponentData!
530 KGlobal::locale()->removeCatalog("khtml");
531}
532
533KHTMLPart::~KHTMLPart()
534{
535 kDebug(6050) << this;
536 KConfigGroup config( KGlobal::config(), "HTML Settings" );
537 config.writeEntry( "AutomaticDetectionLanguage", int(d->m_autoDetectLanguage) );
538
539 if (d->m_manager) { // the PartManager for this part's children
540 d->m_manager->removePart(this);
541 }
542
543 slotWalletClosed();
544 if (!parentPart()) { // only delete it if the top khtml_part closes
545 removeJSErrorExtension();
546 }
547
548 stopAutoScroll();
549 d->m_redirectionTimer.stop();
550
551 if (!d->m_bComplete)
552 closeUrl();
553
554 disconnect( khtml::Cache::loader(), SIGNAL(requestStarted(khtml::DocLoader*,khtml::CachedObject*)),
555 this, SLOT(slotLoaderRequestStarted(khtml::DocLoader*,khtml::CachedObject*)) );
556 disconnect( khtml::Cache::loader(), SIGNAL(requestDone(khtml::DocLoader*,khtml::CachedObject*)),
557 this, SLOT(slotLoaderRequestDone(khtml::DocLoader*,khtml::CachedObject*)) );
558 disconnect( khtml::Cache::loader(), SIGNAL(requestFailed(khtml::DocLoader*,khtml::CachedObject*)),
559 this, SLOT(slotLoaderRequestDone(khtml::DocLoader*,khtml::CachedObject*)) );
560
561 clear();
562 hide();
563
564 if ( d->m_view )
565 {
566 d->m_view->m_part = 0;
567 }
568
569 // Have to delete this here since we forward declare it in khtmlpart_p and
570 // at least some compilers won't call the destructor in this case.
571 delete d->m_jsedlg;
572 d->m_jsedlg = 0;
573
574 if (!parentPart()) // only delete d->m_frame if the top khtml_part closes
575 delete d->m_frame;
576 else if (d->m_frame && d->m_frame->m_run) // for kids, they may get detached while
577 d->m_frame->m_run.data()->abort(); // resolving mimetype; cancel that if needed
578 delete d; d = 0;
579 KHTMLGlobal::deregisterPart( this );
580}
581
582bool KHTMLPart::restoreURL( const KUrl &url )
583{
584 kDebug( 6050 ) << url;
585
586 d->m_redirectionTimer.stop();
587
588 /*
589 * That's not a good idea as it will call closeUrl() on all
590 * child frames, preventing them from further loading. This
591 * method gets called from restoreState() in case of a full frameset
592 * restoral, and restoreState() calls closeUrl() before restoring
593 * anyway.
594 kDebug( 6050 ) << "closing old URL";
595 closeUrl();
596 */
597
598 d->m_bComplete = false;
599 d->m_bLoadEventEmitted = false;
600 d->m_workingURL = url;
601
602 // set the java(script) flags according to the current host.
603 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
604 setDebugScript( KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
605 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host());
606 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host());
607
608 setUrl(url);
609
610 d->m_restoreScrollPosition = true;
611 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
612 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
613
614 KHTMLPageCache::self()->fetchData( d->m_cacheId, this, SLOT(slotRestoreData(QByteArray)));
615
616 emit started( 0L );
617
618 return true;
619}
620
621bool KHTMLPartPrivate::isLocalAnchorJump( const KUrl& url )
622{
623 // kio_help actually uses fragments to identify different pages, so
624 // always reload with it.
625 if (url.protocol() == QLatin1String("help"))
626 return false;
627
628 return url.hasRef() && url.equals( q->url(),
629 KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment | KUrl::AllowEmptyPath );
630}
631
632void KHTMLPartPrivate::executeAnchorJump( const KUrl& url, bool lockHistory )
633{
634 // Note: we want to emit openUrlNotify first thing, to make the history capture the old state.
635 if (!lockHistory)
636 emit m_extension->openUrlNotify();
637
638 DOM::HashChangeEventImpl *hashChangeEvImpl = 0;
639 const QString &oldRef = q->url().ref();
640 const QString &newRef = url.ref();
641 if ((oldRef != newRef) || (oldRef.isNull() && newRef.isEmpty())) {
642 hashChangeEvImpl = new DOM::HashChangeEventImpl();
643 hashChangeEvImpl->initHashChangeEvent("hashchange",
644 true, //bubble
645 false, //cancelable
646 q->url().url(), //oldURL
647 url.url() //newURL
648 );
649 }
650
651 if ( !q->gotoAnchor( url.encodedHtmlRef()) )
652 q->gotoAnchor( url.htmlRef() );
653
654 q->setUrl(url);
655 emit m_extension->setLocationBarUrl( url.prettyUrl() );
656
657 if (hashChangeEvImpl) {
658 m_doc->dispatchWindowEvent(hashChangeEvImpl);
659 }
660}
661
662bool KHTMLPart::openUrl( const KUrl &url )
663{
664 kDebug( 6050 ) << this << "opening" << url;
665#ifndef KHTML_NO_WALLET
666 // Wallet forms are per page, so clear it when loading a different page if we
667 // are not an iframe (because we store walletforms only on the topmost part).
668 if(!parentPart())
669 d->m_walletForms.clear();
670#endif
671 d->m_redirectionTimer.stop();
672
673 // check to see if this is an "error://" URL. This is caused when an error
674 // occurs before this part was loaded (e.g. KonqRun), and is passed to
675 // khtmlpart so that it can display the error.
676 if ( url.protocol() == "error" ) {
677 closeUrl();
678
679 if( d->m_bJScriptEnabled ) {
680 d->m_statusBarText[BarOverrideText].clear();
681 d->m_statusBarText[BarDefaultText].clear();
682 }
683
684 /**
685 * The format of the error url is that two variables are passed in the query:
686 * error = int kio error code, errText = QString error text from kio
687 * and the URL where the error happened is passed as a sub URL.
688 */
689 KUrl::List urls = KUrl::split( url );
690 //kDebug(6050) << "Handling error URL. URL count:" << urls.count();
691
692 if ( !urls.isEmpty() ) {
693 const KUrl mainURL = urls.first();
694 int error = mainURL.queryItem( "error" ).toInt();
695 // error=0 isn't a valid error code, so 0 means it's missing from the URL
696 if ( error == 0 ) error = KIO::ERR_UNKNOWN;
697 const QString errorText = mainURL.queryItem( "errText" );
698 urls.pop_front();
699 d->m_workingURL = KUrl::join( urls );
700 //kDebug(6050) << "Emitting fixed URL " << d->m_workingURL.prettyUrl();
701 emit d->m_extension->setLocationBarUrl( d->m_workingURL.prettyUrl() );
702 htmlError( error, errorText, d->m_workingURL );
703 return true;
704 }
705 }
706
707 if (!parentPart()) { // only do it for toplevel part
708 QString host = url.isLocalFile() ? "localhost" : url.host();
709 QString userAgent = KProtocolManager::userAgentForHost(host);
710 if (userAgent != KProtocolManager::userAgentForHost(QString())) {
711 if (!d->m_statusBarUALabel) {
712 d->m_statusBarUALabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
713 d->m_statusBarUALabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum));
714 d->m_statusBarUALabel->setUseCursor(false);
715 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarUALabel, 0, false);
716 d->m_statusBarUALabel->setPixmap(SmallIcon("preferences-web-browser-identification"));
717 }
718 d->m_statusBarUALabel->setToolTip(i18n("The fake user-agent '%1' is in use.", userAgent));
719 } else if (d->m_statusBarUALabel) {
720 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarUALabel);
721 delete d->m_statusBarUALabel;
722 d->m_statusBarUALabel = 0L;
723 }
724 }
725
726 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
727 KParts::OpenUrlArguments args( arguments() );
728
729 // in case
730 // a) we have no frameset (don't test m_frames.count(), iframes get in there)
731 // b) the url is identical with the currently displayed one (except for the htmlref!)
732 // c) the url request is not a POST operation and
733 // d) the caller did not request to reload the page
734 // e) there was no HTTP redirection meanwhile (testcase: webmin's software/tree.cgi)
735 // => we don't reload the whole document and
736 // we just jump to the requested html anchor
737 bool isFrameSet = false;
738 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
739 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
740 isFrameSet = htmlDoc->body() && (htmlDoc->body()->id() == ID_FRAMESET);
741 }
742
743 if (isFrameSet && d->isLocalAnchorJump(url) && browserArgs.softReload)
744 {
745 QList<khtml::ChildFrame*>::Iterator it = d->m_frames.begin();
746 const QList<khtml::ChildFrame*>::Iterator end = d->m_frames.end();
747 for (; it != end; ++it) {
748 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part.data() );
749 if (part)
750 {
751 // We are reloading frames to make them jump into offsets.
752 KParts::OpenUrlArguments partargs( part->arguments() );
753 partargs.setReload( true );
754 part->setArguments( partargs );
755
756 part->openUrl( part->url() );
757 }
758 }/*next it*/
759 return true;
760 }
761
762 if ( url.hasRef() && !isFrameSet )
763 {
764 bool noReloadForced = !args.reload() && !browserArgs.redirectedRequest() && !browserArgs.doPost();
765 if ( noReloadForced && d->isLocalAnchorJump(url) )
766 {
767 kDebug( 6050 ) << "jumping to anchor. m_url = " << url;
768 setUrl(url);
769 emit started( 0 );
770
771 if ( !gotoAnchor( url.encodedHtmlRef()) )
772 gotoAnchor( url.htmlRef() );
773
774 d->m_bComplete = true;
775 if (d->m_doc)
776 d->m_doc->setParsing(false);
777
778 kDebug( 6050 ) << "completed...";
779 emit completed();
780 return true;
781 }
782 }
783
784 // Save offset of viewport when page is reloaded to be compliant
785 // to every other capable browser out there.
786 if (args.reload()) {
787 args.setXOffset( d->m_view->contentsX() );
788 args.setYOffset( d->m_view->contentsY() );
789 setArguments(args);
790 }
791
792 if (!d->m_restored)
793 closeUrl();
794
795 d->m_restoreScrollPosition = d->m_restored;
796 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
797 connect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
798
799 // Classify the mimetype. Some, like images and plugins are handled
800 // by wrapping things up in tags, so we want to plain output the HTML,
801 // and not start the job and all that (since we would want the
802 // KPart or whatever to load it).
803 // This is also the only place we need to do this, as it's for
804 // internal iframe use, not any other clients.
805 MimeType type = d->classifyMimeType(args.mimeType());
806
807 if (type == MimeImage || type == MimeOther) {
808 begin(url, args.xOffset(), args.yOffset());
809 write(QString::fromLatin1("<html><head></head><body>"));
810 if (type == MimeImage)
811 write(QString::fromLatin1("<img "));
812 else
813 write(QString::fromLatin1("<embed "));
814 write(QString::fromLatin1("src=\""));
815
816 assert(url.url().indexOf('"') == -1);
817 write(url.url());
818
819 write(QString::fromLatin1("\">"));
820 end();
821 return true;
822 }
823
824
825 // 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
826 // data arrives) (Simon)
827 d->m_workingURL = url;
828 if(url.protocol().startsWith( "http" ) && !url.host().isEmpty() &&
829 url.path().isEmpty()) {
830 d->m_workingURL.setPath("/");
831 emit d->m_extension->setLocationBarUrl( d->m_workingURL.prettyUrl() );
832 }
833 setUrl(d->m_workingURL);
834
835 QMap<QString,QString>& metaData = args.metaData();
836 metaData.insert("main_frame_request", parentPart() == 0 ? "TRUE" : "FALSE" );
837 metaData.insert("ssl_parent_ip", d->m_ssl_parent_ip);
838 metaData.insert("ssl_parent_cert", d->m_ssl_parent_cert);
839 metaData.insert("PropagateHttpHeader", "true");
840 metaData.insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE" : "FALSE" );
841 metaData.insert("ssl_activate_warnings", "TRUE" );
842 metaData.insert("cross-domain", toplevelURL().url());
843
844 if (d->m_restored)
845 {
846 metaData.insert("referrer", d->m_pageReferrer);
847 d->m_cachePolicy = KIO::CC_Cache;
848 }
849 else if (args.reload() && !browserArgs.softReload)
850 d->m_cachePolicy = KIO::CC_Reload;
851 else
852 d->m_cachePolicy = KProtocolManager::cacheControl();
853
854 if ( browserArgs.doPost() && (url.protocol().startsWith("http")) )
855 {
856 d->m_job = KIO::http_post( url, browserArgs.postData, KIO::HideProgressInfo );
857 d->m_job->addMetaData("content-type", browserArgs.contentType() );
858 }
859 else
860 {
861 d->m_job = KIO::get( url, KIO::NoReload, KIO::HideProgressInfo );
862 d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
863 }
864
865 if (widget())
866 d->m_job->ui()->setWindow(widget()->topLevelWidget());
867 d->m_job->addMetaData(metaData);
868
869 connect( d->m_job, SIGNAL(result(KJob*)),
870 SLOT(slotFinished(KJob*)) );
871 connect( d->m_job, SIGNAL(data(KIO::Job*,QByteArray)),
872 SLOT(slotData(KIO::Job*,QByteArray)) );
873 connect ( d->m_job, SIGNAL(infoMessage(KJob*,QString,QString)),
874 SLOT(slotInfoMessage(KJob*,QString)) );
875 connect( d->m_job, SIGNAL(redirection(KIO::Job*,KUrl)),
876 SLOT(slotRedirection(KIO::Job*,KUrl)) );
877
878 d->m_bComplete = false;
879 d->m_bLoadEventEmitted = false;
880
881 // delete old status bar msg's from kjs (if it _was_ activated on last URL)
882 if( d->m_bJScriptEnabled ) {
883 d->m_statusBarText[BarOverrideText].clear();
884 d->m_statusBarText[BarDefaultText].clear();
885 }
886
887 // set the javascript flags according to the current url
888 d->m_bJScriptEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaScriptEnabled(url.host());
889 setDebugScript( KHTMLGlobal::defaultHTMLSettings()->isJavaScriptDebugEnabled() );
890 d->m_bJavaEnabled = KHTMLGlobal::defaultHTMLSettings()->isJavaEnabled(url.host());
891 d->m_bPluginsEnabled = KHTMLGlobal::defaultHTMLSettings()->isPluginsEnabled(url.host());
892
893
894 connect( d->m_job, SIGNAL(speed(KJob*,ulong)),
895 this, SLOT(slotJobSpeed(KJob*,ulong)) );
896
897 connect( d->m_job, SIGNAL(percent(KJob*,ulong)),
898 this, SLOT(slotJobPercent(KJob*,ulong)) );
899
900 connect( d->m_job, SIGNAL(result(KJob*)),
901 this, SLOT(slotJobDone(KJob*)) );
902
903 d->m_jobspeed = 0;
904
905 // If this was an explicit reload and the user style sheet should be used,
906 // do a stat to see whether the stylesheet was changed in the meanwhile.
907 if ( args.reload() && !settings()->userStyleSheet().isEmpty() ) {
908 KUrl url( settings()->userStyleSheet() );
909 KIO::StatJob *job = KIO::stat( url, KIO::HideProgressInfo );
910 connect( job, SIGNAL(result(KJob*)),
911 this, SLOT(slotUserSheetStatDone(KJob*)) );
912 }
913 startingJob( d->m_job );
914 emit started( 0L );
915
916 return true;
917}
918
919bool KHTMLPart::closeUrl()
920{
921 if ( d->m_job )
922 {
923 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
924 d->m_job->kill();
925 d->m_job = 0;
926 }
927
928 if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
929 HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
930
931 if ( hdoc->body() && d->m_bLoadEventEmitted ) {
932 hdoc->body()->dispatchWindowEvent( EventImpl::UNLOAD_EVENT, false, false );
933 if ( d->m_doc )
934 d->m_doc->updateRendering();
935 d->m_bLoadEventEmitted = false;
936 }
937 }
938
939 d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
940 d->m_bLoadEventEmitted = true; // don't want that one either
941 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
942
943 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
944
945 KHTMLPageCache::self()->cancelFetch(this);
946 if ( d->m_doc && d->m_doc->parsing() )
947 {
948 kDebug( 6050 ) << " was still parsing... calling end ";
949 slotFinishedParsing();
950 d->m_doc->setParsing(false);
951 }
952
953 if ( !d->m_workingURL.isEmpty() )
954 {
955 // Aborted before starting to render
956 kDebug( 6050 ) << "Aborted before starting to render, reverting location bar to " << url().prettyUrl();
957 emit d->m_extension->setLocationBarUrl( url().prettyUrl() );
958 }
959
960 d->m_workingURL = KUrl();
961
962 if ( d->m_doc && d->m_doc->docLoader() )
963 khtml::Cache::loader()->cancelRequests( d->m_doc->docLoader() );
964
965 // tell all subframes to stop as well
966 {
967 ConstFrameIt it = d->m_frames.constBegin();
968 const ConstFrameIt end = d->m_frames.constEnd();
969 for (; it != end; ++it )
970 {
971 if ( (*it)->m_run )
972 (*it)->m_run.data()->abort();
973 if ( !( *it )->m_part.isNull() )
974 ( *it )->m_part.data()->closeUrl();
975 }
976 }
977 // tell all objects to stop as well
978 {
979 ConstFrameIt it = d->m_objects.constBegin();
980 const ConstFrameIt end = d->m_objects.constEnd();
981 for (; it != end; ++it)
982 {
983 if ( !( *it )->m_part.isNull() )
984 ( *it )->m_part.data()->closeUrl();
985 }
986 }
987 // Stop any started redirections as well!! (DA)
988 if ( d && d->m_redirectionTimer.isActive() )
989 d->m_redirectionTimer.stop();
990
991 // null node activated.
992 emit nodeActivated(Node());
993
994 // make sure before clear() runs, we pop out of a dialog's message loop
995 if ( d->m_view )
996 d->m_view->closeChildDialogs();
997
998 return true;
999}
1000
1001DOM::HTMLDocument KHTMLPart::htmlDocument() const
1002{
1003 if (d->m_doc && d->m_doc->isHTMLDocument())
1004 return static_cast<HTMLDocumentImpl*>(d->m_doc);
1005 else
1006 return static_cast<HTMLDocumentImpl*>(0);
1007}
1008
1009DOM::Document KHTMLPart::document() const
1010{
1011 return d->m_doc;
1012}
1013
1014QString KHTMLPart::documentSource() const
1015{
1016 QString sourceStr;
1017 if ( !( url().isLocalFile() ) && KHTMLPageCache::self()->isComplete( d->m_cacheId ) )
1018 {
1019 QByteArray sourceArray;
1020 QDataStream dataStream( &sourceArray, QIODevice::WriteOnly );
1021 KHTMLPageCache::self()->saveData( d->m_cacheId, &dataStream );
1022 QTextStream stream( sourceArray, QIODevice::ReadOnly );
1023 stream.setCodec( QTextCodec::codecForName( encoding().toLatin1().constData() ) );
1024 sourceStr = stream.readAll();
1025 } else
1026 {
1027 QString tmpFile;
1028 if( KIO::NetAccess::download( url(), tmpFile, NULL ) )
1029 {
1030 QFile f( tmpFile );
1031 if ( f.open( QIODevice::ReadOnly ) )
1032 {
1033 QTextStream stream( &f );
1034 stream.setCodec( QTextCodec::codecForName( encoding().toLatin1().constData() ) );
1035 sourceStr = stream.readAll();
1036 f.close();
1037 }
1038 KIO::NetAccess::removeTempFile( tmpFile );
1039 }
1040 }
1041
1042 return sourceStr;
1043}
1044
1045
1046KParts::BrowserExtension *KHTMLPart::browserExtension() const
1047{
1048 return d->m_extension;
1049}
1050
1051KParts::BrowserHostExtension *KHTMLPart::browserHostExtension() const
1052{
1053 return d->m_hostExtension;
1054}
1055
1056KHTMLView *KHTMLPart::view() const
1057{
1058 return d->m_view;
1059}
1060
1061KHTMLViewBar *KHTMLPart::pTopViewBar() const
1062{
1063 if (const_cast<KHTMLPart*>(this)->parentPart())
1064 return const_cast<KHTMLPart*>(this)->parentPart()->pTopViewBar();
1065 return d->m_topViewBar;
1066}
1067
1068KHTMLViewBar *KHTMLPart::pBottomViewBar() const
1069{
1070 if (const_cast<KHTMLPart*>(this)->parentPart())
1071 return const_cast<KHTMLPart*>(this)->parentPart()->pBottomViewBar();
1072 return d->m_bottomViewBar;
1073}
1074
1075void KHTMLPart::setStatusMessagesEnabled( bool enable )
1076{
1077 d->m_statusMessagesEnabled = enable;
1078}
1079
1080KJS::Interpreter *KHTMLPart::jScriptInterpreter()
1081{
1082 KJSProxy *proxy = jScript();
1083 if (!proxy || proxy->paused())
1084 return 0;
1085
1086 return proxy->interpreter();
1087}
1088
1089bool KHTMLPart::statusMessagesEnabled() const
1090{
1091 return d->m_statusMessagesEnabled;
1092}
1093
1094void KHTMLPart::setJScriptEnabled( bool enable )
1095{
1096 if ( !enable && jScriptEnabled() && d->m_frame && d->m_frame->m_jscript ) {
1097 d->m_frame->m_jscript->clear();
1098 }
1099 d->m_bJScriptForce = enable;
1100 d->m_bJScriptOverride = true;
1101}
1102
1103bool KHTMLPart::jScriptEnabled() const
1104{
1105 if(onlyLocalReferences()) return false;
1106
1107 if ( d->m_bJScriptOverride )
1108 return d->m_bJScriptForce;
1109 return d->m_bJScriptEnabled;
1110}
1111
1112void KHTMLPart::setDNSPrefetch( DNSPrefetch pmode )
1113{
1114 d->m_bDNSPrefetch = pmode;
1115 d->m_bDNSPrefetchIsDefault = false;
1116}
1117
1118KHTMLPart::DNSPrefetch KHTMLPart::dnsPrefetch() const
1119{
1120 if (onlyLocalReferences())
1121 return DNSPrefetchDisabled;
1122 return d->m_bDNSPrefetch;
1123}
1124
1125void KHTMLPart::setMetaRefreshEnabled( bool enable )
1126{
1127 d->m_metaRefreshEnabled = enable;
1128}
1129
1130bool KHTMLPart::metaRefreshEnabled() const
1131{
1132 return d->m_metaRefreshEnabled;
1133}
1134
1135KJSProxy *KHTMLPart::jScript()
1136{
1137 if (!jScriptEnabled()) return 0;
1138
1139 if ( !d->m_frame ) {
1140 KHTMLPart * p = parentPart();
1141 if (!p) {
1142 d->m_frame = new khtml::ChildFrame;
1143 d->m_frame->m_part = this;
1144 } else {
1145 ConstFrameIt it = p->d->m_frames.constBegin();
1146 const ConstFrameIt end = p->d->m_frames.constEnd();
1147 for (; it != end; ++it)
1148 if ((*it)->m_part.data() == this) {
1149 d->m_frame = *it;
1150 break;
1151 }
1152 }
1153 if ( !d->m_frame )
1154 return 0;
1155 }
1156 if ( !d->m_frame->m_jscript )
1157 d->m_frame->m_jscript = new KJSProxy(d->m_frame);
1158 d->m_frame->m_jscript->setDebugEnabled(d->m_bJScriptDebugEnabled);
1159
1160 return d->m_frame->m_jscript;
1161}
1162
1163QVariant KHTMLPart::crossFrameExecuteScript(const QString& target, const QString& script)
1164{
1165 KHTMLPart* destpart = this;
1166
1167 QString trg = target.toLower();
1168
1169 if (target == "_top") {
1170 while (destpart->parentPart())
1171 destpart = destpart->parentPart();
1172 }
1173 else if (target == "_parent") {
1174 if (parentPart())
1175 destpart = parentPart();
1176 }
1177 else if (target == "_self" || target == "_blank") {
1178 // we always allow these
1179 }
1180 else {
1181 destpart = findFrame(target);
1182 if (!destpart)
1183 destpart = this;
1184 }
1185
1186 // easy way out?
1187 if (destpart == this)
1188 return executeScript(DOM::Node(), script);
1189
1190 // now compare the domains
1191 if (destpart->checkFrameAccess(this))
1192 return destpart->executeScript(DOM::Node(), script);
1193
1194 // eww, something went wrong. better execute it in our frame
1195 return executeScript(DOM::Node(), script);
1196}
1197
1198//Enable this to see all JS scripts being executed
1199//#define KJS_VERBOSE
1200
1201KJSErrorDlg *KHTMLPart::jsErrorExtension() {
1202 if (!d->m_settings->jsErrorsEnabled()) {
1203 return 0L;
1204 }
1205
1206 if (parentPart()) {
1207 return parentPart()->jsErrorExtension();
1208 }
1209
1210 if (!d->m_statusBarJSErrorLabel) {
1211 d->m_statusBarJSErrorLabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
1212 d->m_statusBarJSErrorLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum));
1213 d->m_statusBarJSErrorLabel->setUseCursor(false);
1214 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarJSErrorLabel, 0, false);
1215 d->m_statusBarJSErrorLabel->setToolTip(i18n("This web page contains coding errors."));
1216 d->m_statusBarJSErrorLabel->setPixmap(SmallIcon("script-error"));
1217 connect(d->m_statusBarJSErrorLabel, SIGNAL(leftClickedUrl()), SLOT(launchJSErrorDialog()));
1218 connect(d->m_statusBarJSErrorLabel, SIGNAL(rightClickedUrl()), SLOT(jsErrorDialogContextMenu()));
1219 }
1220 if (!d->m_jsedlg) {
1221 d->m_jsedlg = new KJSErrorDlg;
1222 d->m_jsedlg->setURL(url().prettyUrl());
1223 if (KGlobalSettings::showIconsOnPushButtons()) {
1224 d->m_jsedlg->_clear->setIcon(KIcon("edit-clear-locationbar-ltr"));
1225 d->m_jsedlg->_close->setIcon(KIcon("window-close"));
1226 }
1227 }
1228 return d->m_jsedlg;
1229}
1230
1231void KHTMLPart::removeJSErrorExtension() {
1232 if (parentPart()) {
1233 parentPart()->removeJSErrorExtension();
1234 return;
1235 }
1236 if (d->m_statusBarJSErrorLabel != 0) {
1237 d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarJSErrorLabel );
1238 delete d->m_statusBarJSErrorLabel;
1239 d->m_statusBarJSErrorLabel = 0;
1240 }
1241 delete d->m_jsedlg;
1242 d->m_jsedlg = 0;
1243}
1244
1245void KHTMLPart::disableJSErrorExtension() {
1246 removeJSErrorExtension();
1247 // These two lines are really kind of hacky, and it sucks to do this inside
1248 // KHTML but I don't know of anything that's reasonably easy as an alternative
1249 // right now. It makes me wonder if there should be a more clean way to
1250 // contact all running "KHTML" instance as opposed to Konqueror instances too.
1251 d->m_settings->setJSErrorsEnabled(false);
1252 emit configurationChanged();
1253}
1254
1255void KHTMLPart::jsErrorDialogContextMenu() {
1256 KMenu *m = new KMenu(0L);
1257 m->addAction(i18n("&Hide Errors"), this, SLOT(removeJSErrorExtension()));
1258 m->addAction(i18n("&Disable Error Reporting"), this, SLOT(disableJSErrorExtension()));
1259 m->popup(QCursor::pos());
1260}
1261
1262void KHTMLPart::launchJSErrorDialog() {
1263 KJSErrorDlg *dlg = jsErrorExtension();
1264 if (dlg) {
1265 dlg->show();
1266 dlg->raise();
1267 }
1268}
1269
1270void KHTMLPart::launchJSConfigDialog() {
1271 QStringList args;
1272 args << "khtml_java_js";
1273 KToolInvocation::kdeinitExec( "kcmshell4", args );
1274}
1275
1276QVariant KHTMLPart::executeScript(const QString& filename, int baseLine, const DOM::Node& n, const QString& script)
1277{
1278#ifdef KJS_VERBOSE
1279 // The script is now printed by KJS's Parser::parse
1280 kDebug(6070) << "executeScript: caller='" << objectName() << "' filename=" << filename << " baseLine=" << baseLine /*<< " script=" << script*/;
1281#endif
1282 KJSProxy *proxy = jScript();
1283
1284 if (!proxy || proxy->paused())
1285 return QVariant();
1286
1287 KJS::Completion comp;
1288 QVariant ret = proxy->evaluate(filename, baseLine, script, n, &comp);
1289
1290 /*
1291 * Error handling
1292 */
1293 if (comp.complType() == KJS::Throw && comp.value()) {
1294 KJSErrorDlg *dlg = jsErrorExtension();
1295 if (dlg) {
1296 QString msg = KJSDebugger::DebugWindow::exceptionToString(
1297 proxy->interpreter()->globalExec(), comp.value());
1298 dlg->addError(i18n("<qt><b>Error</b>: %1: %2</qt>",
1299 Qt::escape(filename), Qt::escape(msg)));
1300 }
1301 }
1302
1303 // Handle immediate redirects now (e.g. location='foo')
1304 if ( !d->m_redirectURL.isEmpty() && d->m_delayRedirect == -1 )
1305 {
1306 kDebug(6070) << "executeScript done, handling immediate redirection NOW";
1307 // Must abort tokenizer, no further script must execute.
1308 khtml::Tokenizer* t = d->m_doc->tokenizer();
1309 if(t)
1310 t->abort();
1311 d->m_redirectionTimer.setSingleShot( true );
1312 d->m_redirectionTimer.start( 0 );
1313 }
1314
1315 return ret;
1316}
1317
1318QVariant KHTMLPart::executeScript( const QString &script )
1319{
1320 return executeScript( DOM::Node(), script );
1321}
1322
1323QVariant KHTMLPart::executeScript( const DOM::Node &n, const QString &script )
1324{
1325#ifdef KJS_VERBOSE
1326 kDebug(6070) << "caller=" << objectName() << "node=" << n.nodeName().string().toLatin1().constData() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " /* << script */;
1327#endif
1328 KJSProxy *proxy = jScript();
1329
1330 if (!proxy || proxy->paused())
1331 return QVariant();
1332
1333 ++(d->m_runningScripts);
1334 KJS::Completion comp;
1335 const QVariant ret = proxy->evaluate( QString(), 1, script, n, &comp );
1336 --(d->m_runningScripts);
1337
1338 /*
1339 * Error handling
1340 */
1341 if (comp.complType() == KJS::Throw && comp.value()) {
1342 KJSErrorDlg *dlg = jsErrorExtension();
1343 if (dlg) {
1344 QString msg = KJSDebugger::DebugWindow::exceptionToString(
1345 proxy->interpreter()->globalExec(), comp.value());
1346 dlg->addError(i18n("<qt><b>Error</b>: node %1: %2</qt>",
1347 n.nodeName().string(), Qt::escape(msg)));
1348 }
1349 }
1350
1351 if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
1352 submitFormAgain();
1353
1354#ifdef KJS_VERBOSE
1355 kDebug(6070) << "done";
1356#endif
1357 return ret;
1358}
1359
1360void KHTMLPart::setJavaEnabled( bool enable )
1361{
1362 d->m_bJavaForce = enable;
1363 d->m_bJavaOverride = true;
1364}
1365
1366bool KHTMLPart::javaEnabled() const
1367{
1368 if (onlyLocalReferences()) return false;
1369
1370#ifndef Q_WS_QWS
1371 if( d->m_bJavaOverride )
1372 return d->m_bJavaForce;
1373 return d->m_bJavaEnabled;
1374#else
1375 return false;
1376#endif
1377}
1378
1379void KHTMLPart::setPluginsEnabled( bool enable )
1380{
1381 d->m_bPluginsForce = enable;
1382 d->m_bPluginsOverride = true;
1383}
1384
1385bool KHTMLPart::pluginsEnabled() const
1386{
1387 if (onlyLocalReferences()) return false;
1388
1389 if ( d->m_bPluginsOverride )
1390 return d->m_bPluginsForce;
1391 return d->m_bPluginsEnabled;
1392}
1393
1394static int s_DOMTreeIndentLevel = 0;
1395
1396void KHTMLPart::slotDebugDOMTree()
1397{
1398 if ( d->m_doc )
1399 qDebug("%s", d->m_doc->toString().string().toLatin1().constData());
1400
1401 // Now print the contents of the frames that contain HTML
1402
1403 const int indentLevel = s_DOMTreeIndentLevel++;
1404
1405 ConstFrameIt it = d->m_frames.constBegin();
1406 const ConstFrameIt end = d->m_frames.constEnd();
1407 for (; it != end; ++it )
1408 if ( !( *it )->m_part.isNull() && (*it)->m_part.data()->inherits( "KHTMLPart" ) ) {
1409 KParts::ReadOnlyPart* const p = ( *it )->m_part.data();
1410 kDebug(6050) << QString().leftJustified(s_DOMTreeIndentLevel*4,' ') << "FRAME " << p->objectName() << " ";
1411 static_cast<KHTMLPart*>( p )->slotDebugDOMTree();
1412 }
1413 s_DOMTreeIndentLevel = indentLevel;
1414}
1415
1416void KHTMLPart::slotDebugScript()
1417{
1418 if (jScript())
1419 jScript()->showDebugWindow();
1420}
1421
1422void KHTMLPart::slotDebugRenderTree()
1423{
1424#ifndef NDEBUG
1425 if ( d->m_doc ) {
1426 d->m_doc->renderer()->printTree();
1427 // dump out the contents of the rendering & DOM trees
1428// QString dumps;
1429// QTextStream outputStream(&dumps,QIODevice::WriteOnly);
1430// d->m_doc->renderer()->layer()->dump( outputStream );
1431// kDebug() << "dump output:" << "\n" + dumps;
1432// d->m_doc->renderer()->printLineBoxTree();
1433 }
1434#endif
1435}
1436
1437void KHTMLPart::slotDebugFrameTree()
1438{
1439 khtml::ChildFrame::dumpFrameTree(this);
1440}
1441
1442void KHTMLPart::slotStopAnimations()
1443{
1444 stopAnimations();
1445}
1446
1447void KHTMLPart::setAutoloadImages( bool enable )
1448{
1449 if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
1450 return;
1451
1452 if ( d->m_doc )
1453 d->m_doc->docLoader()->setAutoloadImages( enable );
1454
1455 unplugActionList( "loadImages" );
1456
1457 if ( enable ) {
1458 delete d->m_paLoadImages;
1459 d->m_paLoadImages = 0;
1460 }
1461 else if ( !d->m_paLoadImages ) {
1462 d->m_paLoadImages = new KAction( i18n( "Display Images on Page" ), this );
1463 actionCollection()->addAction( "loadImages", d->m_paLoadImages );
1464 d->m_paLoadImages->setIcon( KIcon( "image-loading" ) );
1465 connect( d->m_paLoadImages, SIGNAL(triggered(bool)), this, SLOT(slotLoadImages()) );
1466 }
1467
1468 if ( d->m_paLoadImages ) {
1469 QList<QAction*> lst;
1470 lst.append( d->m_paLoadImages );
1471 plugActionList( "loadImages", lst );
1472 }
1473}
1474
1475bool KHTMLPart::autoloadImages() const
1476{
1477 if ( d->m_doc )
1478 return d->m_doc->docLoader()->autoloadImages();
1479
1480 return true;
1481}
1482
1483void KHTMLPart::clear()
1484{
1485 if ( d->m_bCleared )
1486 return;
1487
1488 d->m_bCleared = true;
1489
1490 d->m_bClearing = true;
1491
1492 {
1493 ConstFrameIt it = d->m_frames.constBegin();
1494 const ConstFrameIt end = d->m_frames.constEnd();
1495 for(; it != end; ++it )
1496 {
1497 // Stop HTMLRun jobs for frames
1498 if ( (*it)->m_run )
1499 (*it)->m_run.data()->abort();
1500 }
1501 }
1502
1503 {
1504 ConstFrameIt it = d->m_objects.constBegin();
1505 const ConstFrameIt end = d->m_objects.constEnd();
1506 for(; it != end; ++it )
1507 {
1508 // Stop HTMLRun jobs for objects
1509 if ( (*it)->m_run )
1510 (*it)->m_run.data()->abort();
1511 }
1512 }
1513
1514
1515 findTextBegin(); // resets d->m_findNode and d->m_findPos
1516 d->m_mousePressNode = DOM::Node();
1517
1518
1519 if ( d->m_doc )
1520 {
1521 if (d->m_doc->attached()) //the view may have detached it already
1522 d->m_doc->detach();
1523 }
1524
1525 // Moving past doc so that onUnload works.
1526 if ( d->m_frame && d->m_frame->m_jscript )
1527 d->m_frame->m_jscript->clear();
1528
1529 // stopping marquees
1530 if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->layer())
1531 d->m_doc->renderer()->layer()->suspendMarquees();
1532
1533 if ( d->m_view )
1534 d->m_view->clear();
1535
1536 // do not dereference the document before the jscript and view are cleared, as some destructors
1537 // might still try to access the document.
1538 if ( d->m_doc ) {
1539 d->m_doc->deref();
1540 }
1541 d->m_doc = 0;
1542
1543 delete d->m_decoder;
1544 d->m_decoder = 0;
1545
1546 // We don't want to change between parts if we are going to delete all of them anyway
1547 if (partManager()) {
1548 disconnect( partManager(), SIGNAL(activePartChanged(KParts::Part*)),
1549 this, SLOT(slotActiveFrameChanged(KParts::Part*)) );
1550 }
1551
1552 if (d->m_frames.count())
1553 {
1554 const KHTMLFrameList frames = d->m_frames;
1555 d->m_frames.clear();
1556 ConstFrameIt it = frames.begin();
1557 const ConstFrameIt end = frames.end();
1558 for(; it != end; ++it )
1559 {
1560 if ( (*it)->m_part )
1561 {
1562 partManager()->removePart( (*it)->m_part.data() );
1563 delete (*it)->m_part.data();
1564 }
1565 delete *it;
1566 }
1567 }
1568 d->m_suppressedPopupOriginParts.clear();
1569
1570 if (d->m_objects.count())
1571 {
1572 KHTMLFrameList objects = d->m_objects;
1573 d->m_objects.clear();
1574 ConstFrameIt oi = objects.constBegin();
1575 const ConstFrameIt oiEnd = objects.constEnd();
1576
1577 for (; oi != oiEnd; ++oi )
1578 {
1579 delete (*oi)->m_part.data();
1580 delete *oi;
1581 }
1582 }
1583
1584 // Listen to part changes again
1585 if (partManager()) {
1586 connect( partManager(), SIGNAL(activePartChanged(KParts::Part*)),
1587 this, SLOT(slotActiveFrameChanged(KParts::Part*)) );
1588 }
1589
1590 d->clearRedirection();
1591 d->m_redirectLockHistory = true;
1592 d->m_bClearing = false;
1593 d->m_frameNameId = 1;
1594 d->m_bFirstData = true;
1595
1596 d->m_bMousePressed = false;
1597
1598 if (d->editor_context.m_caretBlinkTimer >= 0)
1599 killTimer(d->editor_context.m_caretBlinkTimer);
1600 d->editor_context.reset();
1601#ifndef QT_NO_CLIPBOARD
1602 connect( qApp->clipboard(), SIGNAL(selectionChanged()), SLOT(slotClearSelection()));
1603#endif
1604
1605 d->m_jobPercent = 0;
1606
1607 if ( !d->m_haveEncoding )
1608 d->m_encoding.clear();
1609
1610 d->m_DNSPrefetchQueue.clear();
1611 if (d->m_DNSPrefetchTimer > 0)
1612 killTimer(d->m_DNSPrefetchTimer);
1613 d->m_DNSPrefetchTimer = -1;
1614 d->m_lookedupHosts.clear();
1615 if (d->m_DNSTTLTimer > 0)
1616 killTimer(d->m_DNSTTLTimer);
1617 d->m_DNSTTLTimer = -1;
1618 d->m_numDNSPrefetchedNames = 0;
1619
1620#ifdef SPEED_DEBUG
1621 d->m_parsetime.restart();
1622#endif
1623}
1624
1625bool KHTMLPart::openFile()
1626{
1627 return true;
1628}
1629
1630DOM::HTMLDocumentImpl *KHTMLPart::docImpl() const
1631{
1632 if ( d && d->m_doc && d->m_doc->isHTMLDocument() )
1633 return static_cast<HTMLDocumentImpl*>(d->m_doc);
1634 return 0;
1635}
1636
1637DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
1638{
1639 if ( d )
1640 return d->m_doc;
1641 return 0;
1642}
1643
1644void KHTMLPart::slotInfoMessage(KJob* kio_job, const QString& msg)
1645{
1646 assert(d->m_job == kio_job);
1647 Q_ASSERT(kio_job);
1648 Q_UNUSED(kio_job);
1649
1650 if (!parentPart())
1651 setStatusBarText(msg, BarDefaultText);
1652}
1653
1654void KHTMLPart::setPageSecurity( PageSecurity sec )
1655{
1656 emit d->m_extension->setPageSecurity( sec );
1657}
1658
1659void KHTMLPart::slotData( KIO::Job* kio_job, const QByteArray &data )
1660{
1661 assert ( d->m_job == kio_job );
1662 Q_ASSERT(kio_job);
1663 Q_UNUSED(kio_job);
1664
1665 //kDebug( 6050 ) << "slotData: " << data.size();
1666 // The first data ?
1667 if ( !d->m_workingURL.isEmpty() )
1668 {
1669 //kDebug( 6050 ) << "begin!";
1670
1671 // We must suspend KIO while we're inside begin() because it can cause
1672 // crashes if a window (such as kjsdebugger) goes back into the event loop,
1673 // more data arrives, and begin() gets called again (re-entered).
1674 d->m_job->suspend();
1675 begin( d->m_workingURL, arguments().xOffset(), arguments().yOffset() );
1676 d->m_job->resume();
1677
1678 // CC_Refresh means : always send the server an If-Modified-Since conditional request.
1679 // This is the default cache setting and correspond to the KCM's "Keep cache in sync".
1680 // CC_Verify means : only send a conditional request if the cache expiry date is passed.
1681 // It doesn't have a KCM setter.
1682 // We override the first to the second, except when doing a soft-reload.
1683 if (d->m_cachePolicy == KIO::CC_Refresh && !d->m_extension->browserArguments().softReload)
1684 d->m_doc->docLoader()->setCachePolicy(KIO::CC_Verify);
1685 else
1686 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
1687
1688 d->m_workingURL = KUrl();
1689
1690 d->m_cacheId = KHTMLPageCache::self()->createCacheEntry();
1691
1692 // When the first data arrives, the metadata has just been made available
1693 d->m_httpHeaders = d->m_job->queryMetaData("HTTP-Headers");
1694 time_t cacheCreationDate = d->m_job->queryMetaData("cache-creation-date").toLong();
1695 d->m_doc->docLoader()->setCacheCreationDate(cacheCreationDate);
1696
1697 d->m_pageServices = d->m_job->queryMetaData("PageServices");
1698 d->m_pageReferrer = d->m_job->queryMetaData("referrer");
1699 d->m_ssl_in_use = (d->m_job->queryMetaData("ssl_in_use") == "TRUE");
1700
1701 {
1702 KHTMLPart *p = parentPart();
1703 if (p && p->d->m_ssl_in_use != d->m_ssl_in_use) {
1704 while (p->parentPart()) p = p->parentPart();
1705
1706 p->setPageSecurity( NotCrypted );
1707 }
1708 }
1709
1710 setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
1711
1712 // Shouldn't all of this be done only if ssl_in_use == true ? (DF)
1713 d->m_ssl_parent_ip = d->m_job->queryMetaData("ssl_parent_ip");
1714 d->m_ssl_parent_cert = d->m_job->queryMetaData("ssl_parent_cert");
1715 d->m_ssl_peer_chain = d->m_job->queryMetaData("ssl_peer_chain");
1716 d->m_ssl_peer_ip = d->m_job->queryMetaData("ssl_peer_ip");
1717 d->m_ssl_cipher = d->m_job->queryMetaData("ssl_cipher");
1718 d->m_ssl_protocol_version = d->m_job->queryMetaData("ssl_protocol_version");
1719 d->m_ssl_cipher_used_bits = d->m_job->queryMetaData("ssl_cipher_used_bits");
1720 d->m_ssl_cipher_bits = d->m_job->queryMetaData("ssl_cipher_bits");
1721 d->m_ssl_cert_errors = d->m_job->queryMetaData("ssl_cert_errors");
1722
1723 // Check for charset meta-data
1724 QString qData = d->m_job->queryMetaData("charset");
1725 if ( !qData.isEmpty() && !d->m_haveEncoding ) // only use information if the user didn't override the settings
1726 d->m_encoding = qData;
1727
1728
1729 // Support for http-refresh
1730 qData = d->m_job->queryMetaData("http-refresh");
1731 if( !qData.isEmpty())
1732 d->m_doc->processHttpEquiv("refresh", qData);
1733
1734 // DISABLED: Support Content-Location per section 14.14 of RFC 2616.
1735 // See BR# 51185,BR# 82747
1736 /*
1737 QString baseURL = d->m_job->queryMetaData ("content-location");
1738 if (!baseURL.isEmpty())
1739 d->m_doc->setBaseURL(KUrl( d->m_doc->completeURL(baseURL) ));
1740 */
1741
1742 // Support for Content-Language
1743 QString language = d->m_job->queryMetaData("content-language");
1744 if (!language.isEmpty())
1745 d->m_doc->setContentLanguage(language);
1746
1747 if ( !url().isLocalFile() )
1748 {
1749 // Support for http last-modified
1750 d->m_lastModified = d->m_job->queryMetaData("modified");
1751 }
1752 else
1753 d->m_lastModified.clear(); // done on-demand by lastModified()
1754 }
1755
1756 KHTMLPageCache::self()->addData(d->m_cacheId, data);
1757 write( data.data(), data.size() );
1758}
1759
1760void KHTMLPart::slotRestoreData(const QByteArray &data )
1761{
1762 // The first data ?
1763 if ( !d->m_workingURL.isEmpty() )
1764 {
1765 long saveCacheId = d->m_cacheId;
1766 QString savePageReferrer = d->m_pageReferrer;
1767 QString saveEncoding = d->m_encoding;
1768 begin( d->m_workingURL, arguments().xOffset(), arguments().yOffset() );
1769 d->m_encoding = saveEncoding;
1770 d->m_pageReferrer = savePageReferrer;
1771 d->m_cacheId = saveCacheId;
1772 d->m_workingURL = KUrl();
1773 }
1774
1775 //kDebug( 6050 ) << data.size();
1776 write( data.data(), data.size() );
1777
1778 if (data.size() == 0)
1779 {
1780 //kDebug( 6050 ) << "<<end of data>>";
1781 // End of data.
1782 if (d->m_doc && d->m_doc->parsing())
1783 end(); //will emit completed()
1784 }
1785}
1786
1787void KHTMLPart::showError( KJob* job )
1788{
1789 kDebug(6050) << "d->m_bParsing=" << (d->m_doc && d->m_doc->parsing()) << " d->m_bComplete=" << d->m_bComplete
1790 << " d->m_bCleared=" << d->m_bCleared;
1791
1792 if (job->error() == KIO::ERR_NO_CONTENT)
1793 return;
1794
1795 if ( (d->m_doc && d->m_doc->parsing()) || d->m_workingURL.isEmpty() ) // if we got any data already
1796 job->uiDelegate()->showErrorMessage();
1797 else
1798 {
1799 htmlError( job->error(), job->errorText(), d->m_workingURL );
1800 }
1801}
1802
1803// This is a protected method, placed here because of it's relevance to showError
1804void KHTMLPart::htmlError( int errorCode, const QString& text, const KUrl& reqUrl )
1805{
1806 kDebug(6050) << "errorCode" << errorCode << "text" << text;
1807 // make sure we're not executing any embedded JS
1808 bool bJSFO = d->m_bJScriptForce;
1809 bool bJSOO = d->m_bJScriptOverride;
1810 d->m_bJScriptForce = false;
1811 d->m_bJScriptOverride = true;
1812 begin();
1813
1814 QString errorName, techName, description;
1815 QStringList causes, solutions;
1816
1817 QByteArray raw = KIO::rawErrorDetail( errorCode, text, &reqUrl );
1818 QDataStream stream(raw);
1819
1820 stream >> errorName >> techName >> description >> causes >> solutions;
1821
1822 QString url, protocol, datetime;
1823
1824 // This is somewhat confusing, but we have to escape the externally-
1825 // controlled URL twice: once for i18n, and once for HTML.
1826 url = Qt::escape( Qt::escape( reqUrl.prettyUrl() ) );
1827 protocol = reqUrl.protocol();
1828 datetime = KGlobal::locale()->formatDateTime( QDateTime::currentDateTime(),
1829 KLocale::LongDate );
1830
1831 QString filename( KStandardDirs::locate( "data", "khtml/error.html" ) );
1832 QFile file( filename );
1833 bool isOpened = file.open( QIODevice::ReadOnly );
1834 if ( !isOpened )
1835 kWarning(6050) << "Could not open error html template:" << filename;
1836
1837 QString html = QString( QLatin1String( file.readAll() ) );
1838
1839 html.replace( QLatin1String( "TITLE" ), i18n( "Error: %1 - %2", errorName, url ) );
1840 html.replace( QLatin1String( "DIRECTION" ), QApplication::isRightToLeft() ? "rtl" : "ltr" );
1841 html.replace( QLatin1String( "ICON_PATH" ), KIconLoader::global()->iconPath( "dialog-warning", -KIconLoader::SizeHuge ) );
1842
1843 QString doc = QLatin1String( "<h1>" );
1844 doc += i18n( "The requested operation could not be completed" );
1845 doc += QLatin1String( "</h1><h2>" );
1846 doc += errorName;
1847 doc += QLatin1String( "</h2>" );
1848 if ( !techName.isNull() ) {
1849 doc += QLatin1String( "<h2>" );
1850 doc += i18n( "Technical Reason: " );
1851 doc += techName;
1852 doc += QLatin1String( "</h2>" );
1853 }
1854 doc += QLatin1String( "<br clear=\"all\">" );
1855 doc += QLatin1String( "<h3>" );
1856 doc += i18n( "Details of the Request:" );
1857 doc += QLatin1String( "</h3><ul><li>" );
1858 doc += i18n( "URL: %1" , url );
1859 doc += QLatin1String( "</li><li>" );
1860 if ( !protocol.isNull() ) {
1861 doc += i18n( "Protocol: %1", protocol );
1862 doc += QLatin1String( "</li><li>" );
1863 }
1864 doc += i18n( "Date and Time: %1" , datetime );
1865 doc += QLatin1String( "</li><li>" );
1866 doc += i18n( "Additional Information: %1" , text );
1867 doc += QLatin1String( "</li></ul><h3>" );
1868 doc += i18n( "Description:" );
1869 doc += QLatin1String( "</h3><p>" );
1870 doc += description;
1871 doc += QLatin1String( "</p>" );
1872 if ( causes.count() ) {
1873 doc += QLatin1String( "<h3>" );
1874 doc += i18n( "Possible Causes:" );
1875 doc += QLatin1String( "</h3><ul><li>" );
1876 doc += causes.join( "</li><li>" );
1877 doc += QLatin1String( "</li></ul>" );
1878 }
1879 if ( solutions.count() ) {
1880 doc += QLatin1String( "<h3>" );
1881 doc += i18n( "Possible Solutions:" );
1882 doc += QLatin1String( "</h3><ul><li>" );
1883 doc += solutions.join( "</li><li>" );
1884 doc += QLatin1String( "</li></ul>" );
1885 }
1886
1887 html.replace( QLatin1String("TEXT"), doc );
1888
1889 write( html );
1890 end();
1891
1892 d->m_bJScriptForce = bJSFO;
1893 d->m_bJScriptOverride = bJSOO;
1894
1895 // make the working url the current url, so that reload works and
1896 // emit the progress signals to advance one step in the history
1897 // (so that 'back' works)
1898 setUrl(reqUrl); // same as d->m_workingURL
1899 d->m_workingURL = KUrl();
1900 emit started( 0 );
1901 emit completed();
1902}
1903
1904void KHTMLPart::slotFinished( KJob * job )
1905{
1906 d->m_job = 0L;
1907 d->m_jobspeed = 0L;
1908
1909 if (job->error())
1910 {
1911 KHTMLPageCache::self()->cancelEntry(d->m_cacheId);
1912
1913 // The following catches errors that occur as a result of HTTP
1914 // to FTP redirections where the FTP URL is a directory. Since
1915 // KIO cannot change a redirection request from GET to LISTDIR,
1916 // we have to take care of it here once we know for sure it is
1917 // a directory...
1918 if (job->error() == KIO::ERR_IS_DIRECTORY)
1919 {
1920 emit canceled( job->errorString() );
1921 emit d->m_extension->openUrlRequest( d->m_workingURL );
1922 }
1923 else
1924 {
1925 emit canceled( job->errorString() );
1926 // TODO: what else ?
1927 checkCompleted();
1928 showError( job );
1929 }
1930
1931 return;
1932 }
1933 KIO::TransferJob *tjob = ::qobject_cast<KIO::TransferJob*>(job);
1934 if (tjob && tjob->isErrorPage()) {
1935 HTMLPartContainerElementImpl *elt = d->m_frame ?
1936 d->m_frame->m_partContainerElement.data() : 0;
1937
1938 if (!elt)
1939 return;
1940
1941 elt->partLoadingErrorNotify();
1942 checkCompleted();
1943 if (d->m_bComplete) return;
1944 }
1945
1946 //kDebug( 6050 ) << "slotFinished";
1947
1948 KHTMLPageCache::self()->endData(d->m_cacheId);
1949
1950 if ( d->m_doc && d->m_doc->docLoader()->expireDate() && url().protocol().startsWith("http"))
1951 KIO::http_update_cache(url(), false, d->m_doc->docLoader()->expireDate());
1952
1953 d->m_workingURL = KUrl();
1954
1955 if ( d->m_doc && d->m_doc->parsing())
1956 end(); //will emit completed()
1957}
1958
1959MimeType KHTMLPartPrivate::classifyMimeType(const QString& mimeStr)
1960{
1961 // See HTML5's "5.5.1 Navigating across documents" section.
1962 if (mimeStr == "application/xhtml+xml")
1963 return MimeXHTML;
1964 if (mimeStr == "image/svg+xml")
1965 return MimeSVG;
1966 if (mimeStr == "text/html" || mimeStr.isEmpty())
1967 return MimeHTML;
1968
1969 KMimeType::Ptr mime = KMimeType::mimeType(mimeStr, KMimeType::ResolveAliases);
1970 if ((mime && mime->is("text/xml")) || mimeStr.endsWith("+xml"))
1971 return MimeXML;
1972
1973 if (mime && mime->is("text/plain"))
1974 return MimeText;
1975
1976 if (khtmlImLoad::ImageManager::loaderDatabase()->supportedMimeTypes().contains(mimeStr))
1977 return MimeImage;
1978
1979 // Sometimes our subclasses like to handle custom mimetypes. In that case,
1980 // we want to handle them as HTML. We do that in the following cases:
1981 // 1) We're at top-level, so we were forced to open something
1982 // 2) We're an object --- this again means we were forced to open something,
1983 // as an iframe-generating-an-embed case would have us as an iframe
1984 if (!q->parentPart() || (m_frame && m_frame->m_type == khtml::ChildFrame::Object))
1985 return MimeHTML;
1986
1987 return MimeOther;
1988}
1989
1990void KHTMLPart::begin( const KUrl &url, int xOffset, int yOffset )
1991{
1992 if ( d->m_view->underMouse() )
1993 QToolTip::hideText(); // in case a previous tooltip is still shown
1994
1995 // No need to show this for a new page until an error is triggered
1996 if (!parentPart()) {
1997 removeJSErrorExtension();
1998 setSuppressedPopupIndicator( false );
1999 d->m_openableSuppressedPopups = 0;
2000 foreach ( KHTMLPart* part, d->m_suppressedPopupOriginParts ) {
2001 if (part) {
2002 KJS::Window *w = KJS::Window::retrieveWindow( part );
2003 if (w)
2004 w->forgetSuppressedWindows();
2005 }
2006 }
2007 }
2008
2009 d->m_bCleared = false;
2010 d->m_cacheId = 0;
2011 d->m_bComplete = false;
2012 d->m_bLoadEventEmitted = false;
2013 clear();
2014 d->m_bCleared = false;
2015
2016 if(url.isValid()) {
2017 QString urlString = url.url();
2018 KHTMLGlobal::vLinks()->insert( urlString );
2019 QString urlString2 = url.prettyUrl();
2020 if ( urlString != urlString2 ) {
2021 KHTMLGlobal::vLinks()->insert( urlString2 );
2022 }
2023 }
2024
2025 // ###
2026 //stopParser();
2027
2028 KParts::OpenUrlArguments args = arguments();
2029 args.setXOffset(xOffset);
2030 args.setYOffset(yOffset);
2031 setArguments(args);
2032
2033 d->m_pageReferrer.clear();
2034 d->m_referrer = url.protocol().startsWith("http") ? url.url() : "";
2035
2036 setUrl(url);
2037
2038 // Note: by now, any special mimetype besides plaintext would have been
2039 // handled specially inside openURL, so we handle their cases the same
2040 // as HTML.
2041 MimeType type = d->classifyMimeType(args.mimeType());
2042 switch (type) {
2043 case MimeSVG:
2044 d->m_doc = DOMImplementationImpl::createSVGDocument( d->m_view );
2045 break;
2046 case MimeXML: // any XML derivative, except XHTML or SVG
2047 // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl
2048 d->m_doc = DOMImplementationImpl::createXMLDocument( d->m_view );
2049 break;
2050 case MimeText:
2051 d->m_doc = new HTMLTextDocumentImpl( d->m_view );
2052 break;
2053 case MimeXHTML:
2054 case MimeHTML:
2055 default:
2056 d->m_doc = DOMImplementationImpl::createHTMLDocument( d->m_view );
2057 // HTML or XHTML? (#86446)
2058 static_cast<HTMLDocumentImpl *>(d->m_doc)->setHTMLRequested( type != MimeXHTML );
2059 }
2060
2061 d->m_doc->ref();
2062 d->m_doc->setURL( url.url() );
2063 d->m_doc->open( );
2064 if (!d->m_doc->attached())
2065 d->m_doc->attach( );
2066 d->m_doc->setBaseURL( KUrl() );
2067 d->m_doc->docLoader()->setShowAnimations( KHTMLGlobal::defaultHTMLSettings()->showAnimations() );
2068 emit docCreated();
2069
2070 d->m_paUseStylesheet->setItems(QStringList());
2071 d->m_paUseStylesheet->setEnabled( false );
2072
2073 setAutoloadImages( KHTMLGlobal::defaultHTMLSettings()->autoLoadImages() );
2074 QString userStyleSheet = KHTMLGlobal::defaultHTMLSettings()->userStyleSheet();
2075 if ( !userStyleSheet.isEmpty() )
2076 setUserStyleSheet( KUrl( userStyleSheet ) );
2077
2078 d->m_doc->setRestoreState(d->m_extension->browserArguments().docState);
2079 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2080
2081 emit d->m_extension->enableAction( "print", true );
2082
2083 d->m_doc->setParsing(true);
2084}
2085
2086void KHTMLPart::write( const char *data, int len )
2087{
2088 if ( !d->m_decoder )
2089 d->m_decoder = createDecoder();
2090
2091 if ( len == -1 )
2092 len = strlen( data );
2093
2094 if ( len == 0 )
2095 return;
2096
2097 QString decoded=d->m_decoder->decodeWithBuffering(data,len);
2098
2099 if(decoded.isEmpty())
2100 return;
2101
2102 if(d->m_bFirstData)
2103 onFirstData();
2104
2105 khtml::Tokenizer* t = d->m_doc->tokenizer();
2106 if(t)
2107 t->write( decoded, true );
2108}
2109
2110// ### KDE5: remove
2111void KHTMLPart::setAlwaysHonourDoctype( bool b )
2112{
2113 d->m_bStrictModeQuirk = !b;
2114}
2115
2116void KHTMLPart::write( const QString &str )
2117{
2118 if ( str.isNull() )
2119 return;
2120
2121 if(d->m_bFirstData) {
2122 // determine the parse mode
2123 if (d->m_bStrictModeQuirk) {
2124 d->m_doc->setParseMode( DocumentImpl::Strict );
2125 d->m_bFirstData = false;
2126 } else {
2127 onFirstData();
2128 }
2129 }
2130 khtml::Tokenizer* t = d->m_doc->tokenizer();
2131 if(t)
2132 t->write( str, true );
2133}
2134
2135void KHTMLPart::end()
2136{
2137 if (d->m_doc) {
2138 if (d->m_decoder)
2139 {
2140 QString decoded=d->m_decoder->flush();
2141 if (d->m_bFirstData)
2142 onFirstData();
2143 if (!decoded.isEmpty())
2144 write(decoded);
2145 }
2146 d->m_doc->finishParsing();
2147 }
2148}
2149
2150void KHTMLPart::onFirstData()
2151{
2152 assert( d->m_bFirstData );
2153
2154 // determine the parse mode
2155 d->m_doc->determineParseMode();
2156 d->m_bFirstData = false;
2157
2158 // ### this is still quite hacky, but should work a lot better than the old solution
2159 // Note: decoder may be null if only write(QString) is used.
2160 if (d->m_decoder && d->m_decoder->visuallyOrdered())
2161 d->m_doc->setVisuallyOrdered();
2162 // ensure part and view shares zoom-level before styling
2163 updateZoomFactor();
2164 d->m_doc->recalcStyle( NodeImpl::Force );
2165}
2166
2167bool KHTMLPart::doOpenStream( const QString& mimeType )
2168{
2169 KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases);
2170 if ( mime && ( mime->is( "text/html" ) || mime->is( "text/xml" ) ) )
2171 {
2172 begin( url() );
2173 return true;
2174 }
2175 return false;
2176}
2177
2178bool KHTMLPart::doWriteStream( const QByteArray& data )
2179{
2180 write( data.data(), data.size() );
2181 return true;
2182}
2183
2184bool KHTMLPart::doCloseStream()
2185{
2186 end();
2187 return true;
2188}
2189
2190
2191void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
2192{
2193 if (!d->m_view) return;
2194 d->m_view->paint(p, rc, yOff, more);
2195}
2196
2197void KHTMLPart::stopAnimations()
2198{
2199 if ( d->m_doc )
2200 d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
2201
2202 ConstFrameIt it = d->m_frames.constBegin();
2203 const ConstFrameIt end = d->m_frames.constEnd();
2204 for (; it != end; ++it ) {
2205 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
2206 p->stopAnimations();
2207 }
2208}
2209
2210void KHTMLPart::resetFromScript()
2211{
2212 closeUrl();
2213 d->m_bComplete = false;
2214 d->m_bLoadEventEmitted = false;
2215 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2216 connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2217 d->m_doc->setParsing(true);
2218
2219 emit started( 0L );
2220}
2221
2222void KHTMLPart::slotFinishedParsing()
2223{
2224 d->m_doc->setParsing(false);
2225 d->m_doc->dispatchHTMLEvent(EventImpl::KHTML_CONTENTLOADED_EVENT, true, false);
2226 checkEmitLoadEvent();
2227 disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2228
2229 if (!d->m_view)
2230 return; // We are probably being destructed.
2231
2232 checkCompleted();
2233}
2234
2235void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
2236{
2237 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
2238 KHTMLPart* p = this;
2239 while ( p ) {
2240 KHTMLPart* const op = p;
2241 ++(p->d->m_totalObjectCount);
2242 p = p->parentPart();
2243 if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount
2244 && !op->d->m_progressUpdateTimer.isActive()) {
2245 op->d->m_progressUpdateTimer.setSingleShot( true );
2246 op->d->m_progressUpdateTimer.start( 200 );
2247 }
2248 }
2249 }
2250}
2251
2252static bool isAncestorOrSamePart(KHTMLPart* p1, KHTMLPart* p2)
2253{
2254 KHTMLPart* p = p2;
2255 do {
2256 if (p == p1)
2257 return true;
2258 } while ((p = p->parentPart()));
2259 return false;
2260}
2261
2262void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
2263{
2264 if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
2265 KHTMLPart* p = this;
2266 while ( p ) {
2267 KHTMLPart* const op = p;
2268 ++(p->d->m_loadedObjects);
2269 p = p->parentPart();
2270 if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount && op->d->m_jobPercent <= 100
2271 && !op->d->m_progressUpdateTimer.isActive()) {
2272 op->d->m_progressUpdateTimer.setSingleShot( true );
2273 op->d->m_progressUpdateTimer.start( 200 );
2274 }
2275 }
2276 }
2277 /// if we have no document, or the object is not a request of one of our children,
2278 // then our loading state can't possibly be affected : don't waste time checking for completion.
2279 if (!d->m_doc || !dl->doc()->part() || !isAncestorOrSamePart(this, dl->doc()->part()))
2280 return;
2281 checkCompleted();
2282}
2283
2284void KHTMLPart::slotProgressUpdate()
2285{
2286 int percent;
2287 if ( d->m_loadedObjects < d->m_totalObjectCount )
2288 percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
2289 else
2290 percent = d->m_jobPercent;
2291
2292 if( d->m_bComplete )
2293 percent = 100;
2294
2295 if (d->m_statusMessagesEnabled) {
2296 if( d->m_bComplete )
2297 emit d->m_extension->infoMessage( i18n( "Page loaded." ));
2298 else if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
2299 emit d->m_extension->infoMessage( i18np( "%1 Image of %2 loaded.", "%1 Images of %2 loaded.", d->m_loadedObjects, d->m_totalObjectCount) );
2300 }
2301
2302 emit d->m_extension->loadingProgress( percent );
2303}
2304
2305void KHTMLPart::slotJobSpeed( KJob* /*job*/, unsigned long speed )
2306{
2307 d->m_jobspeed = speed;
2308 if (!parentPart())
2309 setStatusBarText(jsStatusBarText(), BarOverrideText);
2310}
2311
2312void KHTMLPart::slotJobPercent( KJob* /*job*/, unsigned long percent )
2313{
2314 d->m_jobPercent = percent;
2315
2316 if ( !parentPart() ) {
2317 d->m_progressUpdateTimer.setSingleShot( true );
2318 d->m_progressUpdateTimer.start( 0 );
2319 }
2320}
2321
2322void KHTMLPart::slotJobDone( KJob* /*job*/ )
2323{
2324 d->m_jobPercent = 100;
2325
2326 if ( !parentPart() ) {
2327 d->m_progressUpdateTimer.setSingleShot( true );
2328 d->m_progressUpdateTimer.start( 0 );
2329 }
2330}
2331
2332void KHTMLPart::slotUserSheetStatDone( KJob *_job )
2333{
2334 using namespace KIO;
2335
2336 if ( _job->error() ) {
2337 showError( _job );
2338 return;
2339 }
2340
2341 const UDSEntry entry = dynamic_cast<KIO::StatJob *>( _job )->statResult();
2342 const time_t lastModified = entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, -1 );
2343
2344 // If the filesystem supports modification times, only reload the
2345 // user-defined stylesheet if necessary - otherwise always reload.
2346 if ( lastModified != static_cast<time_t>(-1) ) {
2347 if ( d->m_userStyleSheetLastModified >= lastModified ) {
2348 return;
2349 }
2350 d->m_userStyleSheetLastModified = lastModified;
2351 }
2352
2353 setUserStyleSheet( KUrl( settings()->userStyleSheet() ) );
2354}
2355
2356bool KHTMLPartPrivate::isFullyLoaded(bool* pendingRedirections) const
2357{
2358 *pendingRedirections = false;
2359
2360 // Any frame that hasn't completed yet ?
2361 ConstFrameIt it = m_frames.constBegin();
2362 const ConstFrameIt end = m_frames.constEnd();
2363 for (; it != end; ++it ) {
2364 if ( !(*it)->m_bCompleted || (*it)->m_run )
2365 {
2366 //kDebug( 6050 ) << this << " is waiting for " << (*it)->m_part;
2367 return false;
2368 }
2369 // Check for frames with pending redirections
2370 if ( (*it)->m_bPendingRedirection )
2371 *pendingRedirections = true;
2372 }
2373
2374 // Any object that hasn't completed yet ?
2375 {
2376 ConstFrameIt oi = m_objects.constBegin();
2377 const ConstFrameIt oiEnd = m_objects.constEnd();
2378
2379 for (; oi != oiEnd; ++oi )
2380 if ( !(*oi)->m_bCompleted )
2381 return false;
2382 }
2383
2384 // Are we still parsing
2385 if ( m_doc && m_doc->parsing() )
2386 return false;
2387
2388 // Still waiting for images/scripts from the loader ?
2389 int requests = 0;
2390 if ( m_doc && m_doc->docLoader() )
2391 requests = khtml::Cache::loader()->numRequests( m_doc->docLoader() );
2392
2393 if ( requests > 0 )
2394 {
2395 //kDebug(6050) << "still waiting for images/scripts from the loader - requests:" << requests;
2396 return false;
2397 }
2398
2399 return true;
2400}
2401
2402void KHTMLPart::checkCompleted()
2403{
2404// kDebug( 6050 ) << this;
2405// kDebug( 6050 ) << " parsing: " << (d->m_doc && d->m_doc->parsing());
2406// kDebug( 6050 ) << " complete: " << d->m_bComplete;
2407
2408 // restore the cursor position
2409 if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
2410 {
2411 if (d->m_focusNodeNumber >= 0)
2412 d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
2413
2414 d->m_focusNodeRestored = true;
2415 }
2416
2417 bool fullyLoaded, pendingChildRedirections;
2418 fullyLoaded = d->isFullyLoaded(&pendingChildRedirections);
2419
2420 // Are we still loading, or already have done the relevant work?
2421 if (!fullyLoaded || d->m_bComplete)
2422 return;
2423
2424 // OK, completed.
2425 // Now do what should be done when we are really completed.
2426 d->m_bComplete = true;
2427 d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
2428 d->m_totalObjectCount = 0;
2429 d->m_loadedObjects = 0;
2430
2431 KHTMLPart* p = this;
2432 while ( p ) {
2433 KHTMLPart* op = p;
2434 p = p->parentPart();
2435 if ( !p && !op->d->m_progressUpdateTimer.isActive()) {
2436 op->d->m_progressUpdateTimer.setSingleShot( true );
2437 op->d->m_progressUpdateTimer.start( 0 );
2438 }
2439 }
2440
2441 checkEmitLoadEvent(); // if we didn't do it before
2442
2443 bool pendingAction = false;
2444
2445 if ( !d->m_redirectURL.isEmpty() )
2446 {
2447 // DA: Do not start redirection for frames here! That action is
2448 // deferred until the parent emits a completed signal.
2449 if ( parentPart() == 0 ) {
2450 //kDebug(6050) << this << " starting redirection timer";
2451 d->m_redirectionTimer.setSingleShot( true );
2452 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
2453 } else {
2454 //kDebug(6050) << this << " not toplevel -> not starting redirection timer. Waiting for slotParentCompleted.";
2455 }
2456
2457 pendingAction = true;
2458 }
2459 else if ( pendingChildRedirections )
2460 {
2461 pendingAction = true;
2462 }
2463
2464 // the view will emit completed on our behalf,
2465 // either now or at next repaint if one is pending
2466
2467 //kDebug(6050) << this << " asks the view to emit completed. pendingAction=" << pendingAction;
2468 d->m_view->complete( pendingAction );
2469
2470 // find the alternate stylesheets
2471 QStringList sheets;
2472 if (d->m_doc)
2473 sheets = d->m_doc->availableStyleSheets();
2474 sheets.prepend( i18n( "Automatic Detection" ) );
2475 d->m_paUseStylesheet->setItems( sheets );
2476
2477 d->m_paUseStylesheet->setEnabled( sheets.count() > 2);
2478 if (sheets.count() > 2)
2479 {
2480 d->m_paUseStylesheet->setCurrentItem(qMax(sheets.indexOf(d->m_sheetUsed), 0));
2481 slotUseStylesheet();
2482 }
2483
2484 setJSDefaultStatusBarText(QString());
2485
2486#ifdef SPEED_DEBUG
2487 if (!parentPart())
2488 kDebug(6080) << "DONE:" <<d->m_parsetime.elapsed();
2489#endif
2490}
2491
2492void KHTMLPart::checkEmitLoadEvent()
2493{
2494 bool fullyLoaded, pendingChildRedirections;
2495 fullyLoaded = d->isFullyLoaded(&pendingChildRedirections);
2496
2497 // ### might want to wait on pendingChildRedirections here, too
2498 if ( d->m_bLoadEventEmitted || !d->m_doc || !fullyLoaded ) return;
2499
2500 d->m_bLoadEventEmitted = true;
2501 if (d->m_doc)
2502 d->m_doc->close();
2503}
2504
2505const KHTMLSettings *KHTMLPart::settings() const
2506{
2507 return d->m_settings;
2508}
2509
2510#ifndef KDE_NO_COMPAT // KDE5: remove this ifndef, keep the method (renamed to baseUrl)
2511KUrl KHTMLPart::baseURL() const
2512{
2513 if ( !d->m_doc ) return KUrl();
2514
2515 return d->m_doc->baseURL();
2516}
2517#endif
2518
2519KUrl KHTMLPart::completeURL( const QString &url )
2520{
2521 if ( !d->m_doc ) return KUrl( url );
2522
2523#if 0
2524 if (d->m_decoder)
2525 return KUrl(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
2526#endif
2527
2528 return KUrl( d->m_doc->completeURL( url ) );
2529}
2530
2531QString KHTMLPartPrivate::codeForJavaScriptURL(const QString &u)
2532{
2533 return KUrl::fromPercentEncoding( u.right( u.length() - 11 ).toUtf8() );
2534}
2535
2536void KHTMLPartPrivate::executeJavascriptURL(const QString &u)
2537{
2538 QString script = codeForJavaScriptURL(u);
2539 kDebug( 6050 ) << "script=" << script;
2540 QVariant res = q->executeScript( DOM::Node(), script );
2541 if ( res.type() == QVariant::String ) {
2542 q->begin( q->url() );
2543 q->setAlwaysHonourDoctype(); // Disable public API compat; it messes with doctype
2544 q->write( res.toString() );
2545 q->end();
2546 }
2547 emit q->completed();
2548}
2549
2550bool KHTMLPartPrivate::isJavaScriptURL(const QString& url)
2551{
2552 return url.indexOf( QLatin1String( "javascript:" ), 0, Qt::CaseInsensitive ) == 0;
2553}
2554
2555// Called by ecma/kjs_window in case of redirections from Javascript,
2556// and by xml/dom_docimpl.cpp in case of http-equiv meta refresh.
2557void KHTMLPart::scheduleRedirection( int delay, const QString &url, bool doLockHistory )
2558{
2559 kDebug(6050) << "delay=" << delay << " url=" << url << " from=" << this->url() << "parent=" << parentPart();
2560 kDebug(6050) << "current redirectURL=" << d->m_redirectURL << " with delay " << d->m_delayRedirect;
2561
2562 // In case of JS redirections, some, such as jump to anchors, and javascript:
2563 // evaluation should actually be handled immediately, and not waiting until
2564 // the end of the script. (Besides, we don't want to abort the tokenizer for those)
2565 if ( delay == -1 && d->isInPageURL(url) ) {
2566 d->executeInPageURL(url, doLockHistory);
2567 return;
2568 }
2569
2570 if( delay < 24*60*60 &&
2571 ( d->m_redirectURL.isEmpty() || delay <= d->m_delayRedirect) ) {
2572 d->m_delayRedirect = delay;
2573 d->m_redirectURL = url;
2574 d->m_redirectLockHistory = doLockHistory;
2575 kDebug(6050) << " d->m_bComplete=" << d->m_bComplete;
2576
2577 if ( d->m_bComplete ) {
2578 d->m_redirectionTimer.stop();
2579 d->m_redirectionTimer.setSingleShot( true );
2580 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
2581 }
2582 }
2583}
2584
2585void KHTMLPartPrivate::clearRedirection()
2586{
2587 m_delayRedirect = 0;
2588 m_redirectURL.clear();
2589 m_redirectionTimer.stop();
2590}
2591
2592void KHTMLPart::slotRedirect()
2593{
2594 kDebug(6050) << this;
2595 QString u = d->m_redirectURL;
2596 KUrl url( u );
2597 d->clearRedirection();
2598
2599 if ( d->isInPageURL(u) )
2600 {
2601 d->executeInPageURL(u, d->m_redirectLockHistory);
2602 return;
2603 }
2604
2605 KParts::OpenUrlArguments args;
2606 KUrl cUrl( this->url() );
2607
2608 // handle windows opened by JS
2609 if ( openedByJS() && d->m_opener )
2610 cUrl = d->m_opener->url();
2611
2612 if (!KAuthorized::authorizeUrlAction("redirect", cUrl, url))
2613 {
2614 kWarning(6050) << "KHTMLPart::scheduleRedirection: Redirection from " << cUrl << " to " << url << " REJECTED!";
2615 emit completed();
2616 return;
2617 }
2618
2619 if ( url.equals(this->url(),
2620 KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment | KUrl::AllowEmptyPath) )
2621 {
2622 args.metaData().insert("referrer", d->m_pageReferrer);
2623 }
2624
2625 // For javascript and META-tag based redirections:
2626 // - We don't take cross-domain-ness in consideration if we are the
2627 // toplevel frame because the new URL may be in a different domain as the current URL
2628 // but that's ok.
2629 // - If we are not the toplevel frame then we check against the toplevelURL()
2630 if (parentPart())
2631 args.metaData().insert("cross-domain", toplevelURL().url());
2632
2633 KParts::BrowserArguments browserArgs;
2634 browserArgs.setLockHistory( d->m_redirectLockHistory );
2635 // _self: make sure we don't use any <base target=>'s
2636
2637 if ( !urlSelected( u, 0, 0, "_self", args, browserArgs ) ) {
2638 // urlSelected didn't open a url, so emit completed ourselves
2639 emit completed();
2640 }
2641}
2642
2643void KHTMLPart::slotRedirection(KIO::Job*, const KUrl& url)
2644{
2645 // the slave told us that we got redirected
2646 //kDebug( 6050 ) << "redirection by KIO to" << url;
2647 emit d->m_extension->setLocationBarUrl( url.prettyUrl() );
2648 d->m_workingURL = url;
2649}
2650
2651bool KHTMLPart::setEncoding( const QString &name, bool override )
2652{
2653 d->m_encoding = name;
2654 d->m_haveEncoding = override;
2655
2656 if( !url().isEmpty() ) {
2657 // reload document
2658 closeUrl();
2659 KUrl oldUrl = url();
2660 setUrl(KUrl());
2661 d->m_restored = true;
2662 openUrl(oldUrl);
2663 d->m_restored = false;
2664 }
2665
2666 return true;
2667}
2668
2669QString KHTMLPart::encoding() const
2670{
2671 if(d->m_haveEncoding && !d->m_encoding.isEmpty())
2672 return d->m_encoding;
2673
2674 if(d->m_decoder && d->m_decoder->encoding())
2675 return QString(d->m_decoder->encoding());
2676
2677 return defaultEncoding();
2678}
2679
2680QString KHTMLPart::defaultEncoding() const
2681{
2682 QString encoding = settings()->encoding();
2683 if ( !encoding.isEmpty() )
2684 return encoding;
2685 // HTTP requires the default encoding to be latin1, when neither
2686 // the user nor the page requested a particular encoding.
2687 if ( url().protocol().startsWith( "http" ) )
2688 return "iso-8859-1";
2689 else
2690 return KGlobal::locale()->encoding();
2691}
2692
2693void KHTMLPart::setUserStyleSheet(const KUrl &url)
2694{
2695 if ( d->m_doc && d->m_doc->docLoader() )
2696 (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
2697}
2698
2699void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
2700{
2701 if ( d->m_doc )
2702 d->m_doc->setUserStyleSheet( styleSheet );
2703}
2704
2705bool KHTMLPart::gotoAnchor( const QString &name )
2706{
2707 if (!d->m_doc)
2708 return false;
2709
2710 HTMLCollectionImpl *anchors =
2711 new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
2712 anchors->ref();
2713 NodeImpl *n = anchors->namedItem(name);
2714 anchors->deref();
2715
2716 if(!n) {
2717 n = d->m_doc->getElementById( name );
2718 }
2719
2720 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
2721
2722 // Implement the rule that "" and "top" both mean top of page as in other browsers.
2723 bool quirkyName = !n && !d->m_doc->inStrictMode() && (name.isEmpty() || name.toLower() == "top");
2724
2725 if (quirkyName) {
2726 d->m_view->setContentsPos( d->m_view->contentsX(), 0);
2727 return true;
2728 } else if (!n) {
2729 kDebug(6050) << name << "not found";
2730 return false;
2731 }
2732
2733 int x = 0, y = 0;
2734 int gox, dummy;
2735 HTMLElementImpl *a = static_cast<HTMLElementImpl *>(n);
2736
2737 a->getUpperLeftCorner(x, y);
2738 if (x <= d->m_view->contentsX())
2739 gox = x - 10;
2740 else {
2741 gox = d->m_view->contentsX();
2742 if ( x + 10 > d->m_view->contentsX()+d->m_view->visibleWidth()) {
2743 a->getLowerRightCorner(x, dummy);
2744 gox = x - d->m_view->visibleWidth() + 10;
2745 }
2746 }
2747
2748 d->m_view->setContentsPos(gox, y);
2749
2750 return true;
2751}
2752
2753bool KHTMLPart::nextAnchor()
2754{
2755 if (!d->m_doc)
2756 return false;
2757 d->m_view->focusNextPrevNode ( true );
2758
2759 return true;
2760}
2761
2762bool KHTMLPart::prevAnchor()
2763{
2764 if (!d->m_doc)
2765 return false;
2766 d->m_view->focusNextPrevNode ( false );
2767
2768 return true;
2769}
2770
2771void KHTMLPart::setStandardFont( const QString &name )
2772{
2773 d->m_settings->setStdFontName(name);
2774}
2775
2776void KHTMLPart::setFixedFont( const QString &name )
2777{
2778 d->m_settings->setFixedFontName(name);
2779}
2780
2781void KHTMLPart::setURLCursor( const QCursor &c )
2782{
2783 d->m_linkCursor = c;
2784}
2785
2786QCursor KHTMLPart::urlCursor() const
2787{
2788 return d->m_linkCursor;
2789}
2790
2791bool KHTMLPart::onlyLocalReferences() const
2792{
2793 return d->m_onlyLocalReferences;
2794}
2795
2796void KHTMLPart::setOnlyLocalReferences(bool enable)
2797{
2798 d->m_onlyLocalReferences = enable;
2799}
2800
2801bool KHTMLPart::forcePermitLocalImages() const
2802{
2803 return d->m_forcePermitLocalImages;
2804}
2805
2806void KHTMLPart::setForcePermitLocalImages(bool enable)
2807{
2808 d->m_forcePermitLocalImages = enable;
2809}
2810
2811void KHTMLPartPrivate::setFlagRecursively(
2812 bool KHTMLPartPrivate::*flag, bool value)
2813{
2814 // first set it on the current one
2815 this->*flag = value;
2816
2817 // descend into child frames recursively
2818 {
2819 QList<khtml::ChildFrame*>::Iterator it = m_frames.begin();
2820 const QList<khtml::ChildFrame*>::Iterator itEnd = m_frames.end();
2821 for (; it != itEnd; ++it) {
2822 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part.data() );
2823 if (part)
2824 part->d->setFlagRecursively(flag, value);
2825 }/*next it*/
2826 }
2827 // do the same again for objects
2828 {
2829 QList<khtml::ChildFrame*>::Iterator it = m_objects.begin();
2830 const QList<khtml::ChildFrame*>::Iterator itEnd = m_objects.end();
2831 for (; it != itEnd; ++it) {
2832 KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part.data() );
2833 if (part)
2834 part->d->setFlagRecursively(flag, value);
2835 }/*next it*/
2836 }
2837}
2838
2839void KHTMLPart::initCaret()
2840{
2841 // initialize caret if not used yet
2842 if (d->editor_context.m_selection.state() == Selection::NONE) {
2843 if (d->m_doc) {
2844 NodeImpl *node;
2845 if (d->m_doc->isHTMLDocument()) {
2846 HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
2847 node = htmlDoc->body();
2848 } else
2849 node = d->m_doc;
2850 if (!node) return;
2851 d->editor_context.m_selection.moveTo(Position(node, 0));
2852 d->editor_context.m_selection.setNeedsLayout();
2853 d->editor_context.m_selection.needsCaretRepaint();
2854 }
2855 }
2856}
2857
2858static void setCaretInvisibleIfNeeded(KHTMLPart *part)
2859{
2860 // On contenteditable nodes, don't hide the caret
2861 if (!khtml::KHTMLPartAccessor::caret(part).caretPos().node()->isContentEditable())
2862 part->setCaretVisible(false);
2863}
2864
2865void KHTMLPart::setCaretMode(bool enable)
2866{
2867 kDebug(6200) << enable;
2868 if (isCaretMode() == enable) return;
2869 d->setFlagRecursively(&KHTMLPartPrivate::m_caretMode, enable);
2870 // FIXME: this won't work on frames as expected
2871 if (!isEditable()) {
2872 if (enable) {
2873 initCaret();
2874 setCaretVisible(true);
2875// view()->ensureCaretVisible();
2876 } else {
2877 setCaretInvisibleIfNeeded(this);
2878 }
2879 }
2880}
2881
2882bool KHTMLPart::isCaretMode() const
2883{
2884 return d->m_caretMode;
2885}
2886
2887void KHTMLPart::setEditable(bool enable)
2888{
2889 if (isEditable() == enable) return;
2890 d->setFlagRecursively(&KHTMLPartPrivate::m_designMode, enable);
2891 // FIXME: this won't work on frames as expected
2892 if (!isCaretMode()) {
2893 if (enable) {
2894 initCaret();
2895 setCaretVisible(true);
2896// view()->ensureCaretVisible();
2897 } else
2898 setCaretInvisibleIfNeeded(this);
2899 }
2900}
2901
2902bool KHTMLPart::isEditable() const
2903{
2904 return d->m_designMode;
2905}
2906
2907khtml::EditorContext *KHTMLPart::editorContext() const {
2908 return &d->editor_context;
2909}
2910
2911void KHTMLPart::setCaretPosition(DOM::Node node, long offset, bool extendSelection)
2912{
2913 Q_UNUSED(node);
2914 Q_UNUSED(offset);
2915 Q_UNUSED(extendSelection);
2916#ifndef KHTML_NO_CARET
2917#if 0
2918 kDebug(6200) << "node: " << node.handle() << " nodeName: "
2919 << node.nodeName().string() << " offset: " << offset
2920 << " extendSelection " << extendSelection;
2921 if (view()->moveCaretTo(node.handle(), offset, !extendSelection))
2922 emitSelectionChanged();
2923 view()->ensureCaretVisible();
2924#endif
2925#endif // KHTML_NO_CARET
2926}
2927
2928KHTMLPart::CaretDisplayPolicy KHTMLPart::caretDisplayPolicyNonFocused() const
2929{
2930#if 0
2931#ifndef KHTML_NO_CARET
2932 return (CaretDisplayPolicy)view()->caretDisplayPolicyNonFocused();
2933#else // KHTML_NO_CARET
2934 return CaretInvisible;
2935#endif // KHTML_NO_CARET
2936#endif
2937 return CaretInvisible;
2938}
2939
2940void KHTMLPart::setCaretDisplayPolicyNonFocused(CaretDisplayPolicy policy)
2941{
2942 Q_UNUSED(policy);
2943#if 0
2944#ifndef KHTML_NO_CARET
2945 view()->setCaretDisplayPolicyNonFocused(policy);
2946#endif // KHTML_NO_CARET
2947#endif
2948}
2949
2950void KHTMLPart::setCaretVisible(bool show)
2951{
2952 if (show) {
2953 NodeImpl *caretNode = d->editor_context.m_selection.caretPos().node();
2954 if (isCaretMode() || (caretNode && caretNode->isContentEditable())) {
2955 invalidateSelection();
2956 enableFindAheadActions(false);
2957 }
2958 } else {
2959
2960 if (d->editor_context.m_caretBlinkTimer >= 0)
2961 killTimer(d->editor_context.m_caretBlinkTimer);
2962 clearCaretRectIfNeeded();
2963
2964 }
2965}
2966
2967void KHTMLPart::findTextBegin()
2968{
2969 d->m_find.findTextBegin();
2970}
2971
2972bool KHTMLPart::initFindNode( bool selection, bool reverse, bool fromCursor )
2973{
2974 return d->m_find.initFindNode(selection, reverse, fromCursor);
2975}
2976
2977void KHTMLPart::slotFind()
2978{
2979 KParts::ReadOnlyPart *part = currentFrame();
2980 if (!part)
2981 return;
2982 if (!part->inherits("KHTMLPart") )
2983 {
2984 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2985 return;
2986 }
2987 static_cast<KHTMLPart *>( part )->findText();
2988}
2989
2990void KHTMLPart::slotFindNext()
2991{
2992 KParts::ReadOnlyPart *part = currentFrame();
2993 if (!part)
2994 return;
2995 if (!part->inherits("KHTMLPart") )
2996 {
2997 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2998 return;
2999 }
3000 static_cast<KHTMLPart *>( part )->findTextNext();
3001}
3002
3003void KHTMLPart::slotFindPrev()
3004{
3005 KParts::ReadOnlyPart *part = currentFrame();
3006 if (!part)
3007 return;
3008 if (!part->inherits("KHTMLPart") )
3009 {
3010 kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
3011 return;
3012 }
3013 static_cast<KHTMLPart *>( part )->findTextNext( true ); // reverse
3014}
3015
3016void KHTMLPart::slotFindDone()
3017{
3018 // ### remove me
3019}
3020
3021void KHTMLPart::slotFindAheadText()
3022{
3023 KHTMLPart *part = qobject_cast<KHTMLPart*>(currentFrame());
3024 if (!part)
3025 return;
3026 part->findText();
3027 KHTMLFindBar* findBar = part->d->m_find.findBar();
3028 findBar->setOptions(findBar->options() & ~FindLinksOnly);
3029}
3030
3031void KHTMLPart::slotFindAheadLink()
3032{
3033 KHTMLPart *part = qobject_cast<KHTMLPart*>(currentFrame());
3034 if (!part)
3035 return;
3036 part->findText();
3037 KHTMLFindBar* findBar = part->d->m_find.findBar();
3038 findBar->setOptions(findBar->options() | FindLinksOnly);
3039}
3040
3041void KHTMLPart::enableFindAheadActions( bool )
3042{
3043 // ### remove me
3044}
3045
3046void KHTMLPart::slotFindDialogDestroyed()
3047{
3048 // ### remove me
3049}
3050
3051void KHTMLPart::findText()
3052{
3053 if (parentPart())
3054 return parentPart()->findText();
3055 d->m_find.activate();
3056}
3057
3058void KHTMLPart::findText( const QString &str, long options, QWidget *parent, KFindDialog *findDialog )
3059{
3060 if (parentPart())
3061 return parentPart()->findText(str, options, parent, findDialog);
3062 d->m_find.createNewKFind(str, options, parent, findDialog );
3063}
3064
3065// New method
3066bool KHTMLPart::findTextNext( bool reverse )
3067{
3068 if (parentPart())
3069 return parentPart()->findTextNext( reverse );
3070 return d->m_find.findTextNext( reverse );
3071}
3072
3073bool KHTMLPart::pFindTextNextInThisFrame( bool reverse )
3074{
3075 return d->m_find.findTextNext( reverse );
3076}
3077
3078QString KHTMLPart::selectedTextAsHTML() const
3079{
3080 const Selection &sel = d->editor_context.m_selection;
3081 if(!hasSelection()) {
3082 kDebug() << "Selection is not valid. Returning empty selection";
3083 return QString();
3084 }
3085 if(sel.start().offset() < 0 || sel.end().offset() < 0) {
3086 kDebug() << "invalid values for end/startOffset " << sel.start().offset() << " " << sel.end().offset();
3087 return QString();
3088 }
3089 DOM::Range r = selection();
3090 if(r.isNull() || r.isDetached())
3091 return QString();
3092 int exceptioncode = 0; //ignore the result
3093 return r.handle()->toHTML(exceptioncode).string();
3094}
3095
3096QString KHTMLPart::selectedText() const
3097{
3098 bool hasNewLine = true;
3099 bool seenTDTag = false;
3100 QString text;
3101 const Selection &sel = d->editor_context.m_selection;
3102 DOM::Node n = sel.start().node();
3103 while(!n.isNull()) {
3104 if(n.nodeType() == DOM::Node::TEXT_NODE && n.handle()->renderer()) {
3105 DOM::DOMStringImpl *dstr = static_cast<DOM::TextImpl*>(n.handle())->renderString();
3106 QString str(dstr->s, dstr->l);
3107 if(!str.isEmpty()) {
3108 if(seenTDTag) {
3109 text += " ";
3110 seenTDTag = false;
3111 }
3112 hasNewLine = false;
3113 if(n == sel.start().node() && n == sel.end().node()) {
3114 int s = khtml::RenderPosition::fromDOMPosition(sel.start()).renderedOffset();
3115 int e = khtml::RenderPosition::fromDOMPosition(sel.end()).renderedOffset();
3116 text = str.mid(s, e-s);
3117 } else if(n == sel.start().node()) {
3118 text = str.mid(khtml::RenderPosition::fromDOMPosition(sel.start()).renderedOffset());
3119 } else if(n == sel.end().node()) {
3120 text += str.left(khtml::RenderPosition::fromDOMPosition(sel.end()).renderedOffset());
3121 } else
3122 text += str;
3123 }
3124 }
3125 else {
3126 // This is our simple HTML -> ASCII transformation:
3127 unsigned short id = n.elementId();
3128 switch(id) {
3129 case ID_TEXTAREA:
3130 text += static_cast<HTMLTextAreaElementImpl*>(n.handle())->value().string();
3131 break;
3132 case ID_INPUT:
3133 if (static_cast<HTMLInputElementImpl*>(n.handle())->inputType() != HTMLInputElementImpl::PASSWORD)
3134 text += static_cast<HTMLInputElementImpl*>(n.handle())->value().string();
3135 break;
3136 case ID_SELECT:
3137 text += static_cast<HTMLSelectElementImpl*>(n.handle())->value().string();
3138 break;
3139 case ID_BR:
3140 text += "\n";
3141 hasNewLine = true;
3142 break;
3143 case ID_IMG:
3144 text += static_cast<HTMLImageElementImpl*>(n.handle())->altText().string();
3145 break;
3146 case ID_TD:
3147 break;
3148 case ID_TH:
3149 case ID_HR:
3150 case ID_OL:
3151 case ID_UL:
3152 case ID_LI:
3153 case ID_DD:
3154 case ID_DL:
3155 case ID_DT:
3156 case ID_PRE:
3157 case ID_LISTING:
3158 case ID_BLOCKQUOTE:
3159 case ID_DIV:
3160 if (!hasNewLine)
3161 text += "\n";
3162 hasNewLine = true;
3163 break;
3164 case ID_P:
3165 case ID_TR:
3166 case ID_H1:
3167 case ID_H2:
3168 case ID_H3:
3169 case ID_H4:
3170 case ID_H5:
3171 case ID_H6:
3172 if (!hasNewLine)
3173 text += "\n";
3174 hasNewLine = true;
3175 break;
3176 }
3177 }
3178 if(n == sel.end().node()) break;
3179 DOM::Node next = n.firstChild();
3180 if(next.isNull()) next = n.nextSibling();
3181 while( next.isNull() && !n.parentNode().isNull() ) {
3182 n = n.parentNode();
3183 next = n.nextSibling();
3184 unsigned short id = n.elementId();
3185 switch(id) {
3186 case ID_TD:
3187 seenTDTag = true; //Add two spaces after a td if then followed by text.
3188 break;
3189 case ID_TH:
3190 case ID_HR:
3191 case ID_OL:
3192 case ID_UL:
3193 case ID_LI:
3194 case ID_DD:
3195 case ID_DL:
3196 case ID_DT:
3197 case ID_PRE:
3198 case ID_LISTING:
3199 case ID_BLOCKQUOTE:
3200 case ID_DIV:
3201 seenTDTag = false;
3202 if (!hasNewLine)
3203 text += "\n";
3204 hasNewLine = true;
3205 break;
3206 case ID_P:
3207 case ID_TR:
3208 case ID_H1:
3209 case ID_H2:
3210 case ID_H3:
3211 case ID_H4:
3212 case ID_H5:
3213 case ID_H6:
3214 if (!hasNewLine)
3215 text += "\n";
3216// text += "\n";
3217 hasNewLine = true;
3218 break;
3219 }
3220 }
3221
3222 n = next;
3223 }
3224
3225 if(text.isEmpty())
3226 return QString();
3227
3228 int start = 0;
3229 int end = text.length();
3230
3231 // Strip leading LFs
3232 while ((start < end) && (text[start] == '\n'))
3233 ++start;
3234
3235 // Strip excessive trailing LFs
3236 while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n'))
3237 --end;
3238
3239 return text.mid(start, end-start);
3240}
3241
3242QString KHTMLPart::simplifiedSelectedText() const
3243{
3244 QString text = selectedText();
3245 text.replace(QChar(0xa0), ' ');
3246 // remove leading and trailing whitespace
3247 while (!text.isEmpty() && text[0].isSpace())
3248 text = text.mid(1);
3249 while (!text.isEmpty() && text[text.length()-1].isSpace())
3250 text.truncate(text.length()-1);
3251 return text;
3252}
3253
3254bool KHTMLPart::hasSelection() const
3255{
3256 return !d->editor_context.m_selection.isEmpty() && !d->editor_context.m_selection.isCollapsed();
3257}
3258
3259DOM::Range KHTMLPart::selection() const
3260{
3261 return d->editor_context.m_selection.toRange();
3262}
3263
3264void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const
3265{
3266 DOM::Range r = d->editor_context.m_selection.toRange();
3267 s = r.startContainer();
3268 so = r.startOffset();
3269 e = r.endContainer();
3270 eo = r.endOffset();
3271}
3272
3273void KHTMLPart::setSelection( const DOM::Range &r )
3274{
3275 setCaret(r);
3276}
3277
3278const Selection &KHTMLPart::caret() const
3279{
3280 return d->editor_context.m_selection;
3281}
3282
3283const Selection &KHTMLPart::dragCaret() const
3284{
3285 return d->editor_context.m_dragCaret;
3286}
3287
3288void KHTMLPart::setCaret(const Selection &s, bool closeTyping)
3289{
3290 if (d->editor_context.m_selection != s) {
3291 clearCaretRectIfNeeded();
3292 setFocusNodeIfNeeded(s);
3293 d->editor_context.m_selection = s;
3294 notifySelectionChanged(closeTyping);
3295 }
3296}
3297
3298void KHTMLPart::setDragCaret(const DOM::Selection &dragCaret)
3299{
3300 if (d->editor_context.m_dragCaret != dragCaret) {
3301 d->editor_context.m_dragCaret.needsCaretRepaint();
3302 d->editor_context.m_dragCaret = dragCaret;
3303 d->editor_context.m_dragCaret.needsCaretRepaint();
3304 }
3305}
3306
3307void KHTMLPart::clearSelection()
3308{
3309 clearCaretRectIfNeeded();
3310 setFocusNodeIfNeeded(d->editor_context.m_selection);
3311#ifdef APPLE_CHANGES
3312 d->editor_context.m_selection.clear();
3313#else
3314 d->editor_context.m_selection.collapse();
3315#endif
3316 notifySelectionChanged();
3317}
3318
3319void KHTMLPart::invalidateSelection()
3320{
3321 clearCaretRectIfNeeded();
3322 d->editor_context.m_selection.setNeedsLayout();
3323 selectionLayoutChanged();
3324}
3325
3326void KHTMLPart::setSelectionVisible(bool flag)
3327{
3328 if (d->editor_context.m_caretVisible == flag)
3329 return;
3330
3331 clearCaretRectIfNeeded();
3332 setFocusNodeIfNeeded(d->editor_context.m_selection);
3333 d->editor_context.m_caretVisible = flag;
3334// notifySelectionChanged();
3335}
3336
3337#if 1
3338void KHTMLPart::slotClearSelection()
3339{
3340 if (!isCaretMode()
3341 && d->editor_context.m_selection.state() != Selection::NONE
3342 && !d->editor_context.m_selection.caretPos().node()->isContentEditable())
3343 clearCaretRectIfNeeded();
3344 bool hadSelection = hasSelection();
3345#ifdef APPLE_CHANGES
3346 d->editor_context.m_selection.clear();
3347#else
3348 d->editor_context.m_selection.collapse();
3349#endif
3350 if (hadSelection)
3351 notifySelectionChanged();
3352}
3353#endif
3354
3355void KHTMLPart::clearCaretRectIfNeeded()
3356{
3357 if (d->editor_context.m_caretPaint) {
3358 d->editor_context.m_caretPaint = false;
3359 d->editor_context.m_selection.needsCaretRepaint();
3360 }
3361}
3362
3363void KHTMLPart::setFocusNodeIfNeeded(const Selection &s)
3364{
3365 if (!xmlDocImpl() || s.state() == Selection::NONE)
3366 return;
3367
3368 NodeImpl *n = s.start().node();
3369 NodeImpl *target = (n && n->isContentEditable()) ? n : 0;
3370 if (!target) {
3371 while (n && n != s.end().node()) {
3372 if (n->isContentEditable()) {
3373 target = n;
3374 break;
3375 }
3376 n = n->traverseNextNode();
3377 }
3378 }
3379 assert(target == 0 || target->isContentEditable());
3380
3381 if (target) {
3382 for ( ; target && !target->isFocusable(); target = target->parentNode())
3383 {}
3384 if (target && target->isMouseFocusable())
3385 xmlDocImpl()->setFocusNode(target);
3386 else if (!target || !target->focused())
3387 xmlDocImpl()->setFocusNode(0);
3388 }
3389}
3390
3391void KHTMLPart::selectionLayoutChanged()
3392{
3393 // kill any caret blink timer now running
3394 if (d->editor_context.m_caretBlinkTimer >= 0) {
3395 killTimer(d->editor_context.m_caretBlinkTimer);
3396 d->editor_context.m_caretBlinkTimer = -1;
3397 }
3398
3399 // see if a new caret blink timer needs to be started
3400 if (d->editor_context.m_caretVisible
3401 && d->editor_context.m_selection.state() != Selection::NONE) {
3402 d->editor_context.m_caretPaint = isCaretMode()
3403 || d->editor_context.m_selection.caretPos().node()->isContentEditable();
3404 if (d->editor_context.m_caretBlinks && d->editor_context.m_caretPaint)
3405 d->editor_context.m_caretBlinkTimer = startTimer(qApp->cursorFlashTime() / 2);
3406 d->editor_context.m_selection.needsCaretRepaint();
3407 // make sure that caret is visible
3408 QRect r(d->editor_context.m_selection.getRepaintRect());
3409 if (d->editor_context.m_caretPaint)
3410 d->m_view->ensureVisible(r.x(), r.y());
3411 }
3412
3413 if (d->m_doc)
3414 d->m_doc->updateSelection();
3415
3416 // Always clear the x position used for vertical arrow navigation.
3417 // It will be restored by the vertical arrow navigation code if necessary.
3418 d->editor_context.m_xPosForVerticalArrowNavigation = d->editor_context.NoXPosForVerticalArrowNavigation;
3419}
3420
3421void KHTMLPart::notifySelectionChanged(bool closeTyping)
3422{
3423 Editor *ed = d->editor_context.m_editor;
3424 selectionLayoutChanged();
3425 if (ed) {
3426 ed->clearTypingStyle();
3427
3428 if (closeTyping)
3429 ed->closeTyping();
3430 }
3431
3432 emitSelectionChanged();
3433}
3434
3435void KHTMLPart::timerEvent(QTimerEvent *e)
3436{
3437 if (e->timerId() == d->editor_context.m_caretBlinkTimer) {
3438 if (d->editor_context.m_caretBlinks &&
3439 d->editor_context.m_selection.state() != Selection::NONE) {
3440 d->editor_context.m_caretPaint = !d->editor_context.m_caretPaint;
3441 d->editor_context.m_selection.needsCaretRepaint();
3442 }
3443 } else if (e->timerId() == d->m_DNSPrefetchTimer) {
3444 // kDebug( 6050 ) << "will lookup " << d->m_DNSPrefetchQueue.head() << d->m_numDNSPrefetchedNames;
3445 KIO::HostInfo::prefetchHost( d->m_DNSPrefetchQueue.dequeue() );
3446 if (d->m_DNSPrefetchQueue.isEmpty()) {
3447 killTimer( d->m_DNSPrefetchTimer );
3448 d->m_DNSPrefetchTimer = -1;
3449 }
3450 } else if (e->timerId() == d->m_DNSTTLTimer) {
3451 foreach (const QString &name, d->m_lookedupHosts)
3452 d->m_DNSPrefetchQueue.enqueue(name);
3453 if (d->m_DNSPrefetchTimer <= 0)
3454 d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay );
3455 }
3456}
3457
3458bool KHTMLPart::mayPrefetchHostname( const QString& name )
3459{
3460 if (d->m_bDNSPrefetch == DNSPrefetchDisabled)
3461 return false;
3462
3463 if (d->m_numDNSPrefetchedNames >= sMaxDNSPrefetchPerPage)
3464 return false;
3465
3466 if (d->m_bDNSPrefetch == DNSPrefetchOnlyWWWAndSLD) {
3467 int dots = name.count('.');
3468 if (dots > 2 || (dots == 2 && !name.startsWith("www.")))
3469 return false;
3470 }
3471
3472 if ( d->m_lookedupHosts.contains( name ) )
3473 return false;
3474
3475 d->m_DNSPrefetchQueue.enqueue( name );
3476 d->m_lookedupHosts.insert( name );
3477 d->m_numDNSPrefetchedNames++;
3478
3479 if (d->m_DNSPrefetchTimer < 1)
3480 d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay );
3481 if (d->m_DNSTTLTimer < 1)
3482 d->m_DNSTTLTimer = startTimer( sDNSTTLSeconds*1000 + 1 );
3483
3484 return true;
3485}
3486
3487void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
3488{
3489 if (d->editor_context.m_caretPaint)
3490 d->editor_context.m_selection.paintCaret(p, rect);
3491}
3492
3493void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
3494{
3495 d->editor_context.m_dragCaret.paintCaret(p, rect);
3496}
3497
3498DOM::Editor *KHTMLPart::editor() const {
3499 if (!d->editor_context.m_editor)
3500 const_cast<KHTMLPart *>(this)->d->editor_context.m_editor = new DOM::Editor(const_cast<KHTMLPart *>(this));
3501 return d->editor_context.m_editor;
3502}
3503
3504void KHTMLPart::resetHoverText()
3505{
3506 if( !d->m_overURL.isEmpty() ) // Only if we were showing a link
3507 {
3508 d->m_overURL.clear();
3509 d->m_overURLTarget.clear();
3510 emit onURL( QString() );
3511 // revert to default statusbar text
3512 setStatusBarText(QString(), BarHoverText);
3513 emit d->m_extension->mouseOverInfo(KFileItem());
3514 }
3515}
3516
3517void KHTMLPart::overURL( const QString &url, const QString &target, bool /*shiftPressed*/ )
3518{
3519 KUrl u = completeURL(url);
3520
3521 // special case for <a href="">
3522 if ( url.isEmpty() )
3523 u.setFileName( url );
3524
3525 emit onURL( url );
3526
3527 if ( url.isEmpty() ) {
3528 setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText);
3529 return;
3530 }
3531
3532 if ( d->isJavaScriptURL(url) ) {
3533 QString jscode = d->codeForJavaScriptURL( url );
3534 jscode = KStringHandler::rsqueeze( jscode, 80 ); // truncate if too long
3535 if (url.startsWith("javascript:window.open"))
3536 jscode += i18n(" (In new window)");
3537 setStatusBarText( Qt::escape( jscode ), BarHoverText );
3538 return;
3539 }
3540
3541 KFileItem item(u, QString(), KFileItem::Unknown);
3542 emit d->m_extension->mouseOverInfo(item);
3543
3544 QString com;
3545
3546 KMimeType::Ptr typ = KMimeType::findByUrl( u );
3547
3548 if ( typ )
3549 com = typ->comment( u );
3550
3551 if ( !u.isValid() ) {
3552 setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText);
3553 return;
3554 }
3555
3556 if ( u.isLocalFile() )
3557 {
3558 // TODO : use KIO::stat() and create a KFileItem out of its result,
3559 // to use KFileItem::statusBarText()
3560 const QString path = QFile::encodeName( u.toLocalFile() );
3561
3562 KDE_struct_stat buff;
3563 bool ok = !KDE::stat( path, &buff );
3564
3565 KDE_struct_stat lbuff;
3566 if (ok) ok = !KDE::lstat( path, &lbuff );
3567
3568 QString text = Qt::escape(u.prettyUrl());
3569 QString text2 = text;
3570
3571 if (ok && S_ISLNK( lbuff.st_mode ) )
3572 {
3573 QString tmp;
3574 if ( com.isNull() )
3575 tmp = i18n( "Symbolic Link");
3576 else
3577 tmp = i18n("%1 (Link)", com);
3578 char buff_two[1024];
3579 text += " -> ";
3580 int n = readlink ( path.toLocal8Bit().data(), buff_two, 1022);
3581 if (n == -1)
3582 {
3583 text2 += " ";
3584 text2 += tmp;
3585 setStatusBarText(text2, BarHoverText);
3586 return;
3587 }
3588 buff_two[n] = 0;
3589
3590 text += buff_two;
3591 text += " ";
3592 text += tmp;
3593 }
3594 else if ( ok && S_ISREG( buff.st_mode ) )
3595 {
3596 if (buff.st_size < 1024)
3597 text = i18np("%2 (%1 byte)", "%2 (%1 bytes)", (long) buff.st_size, text2); // always put the URL last, in case it contains '%'
3598 else
3599 {
3600 float d = (float) buff.st_size/1024.0;
3601 text = i18n("%2 (%1 K)", KGlobal::locale()->formatNumber(d, 2), text2); // was %.2f
3602 }
3603 text += " ";
3604 text += com;
3605 }
3606 else if ( ok && S_ISDIR( buff.st_mode ) )
3607 {
3608 text += " ";
3609 text += com;
3610 }
3611 else
3612 {
3613 text += " ";
3614 text += com;
3615 }
3616 setStatusBarText(text, BarHoverText);
3617 }
3618 else
3619 {
3620 QString extra;
3621 if (target.toLower() == "_blank")
3622 {
3623 extra = i18n(" (In new window)");
3624 }
3625 else if (!target.isEmpty() &&
3626 (target.toLower() != "_top") &&
3627 (target.toLower() != "_self") &&
3628 (target.toLower() != "_parent"))
3629 {
3630 KHTMLPart *p = this;
3631 while (p->parentPart())
3632 p = p->parentPart();
3633 if (!p->frameExists(target))
3634 extra = i18n(" (In new window)");
3635 else
3636 extra = i18n(" (In other frame)");
3637 }
3638
3639 if (u.protocol() == QLatin1String("mailto")) {
3640 QString mailtoMsg /* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
3641 mailtoMsg += i18n("Email to: ") + KUrl::fromPercentEncoding(u.path().toLatin1());
3642 const QStringList queries = u.query().mid(1).split('&');
3643 QStringList::ConstIterator it = queries.begin();
3644 const QStringList::ConstIterator itEnd = queries.end();
3645 for (; it != itEnd; ++it)
3646 if ((*it).startsWith(QLatin1String("subject=")))
3647 mailtoMsg += i18n(" - Subject: ") + KUrl::fromPercentEncoding((*it).mid(8).toLatin1());
3648 else if ((*it).startsWith(QLatin1String("cc=")))
3649 mailtoMsg += i18n(" - CC: ") + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
3650 else if ((*it).startsWith(QLatin1String("bcc=")))
3651 mailtoMsg += i18n(" - BCC: ") + KUrl::fromPercentEncoding((*it).mid(4).toLatin1());
3652 mailtoMsg = Qt::escape(mailtoMsg);
3653 mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), QString());
3654 setStatusBarText("<qt>"+mailtoMsg, BarHoverText);
3655 return;
3656 }
3657 // Is this check necessary at all? (Frerich)
3658#if 0
3659 else if (u.protocol() == QLatin1String("http")) {
3660 DOM::Node hrefNode = nodeUnderMouse().parentNode();
3661 while (hrefNode.nodeName().string() != QLatin1String("A") && !hrefNode.isNull())
3662 hrefNode = hrefNode.parentNode();
3663
3664 if (!hrefNode.isNull()) {
3665 DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
3666 if (!hreflangNode.isNull()) {
3667 QString countryCode = hreflangNode.nodeValue().string().toLower();
3668 // Map the language code to an appropriate country code.
3669 if (countryCode == QLatin1String("en"))
3670 countryCode = QLatin1String("gb");
3671 QString flagImg = QLatin1String("<img src=%1>").arg(
3672 locate("locale", QLatin1String("l10n/")
3673 + countryCode
3674 + QLatin1String("/flag.png")));
3675 emit setStatusBarText(flagImg + u.prettyUrl() + extra);
3676 }
3677 }
3678 }
3679#endif
3680 setStatusBarText(Qt::escape(u.prettyUrl()) + extra, BarHoverText);
3681 }
3682}
3683
3684//
3685// This executes in the active part on a click or other url selection action in
3686// that active part.
3687//
3688bool KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target, const KParts::OpenUrlArguments& _args, const KParts::BrowserArguments& _browserArgs )
3689{
3690 KParts::OpenUrlArguments args = _args;
3691 KParts::BrowserArguments browserArgs = _browserArgs;
3692 bool hasTarget = false;
3693
3694 QString target = _target;
3695 if ( target.isEmpty() && d->m_doc )
3696 target = d->m_doc->baseTarget();
3697 if ( !target.isEmpty() )
3698 hasTarget = true;
3699
3700 if ( d->isJavaScriptURL(url) )
3701 {
3702 crossFrameExecuteScript( target, d->codeForJavaScriptURL(url) );
3703 return false;
3704 }
3705
3706 KUrl cURL = completeURL(url);
3707 // special case for <a href=""> (IE removes filename, mozilla doesn't)
3708 if ( url.isEmpty() )
3709 cURL.setFileName( url ); // removes filename
3710
3711 if ( !cURL.isValid() )
3712 // ### ERROR HANDLING
3713 return false;
3714
3715 kDebug(6050) << this << "complete URL:" << cURL.url() << "target=" << target;
3716
3717 if ( state & Qt::ControlModifier )
3718 {
3719 emit d->m_extension->createNewWindow( cURL, args, browserArgs );
3720 return true;
3721 }
3722
3723 if ( button == Qt::LeftButton && ( state & Qt::ShiftModifier ) )
3724 {
3725 KIO::MetaData metaData;
3726 metaData.insert( "referrer", d->m_referrer );
3727 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), cURL, metaData );
3728 return false;
3729 }
3730
3731 if (!checkLinkSecurity(cURL,
3732 ki18n( "<qt>This untrusted page links to<br /><b>%1</b>.<br />Do you want to follow the link?</qt>" ),
3733 i18n( "Follow" )))
3734 return false;
3735
3736 browserArgs.frameName = target;
3737
3738 args.metaData().insert("main_frame_request",
3739 parentPart() == 0 ? "TRUE":"FALSE");
3740 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
3741 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
3742 args.metaData().insert("PropagateHttpHeader", "true");
3743 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
3744 args.metaData().insert("ssl_activate_warnings", "TRUE");
3745
3746 if ( hasTarget && target != "_self" && target != "_top" && target != "_blank" && target != "_parent" )
3747 {
3748 // unknown frame names should open in a new window.
3749 khtml::ChildFrame *frame = recursiveFrameRequest( this, cURL, args, browserArgs, false );
3750 if ( frame )
3751 {
3752 args.metaData()["referrer"] = d->m_referrer;
3753 requestObject( frame, cURL, args, browserArgs );
3754 return true;
3755 }
3756 }
3757
3758 if (!d->m_referrer.isEmpty() && !args.metaData().contains("referrer"))
3759 args.metaData()["referrer"] = d->m_referrer;
3760
3761 if ( button == Qt::NoButton && (state & Qt::ShiftModifier) && (state & Qt::ControlModifier) )
3762 {
3763 emit d->m_extension->createNewWindow( cURL, args, browserArgs );
3764 return true;
3765 }
3766
3767 if ( state & Qt::ShiftModifier)
3768 {
3769 KParts::WindowArgs winArgs;
3770 winArgs.setLowerWindow(true);
3771 emit d->m_extension->createNewWindow( cURL, args, browserArgs, winArgs );
3772 return true;
3773 }
3774
3775 //If we're asked to open up an anchor in the current URL, in current window,
3776 //merely gotoanchor, and do not reload the new page. Note that this does
3777 //not apply if the URL is the same page, but without a ref
3778 if (cURL.hasRef() && (!hasTarget || target == "_self"))
3779 {
3780 if (d->isLocalAnchorJump(cURL))
3781 {
3782 d->executeAnchorJump(cURL, browserArgs.lockHistory() );
3783 return false; // we jumped, but we didn't open a URL
3784 }
3785 }
3786
3787 if ( !d->m_bComplete && !hasTarget )
3788 closeUrl();
3789
3790 view()->viewport()->unsetCursor();
3791 emit d->m_extension->openUrlRequest( cURL, args, browserArgs );
3792 return true;
3793}
3794
3795void KHTMLPart::slotViewDocumentSource()
3796{
3797 KUrl currentUrl(this->url());
3798 bool isTempFile = false;
3799 if (!(currentUrl.isLocalFile()) && KHTMLPageCache::self()->isComplete(d->m_cacheId))
3800 {
3801 KTemporaryFile sourceFile;
3802 sourceFile.setSuffix(defaultExtension());
3803 sourceFile.setAutoRemove(false);
3804 if (sourceFile.open())
3805 {
3806 QDataStream stream ( &sourceFile );
3807 KHTMLPageCache::self()->saveData(d->m_cacheId, &stream);
3808 currentUrl = KUrl();
3809 currentUrl.setPath(sourceFile.fileName());
3810 isTempFile = true;
3811 }
3812 }
3813
3814 (void) KRun::runUrl( currentUrl, QLatin1String("text/plain"), view(), isTempFile );
3815}
3816
3817void KHTMLPart::slotViewPageInfo()
3818{
3819 Ui_KHTMLInfoDlg ui;
3820
3821 QDialog *dlg = new QDialog(0);
3822 dlg->setAttribute(Qt::WA_DeleteOnClose);
3823 dlg->setObjectName("KHTML Page Info Dialog");
3824 ui.setupUi(dlg);
3825
3826 ui._close->setGuiItem(KStandardGuiItem::close());
3827 connect(ui._close, SIGNAL(clicked()), dlg, SLOT(accept()));
3828
3829 if (d->m_doc)
3830 ui._title->setText(d->m_doc->title().string().trimmed());
3831
3832 // If it's a frame, set the caption to "Frame Information"
3833 if ( parentPart() && d->m_doc && d->m_doc->isHTMLDocument() ) {
3834 dlg->setWindowTitle(i18n("Frame Information"));
3835 }
3836
3837 QString editStr;
3838
3839 if (!d->m_pageServices.isEmpty())
3840 editStr = i18n(" <a href=\"%1\">[Properties]</a>", d->m_pageServices);
3841
3842 QString squeezedURL = KStringHandler::csqueeze( url().prettyUrl(), 80 );
3843 ui._url->setText("<a href=\"" + url().url() + "\">" + squeezedURL + "</a>" + editStr);
3844 if (lastModified().isEmpty())
3845 {
3846 ui._lastModified->hide();
3847 ui._lmLabel->hide();
3848 }
3849 else
3850 ui._lastModified->setText(lastModified());
3851
3852 const QString& enc = encoding();
3853 if (enc.isEmpty()) {
3854 ui._eLabel->hide();
3855 ui._encoding->hide();
3856 } else {
3857 ui._encoding->setText(enc);
3858 }
3859
3860 if (!xmlDocImpl() || xmlDocImpl()->parseMode() == DOM::DocumentImpl::Unknown) {
3861 ui._mode->hide();
3862 ui._modeLabel->hide();
3863 } else {
3864 switch (xmlDocImpl()->parseMode()) {
3865 case DOM::DocumentImpl::Compat:
3866 ui._mode->setText(i18nc("HTML rendering mode (see http://en.wikipedia.org/wiki/Quirks_mode)", "Quirks"));
3867 break;
3868 case DOM::DocumentImpl::Transitional:
3869 ui._mode->setText(i18nc("HTML rendering mode (see http://en.wikipedia.org/wiki/Quirks_mode)", "Almost standards"));
3870 break;
3871 case DOM::DocumentImpl::Strict:
3872 default: // others handled above
3873 ui._mode->setText(i18nc("HTML rendering mode (see http://en.wikipedia.org/wiki/Quirks_mode)", "Strict"));
3874 break;
3875 }
3876 }
3877
3878 /* populate the list view now */
3879 const QStringList headers = d->m_httpHeaders.split("\n");
3880
3881 QStringList::ConstIterator it = headers.begin();
3882 const QStringList::ConstIterator itEnd = headers.end();
3883
3884 for (; it != itEnd; ++it) {
3885 const QStringList header = (*it).split(QRegExp(":[ ]+"));
3886 if (header.count() != 2)
3887 continue;
3888 QTreeWidgetItem *item = new QTreeWidgetItem(ui._headers);
3889 item->setText(0, header[0]);
3890 item->setText(1, header[1]);
3891 }
3892
3893 dlg->show();
3894 /* put no code here */
3895}
3896
3897
3898void KHTMLPart::slotViewFrameSource()
3899{
3900 KParts::ReadOnlyPart *frame = currentFrame();
3901 if ( !frame )
3902 return;
3903
3904 KUrl url = frame->url();
3905 bool isTempFile = false;
3906 if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
3907 {
3908 long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
3909
3910 if (KHTMLPageCache::self()->isComplete(cacheId))
3911 {
3912 KTemporaryFile sourceFile;
3913 sourceFile.setSuffix(defaultExtension());
3914 sourceFile.setAutoRemove(false);
3915 if (sourceFile.open())
3916 {
3917 QDataStream stream ( &sourceFile );
3918 KHTMLPageCache::self()->saveData(cacheId, &stream);
3919 url = KUrl();
3920 url.setPath(sourceFile.fileName());
3921 isTempFile = true;
3922 }
3923 }
3924 }
3925
3926 (void) KRun::runUrl( url, QLatin1String("text/plain"), view(), isTempFile );
3927}
3928
3929KUrl KHTMLPart::backgroundURL() const
3930{
3931 // ### what about XML documents? get from CSS?
3932 if (!d->m_doc || !d->m_doc->isHTMLDocument())
3933 return KUrl();
3934
3935 QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
3936
3937 return KUrl( url(), relURL );
3938}
3939
3940void KHTMLPart::slotSaveBackground()
3941{
3942 KIO::MetaData metaData;
3943 metaData["referrer"] = d->m_referrer;
3944 KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save Background Image As"), backgroundURL(), metaData );
3945}
3946
3947void KHTMLPart::slotSaveDocument()
3948{
3949 KUrl srcURL( url() );
3950
3951 if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() )
3952 srcURL.setFileName( "index" + defaultExtension() );
3953
3954 KIO::MetaData metaData;
3955 // Referre unknown?
3956 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, "text/html", d->m_cacheId );
3957}
3958
3959void KHTMLPart::slotSecurity()
3960{
3961// kDebug( 6050 ) << "Meta Data:" << endl
3962// << d->m_ssl_peer_cert_subject
3963// << endl
3964// << d->m_ssl_peer_cert_issuer
3965// << endl
3966// << d->m_ssl_cipher
3967// << endl
3968// << d->m_ssl_cipher_desc
3969// << endl
3970// << d->m_ssl_cipher_version
3971// << endl
3972// << d->m_ssl_good_from
3973// << endl
3974// << d->m_ssl_good_until
3975// << endl
3976// << d->m_ssl_cert_state
3977// << endl;
3978
3979 //### reenable with new signature
3980#if 0
3981 KSslInfoDialog *kid = new KSslInfoDialog(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
3982
3983 const QStringList sl = d->m_ssl_peer_chain.split('\n', QString::SkipEmptyParts);
3984 QList<QSslCertificate> certChain;
3985 bool certChainOk = d->m_ssl_in_use;
3986 if (certChainOk) {
3987 foreach (const QString &s, sl) {
3988 certChain.append(QSslCertificate(s.toLatin1())); //or is it toLocal8Bit or whatever?
3989 if (certChain.last().isNull()) {
3990 certChainOk = false;
3991 break;
3992 }
3993 }
3994 }
3995 if (certChainOk) {
3996 kid->setup(certChain,
3997 d->m_ssl_peer_ip,
3998 url().url(),
3999 d->m_ssl_cipher,
4000 d->m_ssl_cipher_desc,
4001 d->m_ssl_cipher_version,
4002 d->m_ssl_cipher_used_bits.toInt(),
4003 d->m_ssl_cipher_bits.toInt(),
4004 (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt());
4005 }
4006 kid->exec();
4007 //the dialog deletes itself on close
4008#endif
4009
4010 KSslInfoDialog *kid = new KSslInfoDialog(0);
4011 //### This is boilerplate code and it's copied from SlaveInterface.
4012 QStringList sl = d->m_ssl_peer_chain.split('\x01', QString::SkipEmptyParts);
4013 QList<QSslCertificate> certChain;
4014 bool decodedOk = true;
4015 foreach (const QString &s, sl) {
4016 certChain.append(QSslCertificate(s.toLatin1())); //or is it toLocal8Bit or whatever?
4017 if (certChain.last().isNull()) {
4018 decodedOk = false;
4019 break;
4020 }
4021 }
4022
4023 if (decodedOk || true /*H4X*/) {
4024 kid->setSslInfo(certChain,
4025 d->m_ssl_peer_ip,
4026 url().host(),
4027 d->m_ssl_protocol_version,
4028 d->m_ssl_cipher,
4029 d->m_ssl_cipher_used_bits.toInt(),
4030 d->m_ssl_cipher_bits.toInt(),
4031 KSslInfoDialog::errorsFromString(d->m_ssl_cert_errors));
4032 kDebug(7024) << "Showing SSL Info dialog";
4033 kid->exec();
4034 kDebug(7024) << "SSL Info dialog closed";
4035 } else {
4036 KMessageBox::information(0, i18n("The peer SSL certificate chain "
4037 "appears to be corrupt."),
4038 i18n("SSL"));
4039 }
4040}
4041
4042void KHTMLPart::slotSaveFrame()
4043{
4044 KParts::ReadOnlyPart *frame = currentFrame();
4045 if ( !frame )
4046 return;
4047
4048 KUrl srcURL( frame->url() );
4049
4050 if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() )
4051 srcURL.setFileName( "index" + defaultExtension() );
4052
4053 KIO::MetaData metaData;
4054 // Referrer unknown?
4055 KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save Frame As" ), srcURL, metaData, "text/html" );
4056}
4057
4058void KHTMLPart::slotSetEncoding(const QString &enc)
4059{
4060 d->m_autoDetectLanguage=KEncodingDetector::None;
4061 setEncoding( enc, true);
4062}
4063
4064void KHTMLPart::slotAutomaticDetectionLanguage(KEncodingDetector::AutoDetectScript scri)
4065{
4066 d->m_autoDetectLanguage=scri;
4067 setEncoding( QString(), false );
4068}
4069
4070void KHTMLPart::slotUseStylesheet()
4071{
4072 if (d->m_doc)
4073 {
4074 bool autoselect = (d->m_paUseStylesheet->currentItem() == 0);
4075 d->m_sheetUsed = autoselect ? QString() : d->m_paUseStylesheet->currentText();
4076 d->m_doc->updateStyleSelector();
4077 }
4078}
4079
4080void KHTMLPart::updateActions()
4081{
4082 bool frames = false;
4083
4084 QList<khtml::ChildFrame*>::ConstIterator it = d->m_frames.constBegin();
4085 const QList<khtml::ChildFrame*>::ConstIterator end = d->m_frames.constEnd();
4086 for (; it != end; ++it )
4087 if ( (*it)->m_type == khtml::ChildFrame::Frame )
4088 {
4089 frames = true;
4090 break;
4091 }
4092
4093 if (d->m_paViewFrame)
4094 d->m_paViewFrame->setEnabled( frames );
4095 if (d->m_paSaveFrame)
4096 d->m_paSaveFrame->setEnabled( frames );
4097
4098 if ( frames )
4099 d->m_paFind->setText( i18n( "&Find in Frame..." ) );
4100 else
4101 d->m_paFind->setText( i18n( "&Find..." ) );
4102
4103 KParts::Part *frame = 0;
4104
4105 if ( frames )
4106 frame = currentFrame();
4107
4108 bool enableFindAndSelectAll = true;
4109
4110 if ( frame )
4111 enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
4112
4113 d->m_paFind->setEnabled( enableFindAndSelectAll );
4114 d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
4115
4116 bool enablePrintFrame = false;
4117
4118 if ( frame )
4119 {
4120 QObject *ext = KParts::BrowserExtension::childObject( frame );
4121 if ( ext )
4122 enablePrintFrame = ext->metaObject()->indexOfSlot( "print()" ) != -1;
4123 }
4124
4125 d->m_paPrintFrame->setEnabled( enablePrintFrame );
4126
4127 QString bgURL;
4128
4129 // ### frames
4130 if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
4131 bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
4132
4133 if (d->m_paSaveBackground)
4134 d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
4135
4136 if ( d->m_paDebugScript )
4137 d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
4138}
4139
4140KParts::ScriptableExtension *KHTMLPart::scriptableExtension( const DOM::NodeImpl *frame) {
4141 const ConstFrameIt end = d->m_objects.constEnd();
4142 for(ConstFrameIt it = d->m_objects.constBegin(); it != end; ++it )
4143 if ((*it)->m_partContainerElement.data() == frame)
4144 return (*it)->m_scriptable.data();
4145 return 0L;
4146}
4147
4148void KHTMLPart::loadFrameElement( DOM::HTMLPartContainerElementImpl *frame, const QString &url,
4149 const QString &frameName, const QStringList &params, bool isIFrame )
4150{
4151 //kDebug( 6050 ) << this << " requestFrame( ..., " << url << ", " << frameName << " )";
4152 khtml::ChildFrame* child;
4153
4154 FrameIt it = d->m_frames.find( frameName );
4155 if ( it == d->m_frames.end() ) {
4156 child = new khtml::ChildFrame;
4157 //kDebug( 6050 ) << "inserting new frame into frame map " << frameName;
4158 child->m_name = frameName;
4159 d->m_frames.insert( d->m_frames.end(), child );
4160 } else {
4161 child = *it;
4162 }
4163
4164 child->m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
4165 child->m_partContainerElement = frame;
4166 child->m_params = params;
4167
4168 // If we do not have a part, make sure we create one.
4169 if (!child->m_part) {
4170 QStringList dummy; // the list of servicetypes handled by the part is now unused.
4171 QString khtml = QString::fromLatin1("khtml");
4172 KParts::ReadOnlyPart* part = createPart(d->m_view->viewport(), this,
4173 QString::fromLatin1("text/html"),
4174 khtml, dummy, QStringList());
4175 // We navigate it to about:blank to setup an empty one, but we do it
4176 // before hooking up the signals and extensions, so that any sync emit
4177 // of completed by the kid doesn't cause us to be marked as completed.
4178 // (async ones are discovered by the presence of the KHTMLRun)
4179 // ### load event on the kid?
4180 navigateLocalProtocol(child, part, KUrl("about:blank"));
4181 connectToChildPart(child, part, "text/html" /* mimetype of the part, not what's being loaded */);
4182 }
4183
4184 KUrl u = url.isEmpty() ? KUrl() : completeURL( url );
4185
4186 // Since we don't specify args here a KHTMLRun will be used to determine the
4187 // mimetype, which will then be passed down at the bottom of processObjectRequest
4188 // inside URLArgs to the part. In our particular case, this means that we can
4189 // use that inside KHTMLPart::openUrl to route things appropriately.
4190 child->m_bCompleted = false;
4191 if (!requestObject( child, u ) && !child->m_run) {
4192 child->m_bCompleted = true;
4193 }
4194}
4195
4196QString KHTMLPart::requestFrameName()
4197{
4198 return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
4199}
4200
4201bool KHTMLPart::loadObjectElement( DOM::HTMLPartContainerElementImpl *frame, const QString &url,
4202 const QString &serviceType, const QStringList &params )
4203{
4204 //kDebug( 6031 ) << this << "frame=" << frame;
4205 khtml::ChildFrame *child = new khtml::ChildFrame;
4206 FrameIt it = d->m_objects.insert( d->m_objects.end(), child );
4207 (*it)->m_partContainerElement = frame;
4208 (*it)->m_type = khtml::ChildFrame::Object;
4209 (*it)->m_params = params;
4210
4211 KParts::OpenUrlArguments args;
4212 args.setMimeType(serviceType);
4213 if (!requestObject( *it, completeURL( url ), args ) && !(*it)->m_run) {
4214 (*it)->m_bCompleted = true;
4215 return false;
4216 }
4217 return true;
4218}
4219
4220bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KUrl &url, const KParts::OpenUrlArguments &_args,
4221 const KParts::BrowserArguments& browserArgs )
4222{
4223 // we always permit javascript: URLs here since they're basically just
4224 // empty pages (and checkLinkSecurity/KAuthorized doesn't know what to do with them)
4225 if (!d->isJavaScriptURL(url.url()) && !checkLinkSecurity(url))
4226 {
4227 kDebug(6031) << this << "checkLinkSecurity refused";
4228 return false;
4229 }
4230
4231 if (d->m_bClearing)
4232 {
4233 return false;
4234 }
4235
4236 if ( child->m_bPreloaded )
4237 {
4238 if ( child->m_partContainerElement && child->m_part )
4239 child->m_partContainerElement.data()->setWidget( child->m_part.data()->widget() );
4240
4241 child->m_bPreloaded = false;
4242 return true;
4243 }
4244
4245 //kDebug(6031) << "child=" << child << "child->m_part=" << child->m_part;
4246
4247 KParts::OpenUrlArguments args( _args );
4248
4249 if ( child->m_run ) {
4250 kDebug(6031) << "navigating ChildFrame while mimetype resolution was in progress...";
4251 child->m_run.data()->abort();
4252 }
4253
4254 // ### Dubious -- the whole dir/ vs. img thing
4255 if ( child->m_part && !args.reload() && child->m_part.data()->url().equals( url,
4256 KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment | KUrl::AllowEmptyPath ) )
4257 args.setMimeType(child->m_serviceType);
4258
4259 child->m_browserArgs = browserArgs;
4260 child->m_args = args;
4261
4262 // reload/soft-reload arguments are always inherited from parent
4263 child->m_args.setReload( arguments().reload() );
4264 child->m_browserArgs.softReload = d->m_extension->browserArguments().softReload;
4265
4266 child->m_serviceName.clear();
4267 if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
4268 child->m_args.metaData()["referrer"] = d->m_referrer;
4269
4270 child->m_args.metaData().insert("PropagateHttpHeader", "true");
4271 child->m_args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
4272 child->m_args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
4273 child->m_args.metaData().insert("main_frame_request",
4274 parentPart() == 0 ? "TRUE":"FALSE");
4275 child->m_args.metaData().insert("ssl_was_in_use",
4276 d->m_ssl_in_use ? "TRUE":"FALSE");
4277 child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
4278 child->m_args.metaData().insert("cross-domain", toplevelURL().url());
4279
4280 // We know the frame will be text/html if the HTML says <frame src=""> or <frame src="about:blank">,
4281 // no need to KHTMLRun to figure out the mimetype"
4282 // ### What if we're inside an XML document?
4283 if ((url.isEmpty() || url.url() == "about:blank" || url.protocol() == "javascript") && args.mimeType().isEmpty())
4284 args.setMimeType(QLatin1String("text/html"));
4285
4286 if ( args.mimeType().isEmpty() ) {
4287 kDebug(6031) << "Running new KHTMLRun for" << this << "and child=" << child;
4288 child->m_run = new KHTMLRun( this, child, url, child->m_args, child->m_browserArgs, true );
4289 d->m_bComplete = false; // ensures we stop it in checkCompleted...
4290 return false;
4291 } else {
4292 return processObjectRequest( child, url, args.mimeType() );
4293 }
4294}
4295
4296void KHTMLPart::childLoadFailure( khtml::ChildFrame *child )
4297{
4298 child->m_bCompleted = true;
4299 if ( child->m_partContainerElement )
4300 child->m_partContainerElement.data()->partLoadingErrorNotify();
4301
4302 checkCompleted();
4303}
4304
4305bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KUrl &_url, const QString &mimetype )
4306{
4307 kDebug( 6031 ) << "trying to create part for" << mimetype << _url;
4308
4309 // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
4310 // by an emitting frame part (emit openUrlRequest( blahurl, ... ) . A few lines below we delete the part
4311 // though -> the reference becomes invalid -> crash is likely
4312 KUrl url( _url );
4313
4314 // khtmlrun called us with empty url + mimetype to indicate a loading error,
4315 // we obviosuly failed; but we can return true here since we don't want it
4316 // doing anything more, while childLoadFailure is enough to notify our kid.
4317 if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) ) {
4318 childLoadFailure(child);
4319 return true;
4320 }
4321
4322 // we also want to ignore any spurious requests due to closing when parser is being cleared. These should be
4323 // ignored entirely --- the tail end of ::clear will clean things up.
4324 if (d->m_bClearing)
4325 return false;
4326
4327 if (child->m_bNotify) {
4328 child->m_bNotify = false;
4329 if ( !child->m_browserArgs.lockHistory() )
4330 emit d->m_extension->openUrlNotify();
4331 }
4332
4333 // Now, depending on mimetype and current state of the world, we may have
4334 // to create a new part or ask the user to save things, etc.
4335 //
4336 // We need a new part if there isn't one at all (doh) or the one that's there
4337 // is not for the mimetype we're loading.
4338 //
4339 // For these new types, we may have to ask the user to save it or not
4340 // (we don't if it's navigating the same type).
4341 // Further, we will want to ask if content-disposition suggests we ask for
4342 // saving, even if we're re-navigating.
4343 if ( !child->m_part || child->m_serviceType != mimetype ||
4344 (child->m_run && child->m_run.data()->serverSuggestsSave())) {
4345 // We often get here if we didn't know the mimetype in advance, and had to rely
4346 // on KRun to figure it out. In this case, we let the element check if it wants to
4347 // handle this mimetype itself, for e.g. objects containing images.
4348 if ( child->m_partContainerElement &&
4349 child->m_partContainerElement.data()->mimetypeHandledInternally(mimetype) ) {
4350 child->m_bCompleted = true;
4351 checkCompleted();
4352 return true;
4353 }
4354
4355 // Before attempting to load a part, check if the user wants that.
4356 // Many don't like getting ZIP files embedded.
4357 // However we don't want to ask for flash and other plugin things.
4358 //
4359 // Note: this is fine for frames, since we will merely effectively ignore
4360 // the navigation if this happens
4361 if ( child->m_type != khtml::ChildFrame::Object && child->m_type != khtml::ChildFrame::IFrame ) {
4362 QString suggestedFileName;
4363 int disposition = 0;
4364 if ( KHTMLRun* run = child->m_run.data() ) {
4365 suggestedFileName = run->suggestedFileName();
4366 disposition = run->serverSuggestsSave() ?
4367 KParts::BrowserRun::AttachmentDisposition :
4368 KParts::BrowserRun::InlineDisposition;
4369 }
4370
4371 KParts::BrowserOpenOrSaveQuestion dlg( widget(), url, mimetype );
4372 dlg.setSuggestedFileName( suggestedFileName );
4373 const KParts::BrowserOpenOrSaveQuestion::Result res = dlg.askEmbedOrSave( disposition );
4374
4375 switch( res ) {
4376 case KParts::BrowserOpenOrSaveQuestion::Save:
4377 KHTMLPopupGUIClient::saveURL( widget(), i18n( "Save As" ), url, child->m_args.metaData(), QString(), 0, suggestedFileName );
4378 // fall-through
4379 case KParts::BrowserOpenOrSaveQuestion::Cancel:
4380 child->m_bCompleted = true;
4381 checkCompleted();
4382 return true; // done
4383 default: // Embed
4384 break;
4385 }
4386 }
4387
4388 // Now, for frames and iframes, we always create a KHTMLPart anyway,
4389 // doing it in advance when registering the frame. So we want the
4390 // actual creation only for objects here.
4391 if ( child->m_type == khtml::ChildFrame::Object ) {
4392 KMimeType::Ptr mime = KMimeType::mimeType(mimetype);
4393 if (mime) {
4394 // Even for objects, however, we want to force a KHTMLPart for
4395 // html & xml, even if the normally preferred part is another one,
4396 // so that we can script the target natively via contentDocument method.
4397 if (mime->is("text/html")
4398 || mime->is("application/xml")) { // this includes xhtml and svg
4399 child->m_serviceName = "khtml";
4400 } else {
4401 if (!pluginsEnabled()) {
4402 childLoadFailure(child);
4403 return false;
4404 }
4405 }
4406 }
4407
4408 QStringList dummy; // the list of servicetypes handled by the part is now unused.
4409 KParts::ReadOnlyPart *part = createPart( d->m_view->viewport(), this, mimetype, child->m_serviceName, dummy, child->m_params );
4410
4411 if ( !part ) {
4412 childLoadFailure(child);
4413 return false;
4414 }
4415
4416 connectToChildPart( child, part, mimetype );
4417 }
4418 }
4419
4420 checkEmitLoadEvent();
4421
4422 // Some JS code in the load event may have destroyed the part
4423 // In that case, abort
4424 if ( !child->m_part )
4425 return false;
4426
4427 if ( child->m_bPreloaded ) {
4428 if ( child->m_partContainerElement && child->m_part )
4429 child->m_partContainerElement.data()->setWidget( child->m_part.data()->widget() );
4430
4431 child->m_bPreloaded = false;
4432 return true;
4433 }
4434
4435 // reload/soft-reload arguments are always inherited from parent
4436 child->m_args.setReload( arguments().reload() );
4437 child->m_browserArgs.softReload = d->m_extension->browserArguments().softReload;
4438
4439 // make sure the part has a way to find out about the mimetype.
4440 // we actually set it in child->m_args in requestObject already,
4441 // but it's useless if we had to use a KHTMLRun instance, as the
4442 // point the run object is to find out exactly the mimetype.
4443 child->m_args.setMimeType(mimetype);
4444 child->m_part.data()->setArguments( child->m_args );
4445
4446 // if not a frame set child as completed
4447 // ### dubious.
4448 child->m_bCompleted = child->m_type == khtml::ChildFrame::Object;
4449
4450 if ( child->m_extension )
4451 child->m_extension.data()->setBrowserArguments( child->m_browserArgs );
4452
4453 return navigateChild( child, url );
4454}
4455
4456bool KHTMLPart::navigateLocalProtocol( khtml::ChildFrame* /*child*/, KParts::ReadOnlyPart *inPart,
4457 const KUrl& url )
4458{
4459 if (!qobject_cast<KHTMLPart*>(inPart))
4460 return false;
4461
4462 KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(inPart));
4463
4464 p->begin();
4465
4466 // We may have to re-propagate the domain here if we go here due to navigation
4467 d->propagateInitialDomainAndBaseTo(p);
4468
4469 // Support for javascript: sources
4470 if (d->isJavaScriptURL(url.url())) {
4471 // See if we want to replace content with javascript: output..
4472 QVariant res = p->executeScript( DOM::Node(),
4473 d->codeForJavaScriptURL(url.url()));
4474 if (res.type() == QVariant::String && p->d->m_redirectURL.isEmpty()) {
4475 p->begin();
4476 p->setAlwaysHonourDoctype(); // Disable public API compat; it messes with doctype
4477 // We recreated the document, so propagate domain again.
4478 d->propagateInitialDomainAndBaseTo(p);
4479 p->write( res.toString() );
4480 p->end();
4481 }
4482 } else {
4483 p->setUrl(url);
4484 // we need a body element. testcase: <iframe id="a"></iframe><script>alert(a.document.body);</script>
4485 p->write("<HTML><TITLE></TITLE><BODY></BODY></HTML>");
4486 }
4487 p->end();
4488 // we don't need to worry about child completion explicitly for KHTMLPart...
4489 // or do we?
4490 return true;
4491}
4492
4493bool KHTMLPart::navigateChild( khtml::ChildFrame *child, const KUrl& url )
4494{
4495 if (url.protocol() == "javascript" || url.url() == "about:blank") {
4496 return navigateLocalProtocol(child, child->m_part.data(), url);
4497 } else if ( !url.isEmpty() ) {
4498 kDebug( 6031 ) << "opening" << url << "in frame" << child->m_part;
4499 bool b = child->m_part.data()->openUrl( url );
4500 if (child->m_bCompleted)
4501 checkCompleted();
4502 return b;
4503 } else {
4504 // empty URL -> no need to navigate
4505 child->m_bCompleted = true;
4506 checkCompleted();
4507 return true;
4508 }
4509}
4510
4511void KHTMLPart::connectToChildPart( khtml::ChildFrame *child, KParts::ReadOnlyPart *part,
4512 const QString& mimetype)
4513{
4514 kDebug(6031) << "we:" << this << "kid:" << child << part << mimetype;
4515
4516 part->setObjectName( child->m_name );
4517
4518 // Cleanup any previous part for this childframe and its connections
4519 if ( KParts::ReadOnlyPart* p = child->m_part.data() ) {
4520 if (!qobject_cast<KHTMLPart*>(p) && child->m_jscript)
4521 child->m_jscript->clear();
4522 partManager()->removePart( p );
4523 delete p;
4524 child->m_scriptable.clear();
4525 }
4526
4527 child->m_part = part;
4528
4529 child->m_serviceType = mimetype;
4530 if ( child->m_partContainerElement && part->widget() )
4531 child->m_partContainerElement.data()->setWidget( part->widget() );
4532
4533 if ( child->m_type != khtml::ChildFrame::Object )
4534 partManager()->addPart( part, false );
4535// else
4536// kDebug(6031) << "AH! NO FRAME!!!!!";
4537
4538 if (qobject_cast<KHTMLPart*>(part)) {
4539 static_cast<KHTMLPart*>(part)->d->m_frame = child;
4540 } else if (child->m_partContainerElement) {
4541 // See if this can be scripted..
4542 KParts::ScriptableExtension* scriptExt = KParts::ScriptableExtension::childObject(part);
4543 if (!scriptExt) {
4544 // Try to fall back to LiveConnectExtension compat
4545 KParts::LiveConnectExtension* lc = KParts::LiveConnectExtension::childObject(part);
4546 if (lc)
4547 scriptExt = KParts::ScriptableExtension::adapterFromLiveConnect(part, lc);
4548 }
4549
4550 if (scriptExt)
4551 scriptExt->setHost(d->m_scriptableExtension);
4552 child->m_scriptable = scriptExt;
4553 }
4554 KParts::StatusBarExtension *sb = KParts::StatusBarExtension::childObject(part);
4555 if (sb)
4556 sb->setStatusBar( d->m_statusBarExtension->statusBar() );
4557
4558 connect( part, SIGNAL(started(KIO::Job*)),
4559 this, SLOT(slotChildStarted(KIO::Job*)) );
4560 connect( part, SIGNAL(completed()),
4561 this, SLOT(slotChildCompleted()) );
4562 connect( part, SIGNAL(completed(bool)),
4563 this, SLOT(slotChildCompleted(bool)) );
4564 connect( part, SIGNAL(setStatusBarText(QString)),
4565 this, SIGNAL(setStatusBarText(QString)) );
4566 if ( part->inherits( "KHTMLPart" ) )
4567 {
4568 connect( this, SIGNAL(completed()),
4569 part, SLOT(slotParentCompleted()) );
4570 connect( this, SIGNAL(completed(bool)),
4571 part, SLOT(slotParentCompleted()) );
4572 // As soon as the child's document is created, we need to set its domain
4573 // (but we do so only once, so it can't be simply done in the child)
4574 connect( part, SIGNAL(docCreated()),
4575 this, SLOT(slotChildDocCreated()) );
4576 }
4577
4578 child->m_extension = KParts::BrowserExtension::childObject( part );
4579
4580 if ( KParts::BrowserExtension* kidBrowserExt = child->m_extension.data() )
4581 {
4582 connect( kidBrowserExt, SIGNAL(openUrlNotify()),
4583 d->m_extension, SIGNAL(openUrlNotify()) );
4584
4585 connect( kidBrowserExt, SIGNAL(openUrlRequestDelayed(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)),
4586 this, SLOT(slotChildURLRequest(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)) );
4587
4588 connect( kidBrowserExt, SIGNAL(createNewWindow(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**)),
4589 d->m_extension, SIGNAL(createNewWindow(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**)) );
4590
4591 connect( kidBrowserExt, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)),
4592 d->m_extension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) );
4593 connect( kidBrowserExt, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)),
4594 d->m_extension, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) );
4595
4596 connect( kidBrowserExt, SIGNAL(infoMessage(QString)),
4597 d->m_extension, SIGNAL(infoMessage(QString)) );
4598
4599 connect( kidBrowserExt, SIGNAL(requestFocus(KParts::ReadOnlyPart*)),
4600 this, SLOT(slotRequestFocus(KParts::ReadOnlyPart*)) );
4601
4602 kidBrowserExt->setBrowserInterface( d->m_extension->browserInterface() );
4603 }
4604}
4605
4606KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget,
4607 QObject *parent, const QString &mimetype,
4608 QString &serviceName, QStringList &serviceTypes,
4609 const QStringList &params )
4610{
4611 QString constr;
4612 if ( !serviceName.isEmpty() )
4613 constr.append( QString::fromLatin1( "DesktopEntryName == '%1'" ).arg( serviceName ) );
4614
4615 KService::List offers = KMimeTypeTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr );
4616
4617 if ( offers.isEmpty() ) {
4618 int pos = mimetype.indexOf( "-plugin" );
4619 if (pos < 0)
4620 return 0L;
4621 QString stripped_mime = mimetype.left( pos );
4622 offers = KMimeTypeTrader::self()->query( stripped_mime, "KParts/ReadOnlyPart", constr );
4623 if ( offers.isEmpty() )
4624 return 0L;
4625 }
4626
4627 KService::List::ConstIterator it = offers.constBegin();
4628 const KService::List::ConstIterator itEnd = offers.constEnd();
4629 for ( ; it != itEnd; ++it )
4630 {
4631 KService::Ptr service = (*it);
4632
4633 KPluginLoader loader( *service, KHTMLGlobal::componentData() );
4634 KPluginFactory* const factory = loader.factory();
4635 if ( factory ) {
4636 // Turn params into a QVariantList as expected by KPluginFactory
4637 QVariantList variantlist;
4638 Q_FOREACH(const QString& str, params)
4639 variantlist << QVariant(str);
4640
4641 if ( service->serviceTypes().contains( "Browser/View" ) )
4642 variantlist << QString("Browser/View");
4643
4644 KParts::ReadOnlyPart* part = factory->create<KParts::ReadOnlyPart>(parentWidget, parent, QString(), variantlist);
4645 if ( part ) {
4646 serviceTypes = service->serviceTypes();
4647 serviceName = service->name();
4648 return part;
4649 }
4650 } else {
4651 // TODO KMessageBox::error and i18n, like in KonqFactory::createView?
4652 kWarning() << QString("There was an error loading the module %1.\nThe diagnostics is:\n%2")
4653 .arg(service->name()).arg(loader.errorString());
4654 }
4655 }
4656 return 0;
4657}
4658
4659KParts::PartManager *KHTMLPart::partManager()
4660{
4661 if ( !d->m_manager && d->m_view )
4662 {
4663 d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this );
4664 d->m_manager->setObjectName( "khtml part manager" );
4665 d->m_manager->setAllowNestedParts( true );
4666 connect( d->m_manager, SIGNAL(activePartChanged(KParts::Part*)),
4667 this, SLOT(slotActiveFrameChanged(KParts::Part*)) );
4668 connect( d->m_manager, SIGNAL(partRemoved(KParts::Part*)),
4669 this, SLOT(slotPartRemoved(KParts::Part*)) );
4670 }
4671
4672 return d->m_manager;
4673}
4674
4675void KHTMLPart::submitFormAgain()
4676{
4677 disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
4678 if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
4679 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 );
4680
4681 delete d->m_submitForm;
4682 d->m_submitForm = 0;
4683}
4684
4685void KHTMLPart::submitFormProxy( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
4686{
4687 submitForm(action, url, formData, _target, contentType, boundary);
4688}
4689
4690void KHTMLPart::submitForm( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
4691{
4692 kDebug(6000) << this << "target=" << _target << "url=" << url;
4693 if (d->m_formNotification == KHTMLPart::Only) {
4694 emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
4695 return;
4696 } else if (d->m_formNotification == KHTMLPart::Before) {
4697 emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
4698 }
4699
4700 KUrl u = completeURL( url );
4701
4702 if ( !u.isValid() )
4703 {
4704 // ### ERROR HANDLING!
4705 return;
4706 }
4707
4708 // Form security checks
4709 //
4710 /*
4711 * If these form security checks are still in this place in a month or two
4712 * I'm going to simply delete them.
4713 */
4714
4715 /* This is separate for a reason. It has to be _before_ all script, etc,
4716 * AND I don't want to break anything that uses checkLinkSecurity() in
4717 * other places.
4718 */
4719
4720 if (!d->m_submitForm) {
4721 if (u.protocol() != "https" && u.protocol() != "mailto") {
4722 if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
4723 int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
4724 "\nA third party may be able to intercept and view this information."
4725 "\nAre you sure you wish to continue?"),
4726 i18n("Network Transmission"),KGuiItem(i18n("&Send Unencrypted")));
4727 if (rc == KMessageBox::Cancel)
4728 return;
4729 } else { // Going from nonSSL -> nonSSL
4730 KSSLSettings kss(true);
4731 if (kss.warnOnUnencrypted()) {
4732 int rc = KMessageBox::warningContinueCancel(NULL,
4733 i18n("Warning: Your data is about to be transmitted across the network unencrypted."
4734 "\nAre you sure you wish to continue?"),
4735 i18n("Network Transmission"),
4736 KGuiItem(i18n("&Send Unencrypted")),
4737 KStandardGuiItem::cancel(),
4738 "WarnOnUnencryptedForm");
4739 // Move this setting into KSSL instead
4740 QString grpNotifMsgs = QLatin1String("Notification Messages");
4741 KConfigGroup cg( KGlobal::config(), grpNotifMsgs );
4742
4743 if (!cg.readEntry("WarnOnUnencryptedForm", true)) {
4744 cg.deleteEntry("WarnOnUnencryptedForm");
4745 cg.sync();
4746 kss.setWarnOnUnencrypted(false);
4747 kss.save();
4748 }
4749 if (rc == KMessageBox::Cancel)
4750 return;
4751 }
4752 }
4753 }
4754
4755 if (u.protocol() == "mailto") {
4756 int rc = KMessageBox::warningContinueCancel(NULL,
4757 i18n("This site is attempting to submit form data via email.\n"
4758 "Do you want to continue?"),
4759 i18n("Network Transmission"),
4760 KGuiItem(i18n("&Send Email")),
4761 KStandardGuiItem::cancel(),
4762 "WarnTriedEmailSubmit");
4763
4764 if (rc == KMessageBox::Cancel) {
4765 return;
4766 }
4767 }
4768 }
4769
4770 // End form security checks
4771 //
4772
4773 QString urlstring = u.url();
4774
4775 if ( d->isJavaScriptURL(urlstring) ) {
4776 crossFrameExecuteScript( _target, d->codeForJavaScriptURL(urlstring) );
4777 return;
4778 }
4779
4780 if (!checkLinkSecurity(u,
4781 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>" ),
4782 i18n( "Submit" )))
4783 return;
4784
4785 // OK. We're actually going to submit stuff. Clear any redirections,
4786 // we should win over them
4787 d->clearRedirection();
4788
4789 KParts::OpenUrlArguments args;
4790
4791 if (!d->m_referrer.isEmpty())
4792 args.metaData()["referrer"] = d->m_referrer;
4793
4794 args.metaData().insert("PropagateHttpHeader", "true");
4795 args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
4796 args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
4797 args.metaData().insert("main_frame_request",
4798 parentPart() == 0 ? "TRUE":"FALSE");
4799 args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
4800 args.metaData().insert("ssl_activate_warnings", "TRUE");
4801//WABA: When we post a form we should treat it as the main url
4802//the request should never be considered cross-domain
4803//args.metaData().insert("cross-domain", toplevelURL().url());
4804 KParts::BrowserArguments browserArgs;
4805 browserArgs.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
4806
4807 // Handle mailto: forms
4808 if (u.protocol() == "mailto") {
4809 // 1) Check for attach= and strip it
4810 QString q = u.query().mid(1);
4811 QStringList nvps = q.split("&");
4812 bool triedToAttach = false;
4813
4814 QStringList::Iterator nvp = nvps.begin();
4815 const QStringList::Iterator nvpEnd = nvps.end();
4816
4817// cannot be a for loop as if something is removed we don't want to do ++nvp, as
4818// remove returns an iterator pointing to the next item
4819
4820 while (nvp != nvpEnd) {
4821 const QStringList pair = (*nvp).split("=");
4822 if (pair.count() >= 2) {
4823 if (pair.first().toLower() == "attach") {
4824 nvp = nvps.erase(nvp);
4825 triedToAttach = true;
4826 } else {
4827 ++nvp;
4828 }
4829 } else {
4830 ++nvp;
4831 }
4832 }
4833
4834 if (triedToAttach)
4835 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");
4836
4837 // 2) Append body=
4838 QString bodyEnc;
4839 if (contentType.toLower() == "multipart/form-data") {
4840 // FIXME: is this correct? I suspect not
4841 bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(),
4842 formData.size())));
4843 } else if (contentType.toLower() == "text/plain") {
4844 // Convention seems to be to decode, and s/&/\n/
4845 QString tmpbody = QString::fromLatin1(formData.data(),
4846 formData.size());
4847 tmpbody.replace(QRegExp("[&]"), "\n");
4848 tmpbody.replace(QRegExp("[+]"), " ");
4849 tmpbody = KUrl::fromPercentEncoding(tmpbody.toLatin1()); // Decode the rest of it
4850 bodyEnc = QLatin1String( KUrl::toPercentEncoding(tmpbody) ); // Recode for the URL
4851 } else {
4852 bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(),
4853 formData.size())) );
4854 }
4855
4856 nvps.append(QString("body=%1").arg(bodyEnc));
4857 q = nvps.join("&");
4858 u.setQuery(q);
4859 }
4860
4861 if ( strcmp( action, "get" ) == 0 ) {
4862 if (u.protocol() != "mailto")
4863 u.setQuery( QString::fromLatin1( formData.data(), formData.size() ) );
4864 browserArgs.setDoPost( false );
4865 }
4866 else {
4867 browserArgs.postData = formData;
4868 browserArgs.setDoPost( true );
4869
4870 // construct some user headers if necessary
4871 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
4872 browserArgs.setContentType( "Content-Type: application/x-www-form-urlencoded" );
4873 else // contentType must be "multipart/form-data"
4874 browserArgs.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
4875 }
4876
4877 if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
4878 if( d->m_submitForm ) {
4879 kDebug(6000) << "ABORTING!";
4880 return;
4881 }
4882 d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
4883 d->m_submitForm->submitAction = action;
4884 d->m_submitForm->submitUrl = url;
4885 d->m_submitForm->submitFormData = formData;
4886 d->m_submitForm->target = _target;
4887 d->m_submitForm->submitContentType = contentType;
4888 d->m_submitForm->submitBoundary = boundary;
4889 connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
4890 }
4891 else
4892 {
4893 emit d->m_extension->openUrlRequest( u, args, browserArgs );
4894 }
4895}
4896
4897void KHTMLPart::popupMenu( const QString &linkUrl )
4898{
4899 KUrl popupURL;
4900 KUrl linkKUrl;
4901 KParts::OpenUrlArguments args;
4902 KParts::BrowserArguments browserArgs;
4903 QString referrer;
4904 KParts::BrowserExtension::PopupFlags itemflags=KParts::BrowserExtension::ShowBookmark | KParts::BrowserExtension::ShowReload;
4905
4906 if ( linkUrl.isEmpty() ) { // click on background
4907 KHTMLPart* khtmlPart = this;
4908 while ( khtmlPart->parentPart() )
4909 {
4910 khtmlPart=khtmlPart->parentPart();
4911 }
4912 popupURL = khtmlPart->url();
4913 referrer = khtmlPart->pageReferrer();
4914 if (hasSelection())
4915 itemflags = KParts::BrowserExtension::ShowTextSelectionItems;
4916 else
4917 itemflags |= KParts::BrowserExtension::ShowNavigationItems;
4918 } else { // click on link
4919 popupURL = completeURL( linkUrl );
4920 linkKUrl = popupURL;
4921 referrer = this->referrer();
4922 itemflags |= KParts::BrowserExtension::IsLink;
4923
4924 if (!(d->m_strSelectedURLTarget).isEmpty() &&
4925 (d->m_strSelectedURLTarget.toLower() != "_top") &&
4926 (d->m_strSelectedURLTarget.toLower() != "_self") &&
4927 (d->m_strSelectedURLTarget.toLower() != "_parent")) {
4928 if (d->m_strSelectedURLTarget.toLower() == "_blank")
4929 browserArgs.setForcesNewWindow(true);
4930 else {
4931 KHTMLPart *p = this;
4932 while (p->parentPart())
4933 p = p->parentPart();
4934 if (!p->frameExists(d->m_strSelectedURLTarget))
4935 browserArgs.setForcesNewWindow(true);
4936 }
4937 }
4938 }
4939
4940 // Danger, Will Robinson. The Popup might stay around for a much
4941 // longer time than KHTMLPart. Deal with it.
4942 KHTMLPopupGUIClient* client = new KHTMLPopupGUIClient( this, linkKUrl );
4943 QPointer<QObject> guard( client );
4944
4945 QString mimetype = QLatin1String( "text/html" );
4946 args.metaData()["referrer"] = referrer;
4947
4948 if (!linkUrl.isEmpty()) // over a link
4949 {
4950 if (popupURL.isLocalFile()) // safe to do this
4951 {
4952 mimetype = KMimeType::findByUrl(popupURL,0,true,false)->name();
4953 }
4954 else // look at "extension" of link
4955 {
4956 const QString fname(popupURL.fileName(KUrl::ObeyTrailingSlash));
4957 if (!fname.isEmpty() && !popupURL.hasRef() && popupURL.query().isEmpty())
4958 {
4959 KMimeType::Ptr pmt = KMimeType::findByPath(fname,0,true);
4960
4961 // Further check for mime types guessed from the extension which,
4962 // on a web page, are more likely to be a script delivering content
4963 // of undecidable type. If the mime type from the extension is one
4964 // of these, don't use it. Retain the original type 'text/html'.
4965 if (pmt->name() != KMimeType::defaultMimeType() &&
4966 !pmt->is("application/x-perl") &&
4967 !pmt->is("application/x-perl-module") &&
4968 !pmt->is("application/x-php") &&
4969 !pmt->is("application/x-python-bytecode") &&
4970 !pmt->is("application/x-python") &&
4971 !pmt->is("application/x-shellscript"))
4972 mimetype = pmt->name();
4973 }
4974 }
4975 }
4976
4977 args.setMimeType(mimetype);
4978
4979 emit d->m_extension->popupMenu( QCursor::pos(), popupURL, S_IFREG /*always a file*/,
4980 args, browserArgs, itemflags,
4981 client->actionGroups() );
4982
4983 if ( !guard.isNull() ) {
4984 delete client;
4985 emit popupMenu(linkUrl, QCursor::pos());
4986 d->m_strSelectedURL.clear();
4987 d->m_strSelectedURLTarget.clear();
4988 }
4989}
4990
4991void KHTMLPart::slotParentCompleted()
4992{
4993 //kDebug(6050) << this;
4994 if ( !d->m_redirectURL.isEmpty() && !d->m_redirectionTimer.isActive() )
4995 {
4996 //kDebug(6050) << this << ": starting timer for child redirection -> " << d->m_redirectURL;
4997 d->m_redirectionTimer.setSingleShot( true );
4998 d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
4999 }
5000}
5001
5002void KHTMLPart::slotChildStarted( KIO::Job *job )
5003{
5004 khtml::ChildFrame *child = frame( sender() );
5005
5006 assert( child );
5007
5008 child->m_bCompleted = false;
5009
5010 if ( d->m_bComplete )
5011 {
5012#if 0
5013 // WABA: Looks like this belongs somewhere else
5014 if ( !parentPart() ) // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes
5015 {
5016 emit d->m_extension->openURLNotify();
5017 }
5018#endif
5019 d->m_bComplete = false;
5020 emit started( job );
5021 }
5022}
5023
5024void KHTMLPart::slotChildCompleted()
5025{
5026 slotChildCompleted( false );
5027}
5028
5029void KHTMLPart::slotChildCompleted( bool pendingAction )
5030{
5031 khtml::ChildFrame *child = frame( sender() );
5032
5033 if ( child ) {
5034 kDebug(6031) << this << "child=" << child << "m_partContainerElement=" << child->m_partContainerElement;
5035 child->m_bCompleted = true;
5036 child->m_bPendingRedirection = pendingAction;
5037 child->m_args = KParts::OpenUrlArguments();
5038 child->m_browserArgs = KParts::BrowserArguments();
5039 // dispatch load event. We don't do that for KHTMLPart's since their internal
5040 // load will be forwarded inside NodeImpl::dispatchWindowEvent
5041 if (!qobject_cast<KHTMLPart*>(child->m_part))
5042 QTimer::singleShot(0, child->m_partContainerElement.data(), SLOT(slotEmitLoadEvent()));
5043 }
5044 checkCompleted();
5045}
5046
5047void KHTMLPart::slotChildDocCreated()
5048{
5049 // Set domain to the frameset's domain
5050 // This must only be done when loading the frameset initially (#22039),
5051 // not when following a link in a frame (#44162).
5052 if (KHTMLPart* htmlFrame = qobject_cast<KHTMLPart*>(sender()))
5053 d->propagateInitialDomainAndBaseTo(htmlFrame);
5054
5055 // So it only happens once
5056 disconnect( sender(), SIGNAL(docCreated()), this, SLOT(slotChildDocCreated()) );
5057}
5058
5059void KHTMLPartPrivate::propagateInitialDomainAndBaseTo(KHTMLPart* kid)
5060{
5061 // This method is used to propagate our domain and base information for
5062 // child frames, to provide them for about: or JavaScript: URLs
5063 if ( m_doc && kid->d->m_doc ) {
5064 DocumentImpl* kidDoc = kid->d->m_doc;
5065 if ( kidDoc->origin()->isEmpty() ) {
5066 kidDoc->setOrigin ( m_doc->origin() );
5067 kidDoc->setBaseURL( m_doc->baseURL() );
5068 }
5069 }
5070}
5071
5072void KHTMLPart::slotChildURLRequest( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs )
5073{
5074 khtml::ChildFrame *child = frame( sender()->parent() );
5075 KHTMLPart *callingHtmlPart = const_cast<KHTMLPart *>(dynamic_cast<const KHTMLPart *>(sender()->parent()));
5076
5077 // TODO: handle child target correctly! currently the script are always executed for the parent
5078 QString urlStr = url.url();
5079 if ( d->isJavaScriptURL(urlStr) ) {
5080 executeScript( DOM::Node(), d->codeForJavaScriptURL(urlStr) );
5081 return;
5082 }
5083
5084 QString frameName = browserArgs.frameName.toLower();
5085 if ( !frameName.isEmpty() ) {
5086 if ( frameName == QLatin1String( "_top" ) )
5087 {
5088 emit d->m_extension->openUrlRequest( url, args, browserArgs );
5089 return;
5090 }
5091 else if ( frameName == QLatin1String( "_blank" ) )
5092 {
5093 emit d->m_extension->createNewWindow( url, args, browserArgs );
5094 return;
5095 }
5096 else if ( frameName == QLatin1String( "_parent" ) )
5097 {
5098 KParts::BrowserArguments newBrowserArgs( browserArgs );
5099 newBrowserArgs.frameName.clear();
5100 emit d->m_extension->openUrlRequest( url, args, newBrowserArgs );
5101 return;
5102 }
5103 else if ( frameName != QLatin1String( "_self" ) )
5104 {
5105 khtml::ChildFrame *_frame = recursiveFrameRequest( callingHtmlPart, url, args, browserArgs );
5106
5107 if ( !_frame )
5108 {
5109 emit d->m_extension->openUrlRequest( url, args, browserArgs );
5110 return;
5111 }
5112
5113 child = _frame;
5114 }
5115 }
5116
5117 if ( child && child->m_type != khtml::ChildFrame::Object ) {
5118 // Inform someone that we are about to show something else.
5119 child->m_bNotify = true;
5120 requestObject( child, url, args, browserArgs );
5121 } else if ( frameName== "_self" ) // this is for embedded objects (via <object>) which want to replace the current document
5122 {
5123 KParts::BrowserArguments newBrowserArgs( browserArgs );
5124 newBrowserArgs.frameName.clear();
5125 emit d->m_extension->openUrlRequest( url, args, newBrowserArgs );
5126 }
5127}
5128
5129void KHTMLPart::slotRequestFocus( KParts::ReadOnlyPart * )
5130{
5131 emit d->m_extension->requestFocus(this);
5132}
5133
5134khtml::ChildFrame *KHTMLPart::frame( const QObject *obj )
5135{
5136 assert( obj->inherits( "KParts::ReadOnlyPart" ) );
5137 const KParts::ReadOnlyPart* const part = static_cast<const KParts::ReadOnlyPart *>( obj );
5138
5139 FrameIt it = d->m_frames.begin();
5140 const FrameIt end = d->m_frames.end();
5141 for (; it != end; ++it ) {
5142 if ((*it)->m_part.data() == part )
5143 return *it;
5144 }
5145
5146 FrameIt oi = d->m_objects.begin();
5147 const FrameIt oiEnd = d->m_objects.end();
5148 for (; oi != oiEnd; ++oi ) {
5149 if ((*oi)->m_part.data() == part)
5150 return *oi;
5151 }
5152
5153 return 0L;
5154}
5155
5156//#define DEBUG_FINDFRAME
5157
5158bool KHTMLPart::checkFrameAccess(KHTMLPart *callingHtmlPart)
5159{
5160 if (callingHtmlPart == this)
5161 return true; // trivial
5162
5163 if (!xmlDocImpl()) {
5164#ifdef DEBUG_FINDFRAME
5165 kDebug(6050) << "Empty part" << this << "URL = " << url();
5166#endif
5167 return false; // we are empty?
5168 }
5169
5170 // now compare the domains
5171 if (callingHtmlPart && callingHtmlPart->xmlDocImpl() && xmlDocImpl()) {
5172 khtml::SecurityOrigin* actDomain = callingHtmlPart->xmlDocImpl()->origin();
5173 khtml::SecurityOrigin* destDomain = xmlDocImpl()->origin();
5174
5175 if (actDomain->canAccess(destDomain))
5176 return true;
5177 }
5178#ifdef DEBUG_FINDFRAME
5179 else
5180 {
5181 kDebug(6050) << "Unknown part/domain" << callingHtmlPart << "tries to access part" << this;
5182 }
5183#endif
5184 return false;
5185}
5186
5187KHTMLPart *
5188KHTMLPart::findFrameParent( KParts::ReadOnlyPart *callingPart, const QString &f, khtml::ChildFrame **childFrame )
5189{
5190 return d->findFrameParent(callingPart, f, childFrame, false);
5191}
5192
5193KHTMLPart* KHTMLPartPrivate::findFrameParent(KParts::ReadOnlyPart* callingPart,
5194 const QString& f, khtml::ChildFrame **childFrame, bool checkForNavigation)
5195{
5196#ifdef DEBUG_FINDFRAME
5197 kDebug(6050) << q << "URL =" << q->url() << "name =" << q->objectName() << "findFrameParent(" << f << ")";
5198#endif
5199 // Check access
5200 KHTMLPart* const callingHtmlPart = qobject_cast<KHTMLPart *>(callingPart);
5201
5202 if (!callingHtmlPart)
5203 return 0;
5204
5205 if (!checkForNavigation && !q->checkFrameAccess(callingHtmlPart))
5206 return 0;
5207
5208 if (!childFrame && !q->parentPart() && (q->objectName() == f)) {
5209 if (!checkForNavigation || callingHtmlPart->d->canNavigate(q))
5210 return q;
5211 }
5212
5213 FrameIt it = m_frames.find( f );
5214 const FrameIt end = m_frames.end();
5215 if ( it != end )
5216 {
5217#ifdef DEBUG_FINDFRAME
5218 kDebug(6050) << "FOUND!";
5219#endif
5220 if (!checkForNavigation || callingHtmlPart->d->canNavigate((*it)->m_part.data())) {
5221 if (childFrame)
5222 *childFrame = *it;
5223 return q;
5224 }
5225 }
5226
5227 it = m_frames.begin();
5228 for (; it != end; ++it )
5229 {
5230 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
5231 {
5232 KHTMLPart* const frameParent = p->d->findFrameParent(callingPart, f, childFrame, checkForNavigation);
5233 if (frameParent)
5234 return frameParent;
5235 }
5236 }
5237 return 0;
5238}
5239
5240KHTMLPart* KHTMLPartPrivate::top()
5241{
5242 KHTMLPart* t = q;
5243 while (t->parentPart())
5244 t = t->parentPart();
5245 return t;
5246}
5247
5248bool KHTMLPartPrivate::canNavigate(KParts::ReadOnlyPart* bCand)
5249{
5250 if (!bCand) // No part here (e.g. invalid url), reuse that frame
5251 return true;
5252
5253 KHTMLPart* b = qobject_cast<KHTMLPart*>(bCand);
5254 if (!b) // Another kind of part? Not sure what to do...
5255 return false;
5256
5257 // HTML5 gives conditions for this (a) being able to navigate b
5258
5259 // 1) Same domain
5260 if (q->checkFrameAccess(b))
5261 return true;
5262
5263 // 2) A is nested, with B its top
5264 if (q->parentPart() && top() == b)
5265 return true;
5266
5267 // 3) B is 'auxilary' -- window.open with opener,
5268 // and A can navigate B's opener
5269 if (b->opener() && canNavigate(b->opener()))
5270 return true;
5271
5272 // 4) B is not top-level, but an ancestor of it has same origin as A
5273 for (KHTMLPart* anc = b->parentPart(); anc; anc = anc->parentPart()) {
5274 if (anc->checkFrameAccess(q))
5275 return true;
5276 }
5277
5278 return false;
5279}
5280
5281KHTMLPart *KHTMLPart::findFrame( const QString &f )
5282{
5283 khtml::ChildFrame *childFrame;
5284 KHTMLPart *parentFrame = findFrameParent(this, f, &childFrame);
5285 if (parentFrame)
5286 return qobject_cast<KHTMLPart*>(childFrame->m_part.data());
5287
5288 return 0;
5289}
5290
5291KParts::ReadOnlyPart *KHTMLPart::findFramePart(const QString &f)
5292{
5293 khtml::ChildFrame *childFrame;
5294 return findFrameParent(this, f, &childFrame) ? childFrame->m_part.data() : 0L;
5295}
5296
5297KParts::ReadOnlyPart *KHTMLPart::currentFrame() const
5298{
5299 KParts::ReadOnlyPart* part = (KParts::ReadOnlyPart*)(this);
5300 // Find active part in our frame manager, in case we are a frameset
5301 // and keep doing that (in case of nested framesets).
5302 // Just realized we could also do this recursively, calling part->currentFrame()...
5303 while ( part && part->inherits("KHTMLPart") &&
5304 static_cast<KHTMLPart *>(part)->d->m_frames.count() > 0 ) {
5305 KHTMLPart* frameset = static_cast<KHTMLPart *>(part);
5306 part = static_cast<KParts::ReadOnlyPart *>(frameset->partManager()->activePart());
5307 if ( !part ) return frameset;
5308 }
5309 return part;
5310}
5311
5312bool KHTMLPart::frameExists( const QString &frameName )
5313{
5314 FrameIt it = d->m_frames.find( frameName );
5315 if ( it == d->m_frames.end() )
5316 return false;
5317
5318 // WABA: We only return true if the child actually has a frame
5319 // set. Otherwise we might find our preloaded-selve.
5320 // This happens when we restore the frameset.
5321 return (!(*it)->m_partContainerElement.isNull());
5322}
5323
5324void KHTMLPartPrivate::renameFrameForContainer(DOM::HTMLPartContainerElementImpl* cont,
5325 const QString& newName)
5326{
5327 for (int i = 0; i < m_frames.size(); ++i) {
5328 khtml::ChildFrame* f = m_frames[i];
5329 if (f->m_partContainerElement.data() == cont)
5330 f->m_name = newName;
5331 }
5332}
5333
5334KJSProxy *KHTMLPart::framejScript(KParts::ReadOnlyPart *framePart)
5335{
5336 KHTMLPart* const kp = qobject_cast<KHTMLPart*>(framePart);
5337 if (kp)
5338 return kp->jScript();
5339
5340 FrameIt it = d->m_frames.begin();
5341 const FrameIt itEnd = d->m_frames.end();
5342
5343 for (; it != itEnd; ++it) {
5344 khtml::ChildFrame* frame = *it;
5345 if (framePart == frame->m_part.data()) {
5346 if (!frame->m_jscript)
5347 frame->m_jscript = new KJSProxy(frame);
5348 return frame->m_jscript;
5349 }
5350 }
5351 return 0L;
5352}
5353
5354KHTMLPart *KHTMLPart::parentPart()
5355{
5356 return qobject_cast<KHTMLPart*>( parent() );
5357}
5358
5359khtml::ChildFrame *KHTMLPart::recursiveFrameRequest( KHTMLPart *callingHtmlPart, const KUrl &url,
5360 const KParts::OpenUrlArguments &args,
5361 const KParts::BrowserArguments &browserArgs, bool callParent )
5362{
5363#ifdef DEBUG_FINDFRAME
5364 kDebug( 6050 ) << this << "frame = " << browserArgs.frameName << "url = " << url;
5365#endif
5366 khtml::ChildFrame *childFrame;
5367 KHTMLPart *childPart = findFrameParent(callingHtmlPart, browserArgs.frameName, &childFrame);
5368 if (childPart)
5369 {
5370 if (childPart == this)
5371 return childFrame;
5372
5373 childPart->requestObject( childFrame, url, args, browserArgs );
5374 return 0;
5375 }
5376
5377 if ( parentPart() && callParent )
5378 {
5379 khtml::ChildFrame *res = parentPart()->recursiveFrameRequest( callingHtmlPart, url, args, browserArgs, callParent );
5380
5381 if ( res )
5382 parentPart()->requestObject( res, url, args, browserArgs );
5383 }
5384
5385 return 0L;
5386}
5387
5388#ifdef DEBUG_SAVESTATE
5389static int s_saveStateIndentLevel = 0;
5390#endif
5391
5392void KHTMLPart::saveState( QDataStream &stream )
5393{
5394#ifdef DEBUG_SAVESTATE
5395 QString indent= QString().leftJustified( s_saveStateIndentLevel * 4, ' ' );
5396 const int indentLevel = s_saveStateIndentLevel++;
5397 kDebug( 6050 ) << indent << "saveState this=" << this << " '" << objectName() << "' saving URL " << url().url();
5398#endif
5399
5400 stream << url() << (qint32)d->m_view->contentsX() << (qint32)d->m_view->contentsY()
5401 << (qint32) d->m_view->contentsWidth() << (qint32) d->m_view->contentsHeight() << (qint32) d->m_view->marginWidth() << (qint32) d->m_view->marginHeight();
5402
5403 // save link cursor position
5404 int focusNodeNumber;
5405 if (!d->m_focusNodeRestored)
5406 focusNodeNumber = d->m_focusNodeNumber;
5407 else if (d->m_doc && d->m_doc->focusNode())
5408 focusNodeNumber = d->m_doc->nodeAbsIndex(d->m_doc->focusNode());
5409 else
5410 focusNodeNumber = -1;
5411 stream << focusNodeNumber;
5412
5413 // Save the doc's cache id.
5414 stream << d->m_cacheId;
5415
5416 // Save the state of the document (Most notably the state of any forms)
5417 QStringList docState;
5418 if (d->m_doc)
5419 {
5420 docState = d->m_doc->docState();
5421 }
5422 stream << d->m_encoding << d->m_sheetUsed << docState;
5423
5424 stream << d->m_zoomFactor;
5425 stream << d->m_fontScaleFactor;
5426
5427 stream << d->m_httpHeaders;
5428 stream << d->m_pageServices;
5429 stream << d->m_pageReferrer;
5430
5431 // Save ssl data
5432 stream << d->m_ssl_in_use
5433 << d->m_ssl_peer_chain
5434 << d->m_ssl_peer_ip
5435 << d->m_ssl_cipher
5436 << d->m_ssl_protocol_version
5437 << d->m_ssl_cipher_used_bits
5438 << d->m_ssl_cipher_bits
5439 << d->m_ssl_cert_errors
5440 << d->m_ssl_parent_ip
5441 << d->m_ssl_parent_cert;
5442
5443
5444 QStringList frameNameLst, frameServiceTypeLst, frameServiceNameLst;
5445 KUrl::List frameURLLst;
5446 QList<QByteArray> frameStateBufferLst;
5447 QList<int> frameTypeLst;
5448
5449 ConstFrameIt it = d->m_frames.constBegin();
5450 const ConstFrameIt end = d->m_frames.constEnd();
5451 for (; it != end; ++it )
5452 {
5453 if ( !(*it)->m_part )
5454 continue;
5455
5456 frameNameLst << (*it)->m_name;
5457 frameServiceTypeLst << (*it)->m_serviceType;
5458 frameServiceNameLst << (*it)->m_serviceName;
5459 frameURLLst << (*it)->m_part.data()->url();
5460
5461 QByteArray state;
5462 QDataStream frameStream( &state, QIODevice::WriteOnly );
5463
5464 if ( (*it)->m_extension )
5465 (*it)->m_extension.data()->saveState( frameStream );
5466
5467 frameStateBufferLst << state;
5468
5469 frameTypeLst << int( (*it)->m_type );
5470 }
5471
5472 // Save frame data
5473 stream << (quint32) frameNameLst.count();
5474 stream << frameNameLst << frameServiceTypeLst << frameServiceNameLst << frameURLLst << frameStateBufferLst << frameTypeLst;
5475#ifdef DEBUG_SAVESTATE
5476 s_saveStateIndentLevel = indentLevel;
5477#endif
5478}
5479
5480void KHTMLPart::restoreState( QDataStream &stream )
5481{
5482 KUrl u;
5483 qint32 xOffset, yOffset, wContents, hContents, mWidth, mHeight;
5484 quint32 frameCount;
5485 QStringList frameNames, frameServiceTypes, docState, frameServiceNames;
5486 QList<int> frameTypes;
5487 KUrl::List frameURLs;
5488 QList<QByteArray> frameStateBuffers;
5489 QList<int> fSizes;
5490 QString encoding, sheetUsed;
5491 long old_cacheId = d->m_cacheId;
5492
5493 stream >> u >> xOffset >> yOffset >> wContents >> hContents >> mWidth >> mHeight;
5494
5495 d->m_view->setMarginWidth( mWidth );
5496 d->m_view->setMarginHeight( mHeight );
5497
5498 // restore link cursor position
5499 // nth node is active. value is set in checkCompleted()
5500 stream >> d->m_focusNodeNumber;
5501 d->m_focusNodeRestored = false;
5502
5503 stream >> d->m_cacheId;
5504
5505 stream >> encoding >> sheetUsed >> docState;
5506
5507 d->m_encoding = encoding;
5508 d->m_sheetUsed = sheetUsed;
5509
5510 int zoomFactor;
5511 stream >> zoomFactor;
5512 setZoomFactor(zoomFactor);
5513
5514 int fontScaleFactor;
5515 stream >> fontScaleFactor;
5516 setFontScaleFactor(fontScaleFactor);
5517
5518 stream >> d->m_httpHeaders;
5519 stream >> d->m_pageServices;
5520 stream >> d->m_pageReferrer;
5521
5522 // Restore ssl data
5523 stream >> d->m_ssl_in_use
5524 >> d->m_ssl_peer_chain
5525 >> d->m_ssl_peer_ip
5526 >> d->m_ssl_cipher
5527 >> d->m_ssl_protocol_version
5528 >> d->m_ssl_cipher_used_bits
5529 >> d->m_ssl_cipher_bits
5530 >> d->m_ssl_cert_errors
5531 >> d->m_ssl_parent_ip
5532 >> d->m_ssl_parent_cert;
5533
5534 setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
5535
5536 stream >> frameCount >> frameNames >> frameServiceTypes >> frameServiceNames
5537 >> frameURLs >> frameStateBuffers >> frameTypes;
5538
5539 d->m_bComplete = false;
5540 d->m_bLoadEventEmitted = false;
5541
5542// kDebug( 6050 ) << "docState.count() = " << docState.count();
5543// kDebug( 6050 ) << "m_url " << url().url() << " <-> " << u.url();
5544// kDebug( 6050 ) << "m_frames.count() " << d->m_frames.count() << " <-> " << frameCount;
5545
5546 if (d->m_cacheId == old_cacheId && signed(frameCount) == d->m_frames.count())
5547 {
5548 // Partial restore
5549 d->m_redirectionTimer.stop();
5550
5551 FrameIt fIt = d->m_frames.begin();
5552 const FrameIt fEnd = d->m_frames.end();
5553
5554 for (; fIt != fEnd; ++fIt )
5555 (*fIt)->m_bCompleted = false;
5556
5557 fIt = d->m_frames.begin();
5558
5559 QStringList::ConstIterator fNameIt = frameNames.constBegin();
5560 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin();
5561 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin();
5562 KUrl::List::ConstIterator fURLIt = frameURLs.constBegin();
5563 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin();
5564 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin();
5565
5566 for (; fIt != fEnd; ++fIt, ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt )
5567 {
5568 khtml::ChildFrame* const child = *fIt;
5569
5570// kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt;
5571
5572 if ( child->m_name != *fNameIt || child->m_serviceType != *fServiceTypeIt )
5573 {
5574 child->m_bPreloaded = true;
5575 child->m_name = *fNameIt;
5576 child->m_serviceName = *fServiceNameIt;
5577 child->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt);
5578 processObjectRequest( child, *fURLIt, *fServiceTypeIt );
5579 }
5580 if ( child->m_part )
5581 {
5582 child->m_bCompleted = false;
5583 if ( child->m_extension && !(*fBufferIt).isEmpty() )
5584 {
5585 QDataStream frameStream( *fBufferIt );
5586 child->m_extension.data()->restoreState( frameStream );
5587 }
5588 else
5589 child->m_part.data()->openUrl( *fURLIt );
5590 }
5591 }
5592
5593 KParts::OpenUrlArguments args( arguments() );
5594 args.setXOffset(xOffset);
5595 args.setYOffset(yOffset);
5596 setArguments(args);
5597
5598 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
5599 browserArgs.docState = docState;
5600 d->m_extension->setBrowserArguments(browserArgs);
5601
5602 d->m_view->resizeContents( wContents, hContents );
5603 d->m_view->setContentsPos( xOffset, yOffset );
5604
5605 setUrl(u);
5606 }
5607 else
5608 {
5609 // Full restore.
5610 closeUrl();
5611 // We must force a clear because we want to be sure to delete all
5612 // frames.
5613 d->m_bCleared = false;
5614 clear();
5615 d->m_encoding = encoding;
5616 d->m_sheetUsed = sheetUsed;
5617
5618 QStringList::ConstIterator fNameIt = frameNames.constBegin();
5619 const QStringList::ConstIterator fNameEnd = frameNames.constEnd();
5620
5621 QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin();
5622 QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin();
5623 KUrl::List::ConstIterator fURLIt = frameURLs.constBegin();
5624 QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin();
5625 QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin();
5626
5627 for (; fNameIt != fNameEnd; ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt )
5628 {
5629 khtml::ChildFrame* const newChild = new khtml::ChildFrame;
5630 newChild->m_bPreloaded = true;
5631 newChild->m_name = *fNameIt;
5632 newChild->m_serviceName = *fServiceNameIt;
5633 newChild->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt);
5634
5635// kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt;
5636
5637 const FrameIt childFrame = d->m_frames.insert( d->m_frames.end(), newChild );
5638
5639 processObjectRequest( *childFrame, *fURLIt, *fServiceTypeIt );
5640
5641 (*childFrame)->m_bPreloaded = true;
5642
5643 if ( (*childFrame)->m_part )
5644 {
5645 if ( (*childFrame)->m_extension && !(*fBufferIt).isEmpty() )
5646 {
5647 QDataStream frameStream( *fBufferIt );
5648 (*childFrame)->m_extension.data()->restoreState( frameStream );
5649 }
5650 else
5651 (*childFrame)->m_part.data()->openUrl( *fURLIt );
5652 }
5653 }
5654
5655 KParts::OpenUrlArguments args( arguments() );
5656 args.setXOffset(xOffset);
5657 args.setYOffset(yOffset);
5658 setArguments(args);
5659
5660 KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
5661 browserArgs.docState = docState;
5662 d->m_extension->setBrowserArguments(browserArgs);
5663
5664 if (!KHTMLPageCache::self()->isComplete(d->m_cacheId))
5665 {
5666 d->m_restored = true;
5667 openUrl( u );
5668 d->m_restored = false;
5669 }
5670 else
5671 {
5672 restoreURL( u );
5673 }
5674 }
5675
5676}
5677
5678void KHTMLPart::show()
5679{
5680 if ( widget() )
5681 widget()->show();
5682}
5683
5684void KHTMLPart::hide()
5685{
5686 if ( widget() )
5687 widget()->hide();
5688}
5689
5690DOM::Node KHTMLPart::nodeUnderMouse() const
5691{
5692 return d->m_view->nodeUnderMouse();
5693}
5694
5695DOM::Node KHTMLPart::nonSharedNodeUnderMouse() const
5696{
5697 return d->m_view->nonSharedNodeUnderMouse();
5698}
5699
5700void KHTMLPart::emitSelectionChanged()
5701{
5702 // Don't emit signals about our selection if this is a frameset;
5703 // the active frame has the selection (#187403)
5704 if (!d->m_activeFrame)
5705 {
5706 emit d->m_extension->enableAction( "copy", hasSelection() );
5707 emit d->m_extension->selectionInfo( selectedText() );
5708 emit selectionChanged();
5709 }
5710}
5711
5712int KHTMLPart::zoomFactor() const
5713{
5714 return d->m_zoomFactor;
5715}
5716
5717// ### make the list configurable ?
5718static const int zoomSizes[] = { 20, 40, 60, 80, 90, 95, 100, 105, 110, 120, 140, 160, 180, 200, 250, 300 };
5719static const int zoomSizeCount = (sizeof(zoomSizes) / sizeof(int));
5720static const int minZoom = 20;
5721static const int maxZoom = 300;
5722
5723// My idea of useful stepping ;-) (LS)
5724extern const int KDE_NO_EXPORT fastZoomSizes[] = { 20, 50, 75, 90, 100, 120, 150, 200, 300 };
5725extern const int KDE_NO_EXPORT fastZoomSizeCount = sizeof fastZoomSizes / sizeof fastZoomSizes[0];
5726
5727void KHTMLPart::slotIncZoom()
5728{
5729 zoomIn(zoomSizes, zoomSizeCount);
5730}
5731
5732void KHTMLPart::slotDecZoom()
5733{
5734 zoomOut(zoomSizes, zoomSizeCount);
5735}
5736
5737void KHTMLPart::slotIncZoomFast()
5738{
5739 zoomIn(fastZoomSizes, fastZoomSizeCount);
5740}
5741
5742void KHTMLPart::slotDecZoomFast()
5743{
5744 zoomOut(fastZoomSizes, fastZoomSizeCount);
5745}
5746
5747void KHTMLPart::zoomIn(const int stepping[], int count)
5748{
5749 int zoomFactor = d->m_zoomFactor;
5750
5751 if (zoomFactor < maxZoom) {
5752 // find the entry nearest to the given zoomsizes
5753 for (int i = 0; i < count; ++i)
5754 if (stepping[i] > zoomFactor) {
5755 zoomFactor = stepping[i];
5756 break;
5757 }
5758 setZoomFactor(zoomFactor);
5759 }
5760}
5761
5762void KHTMLPart::zoomOut(const int stepping[], int count)
5763{
5764 int zoomFactor = d->m_zoomFactor;
5765 if (zoomFactor > minZoom) {
5766 // find the entry nearest to the given zoomsizes
5767 for (int i = count-1; i >= 0; --i)
5768 if (stepping[i] < zoomFactor) {
5769 zoomFactor = stepping[i];
5770 break;
5771 }
5772 setZoomFactor(zoomFactor);
5773 }
5774}
5775
5776void KHTMLPart::setZoomFactor (int percent)
5777{
5778 // ### zooming under 100% is majorly botched,
5779 // so disable that for now.
5780 if (percent < 100) percent = 100;
5781 // ### if (percent < minZoom) percent = minZoom;
5782
5783 if (percent > maxZoom) percent = maxZoom;
5784 if (d->m_zoomFactor == percent) return;
5785 d->m_zoomFactor = percent;
5786
5787 updateZoomFactor();
5788}
5789
5790
5791void KHTMLPart::updateZoomFactor ()
5792{
5793 if(d->m_view) {
5794 QApplication::setOverrideCursor( Qt::WaitCursor );
5795 d->m_view->setZoomLevel( d->m_zoomFactor );
5796 QApplication::restoreOverrideCursor();
5797 }
5798
5799 ConstFrameIt it = d->m_frames.constBegin();
5800 const ConstFrameIt end = d->m_frames.constEnd();
5801 for (; it != end; ++it ) {
5802 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
5803 p->setZoomFactor(d->m_zoomFactor);
5804 }
5805
5806 if ( d->m_guiProfile == BrowserViewGUI ) {
5807 d->m_paDecZoomFactor->setEnabled( d->m_zoomFactor > minZoom );
5808 d->m_paIncZoomFactor->setEnabled( d->m_zoomFactor < maxZoom );
5809 }
5810}
5811
5812void KHTMLPart::slotIncFontSize()
5813{
5814 incFontSize(zoomSizes, zoomSizeCount);
5815}
5816
5817void KHTMLPart::slotDecFontSize()
5818{
5819 decFontSize(zoomSizes, zoomSizeCount);
5820}
5821
5822void KHTMLPart::slotIncFontSizeFast()
5823{
5824 incFontSize(fastZoomSizes, fastZoomSizeCount);
5825}
5826
5827void KHTMLPart::slotDecFontSizeFast()
5828{
5829 decFontSize(fastZoomSizes, fastZoomSizeCount);
5830}
5831
5832void KHTMLPart::incFontSize(const int stepping[], int count)
5833{
5834 int zoomFactor = d->m_fontScaleFactor;
5835
5836 if (zoomFactor < maxZoom) {
5837 // find the entry nearest to the given zoomsizes
5838 for (int i = 0; i < count; ++i)
5839 if (stepping[i] > zoomFactor) {
5840 zoomFactor = stepping[i];
5841 break;
5842 }
5843 setFontScaleFactor(zoomFactor);
5844 }
5845}
5846
5847void KHTMLPart::decFontSize(const int stepping[], int count)
5848{
5849 int zoomFactor = d->m_fontScaleFactor;
5850 if (zoomFactor > minZoom) {
5851 // find the entry nearest to the given zoomsizes
5852 for (int i = count-1; i >= 0; --i)
5853 if (stepping[i] < zoomFactor) {
5854 zoomFactor = stepping[i];
5855 break;
5856 }
5857 setFontScaleFactor(zoomFactor);
5858 }
5859}
5860
5861void KHTMLPart::setFontScaleFactor(int percent)
5862{
5863 if (percent < minZoom) percent = minZoom;
5864 if (percent > maxZoom) percent = maxZoom;
5865 if (d->m_fontScaleFactor == percent) return;
5866 d->m_fontScaleFactor = percent;
5867
5868 if (d->m_view && d->m_doc) {
5869 QApplication::setOverrideCursor( Qt::WaitCursor );
5870 if (d->m_doc->styleSelector())
5871 d->m_doc->styleSelector()->computeFontSizes(d->m_doc->logicalDpiY(), d->m_fontScaleFactor);
5872 d->m_doc->recalcStyle( NodeImpl::Force );
5873 QApplication::restoreOverrideCursor();
5874 }
5875
5876 ConstFrameIt it = d->m_frames.constBegin();
5877 const ConstFrameIt end = d->m_frames.constEnd();
5878 for (; it != end; ++it ) {
5879 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
5880 p->setFontScaleFactor(d->m_fontScaleFactor);
5881 }
5882}
5883
5884int KHTMLPart::fontScaleFactor() const
5885{
5886 return d->m_fontScaleFactor;
5887}
5888
5889void KHTMLPart::slotZoomView( int delta )
5890{
5891 if ( delta < 0 )
5892 slotIncZoom();
5893 else
5894 slotDecZoom();
5895}
5896
5897void KHTMLPart::setStatusBarText( const QString& text, StatusBarPriority p)
5898{
5899 if (!d->m_statusMessagesEnabled)
5900 return;
5901
5902 d->m_statusBarText[p] = text;
5903
5904 // shift handling ?
5905 QString tobe = d->m_statusBarText[BarHoverText];
5906 if (tobe.isEmpty())
5907 tobe = d->m_statusBarText[BarOverrideText];
5908 if (tobe.isEmpty()) {
5909 tobe = d->m_statusBarText[BarDefaultText];
5910 if (!tobe.isEmpty() && d->m_jobspeed)
5911 tobe += " ";
5912 if (d->m_jobspeed)
5913 tobe += i18n( "(%1/s)" , KIO::convertSize( d->m_jobspeed ) );
5914 }
5915 tobe = "<qt>"+tobe;
5916
5917 emit ReadOnlyPart::setStatusBarText(tobe);
5918}
5919
5920
5921void KHTMLPart::setJSStatusBarText( const QString &text )
5922{
5923 setStatusBarText(text, BarOverrideText);
5924}
5925
5926void KHTMLPart::setJSDefaultStatusBarText( const QString &text )
5927{
5928 setStatusBarText(text, BarDefaultText);
5929}
5930
5931QString KHTMLPart::jsStatusBarText() const
5932{
5933 return d->m_statusBarText[BarOverrideText];
5934}
5935
5936QString KHTMLPart::jsDefaultStatusBarText() const
5937{
5938 return d->m_statusBarText[BarDefaultText];
5939}
5940
5941QString KHTMLPart::referrer() const
5942{
5943 return d->m_referrer;
5944}
5945
5946QString KHTMLPart::pageReferrer() const
5947{
5948 KUrl referrerURL = KUrl( d->m_pageReferrer );
5949 if (referrerURL.isValid())
5950 {
5951 QString protocol = referrerURL.protocol();
5952
5953 if ((protocol == "http") ||
5954 ((protocol == "https") && (url().protocol() == "https")))
5955 {
5956 referrerURL.setRef(QString());
5957 referrerURL.setUser(QString());
5958 referrerURL.setPass(QString());
5959 return referrerURL.url();
5960 }
5961 }
5962
5963 return QString();
5964}
5965
5966
5967QString KHTMLPart::lastModified() const
5968{
5969 if ( d->m_lastModified.isEmpty() && url().isLocalFile() ) {
5970 // Local file: set last-modified from the file's mtime.
5971 // Done on demand to save time when this isn't needed - but can lead
5972 // to slightly wrong results if updating the file on disk w/o reloading.
5973 QDateTime lastModif = QFileInfo( url().toLocalFile() ).lastModified();
5974 d->m_lastModified = lastModif.toString( Qt::LocalDate );
5975 }
5976 //kDebug(6050) << d->m_lastModified;
5977 return d->m_lastModified;
5978}
5979
5980void KHTMLPart::slotLoadImages()
5981{
5982 if (d->m_doc )
5983 d->m_doc->docLoader()->setAutoloadImages( !d->m_doc->docLoader()->autoloadImages() );
5984
5985 ConstFrameIt it = d->m_frames.constBegin();
5986 const ConstFrameIt end = d->m_frames.constEnd();
5987 for (; it != end; ++it ) {
5988 if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
5989 p->slotLoadImages();
5990 }
5991}
5992
5993void KHTMLPart::reparseConfiguration()
5994{
5995 KHTMLSettings *settings = KHTMLGlobal::defaultHTMLSettings();
5996 settings->init();
5997
5998 setAutoloadImages( settings->autoLoadImages() );
5999 if (d->m_doc)
6000 d->m_doc->docLoader()->setShowAnimations( settings->showAnimations() );
6001
6002 d->m_bOpenMiddleClick = settings->isOpenMiddleClickEnabled();
6003 d->m_bJScriptEnabled = settings->isJavaScriptEnabled(url().host());
6004 setDebugScript( settings->isJavaScriptDebugEnabled() );
6005 d->m_bJavaEnabled = settings->isJavaEnabled(url().host());
6006 d->m_bPluginsEnabled = settings->isPluginsEnabled(url().host());
6007 d->m_metaRefreshEnabled = settings->isAutoDelayedActionsEnabled ();
6008
6009 delete d->m_settings;
6010 d->m_settings = new KHTMLSettings(*KHTMLGlobal::defaultHTMLSettings());
6011
6012 QApplication::setOverrideCursor( Qt::WaitCursor );
6013 khtml::CSSStyleSelector::reparseConfiguration();
6014 if(d->m_doc) d->m_doc->updateStyleSelector();
6015 QApplication::restoreOverrideCursor();
6016
6017 if (d->m_view) {
6018 KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling();
6019 if (ssm == KHTMLSettings::KSmoothScrollingDisabled)
6020 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled);
6021 else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient)
6022 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient);
6023 else
6024 d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled);
6025 }
6026
6027 if (KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled())
6028 runAdFilter();
6029}
6030
6031QStringList KHTMLPart::frameNames() const
6032{
6033 QStringList res;
6034
6035 ConstFrameIt it = d->m_frames.constBegin();
6036 const ConstFrameIt end = d->m_frames.constEnd();
6037 for (; it != end; ++it )
6038 if (!(*it)->m_bPreloaded && (*it)->m_part)
6039 res += (*it)->m_name;
6040
6041 return res;
6042}
6043
6044QList<KParts::ReadOnlyPart*> KHTMLPart::frames() const
6045{
6046 QList<KParts::ReadOnlyPart*> res;
6047
6048 ConstFrameIt it = d->m_frames.constBegin();
6049 const ConstFrameIt end = d->m_frames.constEnd();
6050 for (; it != end; ++it )
6051 if (!(*it)->m_bPreloaded && (*it)->m_part) // ### TODO: make sure that we always create an empty
6052 // KHTMLPart for frames so this never happens.
6053 res.append( (*it)->m_part.data() );
6054
6055 return res;
6056}
6057
6058bool KHTMLPart::openUrlInFrame( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs)
6059{
6060 kDebug( 6031 ) << this << url;
6061 FrameIt it = d->m_frames.find( browserArgs.frameName );
6062
6063 if ( it == d->m_frames.end() )
6064 return false;
6065
6066 // Inform someone that we are about to show something else.
6067 if ( !browserArgs.lockHistory() )
6068 emit d->m_extension->openUrlNotify();
6069
6070 requestObject( *it, url, args, browserArgs );
6071
6072 return true;
6073}
6074
6075void KHTMLPart::setDNDEnabled( bool b )
6076{
6077 d->m_bDnd = b;
6078}
6079
6080bool KHTMLPart::dndEnabled() const
6081{
6082 return d->m_bDnd;
6083}
6084
6085void KHTMLPart::customEvent( QEvent *event )
6086{
6087 if ( khtml::MousePressEvent::test( event ) )
6088 {
6089 khtmlMousePressEvent( static_cast<khtml::MousePressEvent *>( event ) );
6090 return;
6091 }
6092
6093 if ( khtml::MouseDoubleClickEvent::test( event ) )
6094 {
6095 khtmlMouseDoubleClickEvent( static_cast<khtml::MouseDoubleClickEvent *>( event ) );
6096 return;
6097 }
6098
6099 if ( khtml::MouseMoveEvent::test( event ) )
6100 {
6101 khtmlMouseMoveEvent( static_cast<khtml::MouseMoveEvent *>( event ) );
6102 return;
6103 }
6104
6105 if ( khtml::MouseReleaseEvent::test( event ) )
6106 {
6107 khtmlMouseReleaseEvent( static_cast<khtml::MouseReleaseEvent *>( event ) );
6108 return;
6109 }
6110
6111 if ( khtml::DrawContentsEvent::test( event ) )
6112 {
6113 khtmlDrawContentsEvent( static_cast<khtml::DrawContentsEvent *>( event ) );
6114 return;
6115 }
6116
6117 KParts::ReadOnlyPart::customEvent( event );
6118}
6119
6120bool KHTMLPart::isPointInsideSelection(int x, int y)
6121{
6122 // Treat a collapsed selection like no selection.
6123 if (d->editor_context.m_selection.state() == Selection::CARET)
6124 return false;
6125 if (!xmlDocImpl()->renderer())
6126 return false;
6127
6128 khtml::RenderObject::NodeInfo nodeInfo(true, true);
6129 xmlDocImpl()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y);
6130 NodeImpl *innerNode = nodeInfo.innerNode();
6131 if (!innerNode || !innerNode->renderer())
6132 return false;
6133
6134 return innerNode->isPointInsideSelection(x, y, d->editor_context.m_selection);
6135}
6136
6137/** returns the position of the first inline text box of the line at
6138 * coordinate y in renderNode
6139 *
6140 * This is a helper function for line-by-line text selection.
6141 */
6142static bool firstRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
6143{
6144 for (khtml::RenderObject *n = renderNode; n; n = n->nextSibling()) {
6145 if (n->isText()) {
6146 khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
6147 for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
6148 if (box->m_y == y && textRenderer->element()) {
6149 startNode = textRenderer->element();
6150 startOffset = box->m_start;
6151 return true;
6152 }
6153 }
6154 }
6155
6156 if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
6157 return true;
6158 }
6159 }
6160
6161 return false;
6162}
6163
6164/** returns the position of the last inline text box of the line at
6165 * coordinate y in renderNode
6166 *
6167 * This is a helper function for line-by-line text selection.
6168 */
6169static bool lastRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
6170{
6171 khtml::RenderObject *n = renderNode;
6172 if (!n) {
6173 return false;
6174 }
6175 khtml::RenderObject *next;
6176 while ((next = n->nextSibling())) {
6177 n = next;
6178 }
6179
6180 while (1) {
6181 if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
6182 return true;
6183 }
6184
6185 if (n->isText()) {
6186 khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
6187 for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
6188 if (box->m_y == y && textRenderer->element()) {
6189 endNode = textRenderer->element();
6190 endOffset = box->m_start + box->m_len;
6191 return true;
6192 }
6193 }
6194 }
6195
6196 if (n == renderNode) {
6197 return false;
6198 }
6199
6200 n = n->previousSibling();
6201 }
6202}
6203
6204void KHTMLPart::handleMousePressEventDoubleClick(khtml::MouseDoubleClickEvent *event)
6205{
6206 QMouseEvent *mouse = event->qmouseEvent();
6207 DOM::Node innerNode = event->innerNode();
6208
6209 Selection selection;
6210
6211 if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() &&
6212 innerNode.handle()->renderer()->shouldSelect()) {
6213 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()).position());
6214 if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
6215 selection.moveTo(pos);
6216 selection.expandUsingGranularity(Selection::WORD);
6217 }
6218 }
6219
6220 if (selection.state() != Selection::CARET) {
6221 d->editor_context.beginSelectingText(Selection::WORD);
6222 }
6223
6224 setCaret(selection);
6225 startAutoScroll();
6226}
6227
6228void KHTMLPart::handleMousePressEventTripleClick(khtml::MouseDoubleClickEvent *event)
6229{
6230 QMouseEvent *mouse = event->qmouseEvent();
6231 DOM::Node innerNode = event->innerNode();
6232
6233 Selection selection;
6234
6235 if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() &&
6236 innerNode.handle()->renderer()->shouldSelect()) {
6237 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()).position());
6238 if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
6239 selection.moveTo(pos);
6240 selection.expandUsingGranularity(Selection::LINE);
6241 }
6242 }
6243
6244 if (selection.state() != Selection::CARET) {
6245 d->editor_context.beginSelectingText(Selection::LINE);
6246 }
6247
6248 setCaret(selection);
6249 startAutoScroll();
6250}
6251
6252void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event)
6253{
6254 QMouseEvent *mouse = event->qmouseEvent();
6255 DOM::Node innerNode = event->innerNode();
6256
6257 if (mouse->button() == Qt::LeftButton) {
6258 Selection sel;
6259
6260 if (!innerNode.isNull() && innerNode.handle()->renderer() &&
6261 innerNode.handle()->renderer()->shouldSelect()) {
6262 bool extendSelection = mouse->modifiers() & Qt::ShiftModifier;
6263
6264 // Don't restart the selection when the mouse is pressed on an
6265 // existing selection so we can allow for text dragging.
6266 if (!extendSelection && isPointInsideSelection(event->x(), event->y())) {
6267 return;
6268 }
6269 Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()).position());
6270 if (pos.isEmpty())
6271 pos = Position(innerNode.handle(), innerNode.handle()->caretMinOffset());
6272 kDebug(6050) << event->x() << event->y() << pos << endl;
6273
6274 sel = caret();
6275 if (extendSelection && sel.notEmpty()) {
6276 sel.clearModifyBias();
6277 sel.setExtent(pos);
6278 if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
6279 sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
6280 }
6281 d->editor_context.m_beganSelectingText = true;
6282 } else {
6283 sel = pos;
6284 d->editor_context.m_selectionGranularity = Selection::CHARACTER;
6285 }
6286 }
6287
6288 setCaret(sel);
6289 startAutoScroll();
6290 }
6291}
6292
6293void KHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent *event )
6294{
6295 DOM::DOMString url = event->url();
6296 QMouseEvent *_mouse = event->qmouseEvent();
6297 DOM::Node innerNode = event->innerNode();
6298 d->m_mousePressNode = innerNode;
6299
6300 d->m_dragStartPos = QPoint(event->x(), event->y());
6301
6302 if ( !event->url().isNull() ) {
6303 d->m_strSelectedURL = event->url().string();
6304 d->m_strSelectedURLTarget = event->target().string();
6305 }
6306 else {
6307 d->m_strSelectedURL.clear();
6308 d->m_strSelectedURLTarget.clear();
6309 }
6310
6311 if ( _mouse->button() == Qt::LeftButton ||
6312 _mouse->button() == Qt::MidButton )
6313 {
6314 d->m_bMousePressed = true;
6315
6316#ifdef KHTML_NO_SELECTION
6317 d->m_dragLastPos = _mouse->globalPos();
6318#else
6319 if ( _mouse->button() == Qt::LeftButton )
6320 {
6321 if ( (!d->m_strSelectedURL.isNull() && !isEditable())
6322 || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) )
6323 return;
6324
6325 d->editor_context.m_beganSelectingText = false;
6326
6327 handleMousePressEventSingleClick(event);
6328 }
6329#endif
6330 }
6331
6332 if ( _mouse->button() == Qt::RightButton )
6333 {
6334 popupMenu( d->m_strSelectedURL );
6335 // might be deleted, don't touch "this"
6336 }
6337}
6338
6339void KHTMLPart::khtmlMouseDoubleClickEvent( khtml::MouseDoubleClickEvent *event )
6340{
6341 QMouseEvent *_mouse = event->qmouseEvent();
6342 if ( _mouse->button() == Qt::LeftButton )
6343 {
6344 d->m_bMousePressed = true;
6345 d->editor_context.m_beganSelectingText = false;
6346
6347 if (event->clickCount() == 2) {
6348 handleMousePressEventDoubleClick(event);
6349 return;
6350 }
6351
6352 if (event->clickCount() >= 3) {
6353 handleMousePressEventTripleClick(event);
6354 return;
6355 }
6356 }
6357}
6358
6359#ifndef KHTML_NO_SELECTION
6360bool KHTMLPart::isExtendingSelection() const
6361 {
6362 // This is it, the whole detection. khtmlMousePressEvent only sets this
6363 // on LMB or MMB, but never on RMB. As text selection doesn't work for MMB,
6364 // it's sufficient to only rely on this flag to detect selection extension.
6365 return d->editor_context.m_beganSelectingText;
6366}
6367
6368void KHTMLPart::extendSelectionTo(int x, int y, const DOM::Node &innerNode)
6369{
6370 // handle making selection
6371 Position pos(innerNode.handle()->positionForCoordinates(x, y).position());
6372
6373 // Don't modify the selection if we're not on a node.
6374 if (pos.isEmpty())
6375 return;
6376
6377 // Restart the selection if this is the first mouse move. This work is usually
6378 // done in khtmlMousePressEvent, but not if the mouse press was on an existing selection.
6379 Selection sel = caret();
6380 sel.clearModifyBias();
6381 if (!d->editor_context.m_beganSelectingText) {
6382 // We are beginning a selection during press-drag, when the original click
6383 // wasn't appropriate for one. Make sure to set the granularity.
6384 d->editor_context.beginSelectingText(Selection::CHARACTER);
6385 sel.moveTo(pos);
6386 }
6387
6388 sel.setExtent(pos);
6389 if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
6390 sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
6391 }
6392 setCaret(sel);
6393
6394}
6395#endif // KHTML_NO_SELECTION
6396
6397bool KHTMLPart::handleMouseMoveEventDrag(khtml::MouseMoveEvent *event)
6398{
6399#ifdef QT_NO_DRAGANDDROP
6400 return false;
6401#else
6402 if (!dndEnabled())
6403 return false;
6404
6405 DOM::Node innerNode = event->innerNode();
6406
6407 if( (d->m_bMousePressed &&
6408 ( (!d->m_strSelectedURL.isEmpty() && !isEditable())
6409 || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) ) )
6410 && ( d->m_dragStartPos - QPoint(event->x(), event->y()) ).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
6411
6412 DOM::DOMString url = event->url();
6413
6414 QPixmap pix;
6415 HTMLImageElementImpl *img = 0L;
6416 KUrl u;
6417
6418 // qDebug("****************** Event URL: %s", url.string().toLatin1().constData());
6419 // qDebug("****************** Event Target: %s", target.string().toLatin1().constData());
6420
6421 // Normal image...
6422 if ( url.length() == 0 && innerNode.handle() && innerNode.handle()->id() == ID_IMG )
6423 {
6424 img = static_cast<HTMLImageElementImpl *>(innerNode.handle());
6425 u = KUrl( completeURL( khtml::parseURL(img->getAttribute(ATTR_SRC)).string() ) );
6426 pix = KIconLoader::global()->loadIcon("image-x-generic", KIconLoader::Desktop);
6427 }
6428 else
6429 {
6430 // Text or image link...
6431 u = completeURL( d->m_strSelectedURL );
6432 pix = KIO::pixmapForUrl(u, 0, KIconLoader::Desktop, KIconLoader::SizeMedium);
6433 }
6434
6435 u.setPass(QString());
6436
6437 QDrag *drag = new QDrag( d->m_view->viewport() );
6438 QMap<QString, QString> metaDataMap;
6439 if ( !d->m_referrer.isEmpty() )
6440 metaDataMap.insert( "referrer", d->m_referrer );
6441 QMimeData* mimeData = new QMimeData();
6442 u.populateMimeData( mimeData, metaDataMap );
6443 drag->setMimeData( mimeData );
6444
6445 if( img && img->complete() )
6446 drag->mimeData()->setImageData( img->currentImage() );
6447
6448 if ( !pix.isNull() )
6449 drag->setPixmap( pix );
6450
6451 stopAutoScroll();
6452 drag->start();
6453
6454 // when we finish our drag, we need to undo our mouse press
6455 d->m_bMousePressed = false;
6456 d->m_strSelectedURL.clear();
6457 d->m_strSelectedURLTarget.clear();
6458 return true;
6459 }
6460 return false;
6461#endif // QT_NO_DRAGANDDROP
6462}
6463
6464bool KHTMLPart::handleMouseMoveEventOver(khtml::MouseMoveEvent *event)
6465{
6466 // Mouse clicked -> do nothing
6467 if ( d->m_bMousePressed ) return false;
6468
6469 DOM::DOMString url = event->url();
6470
6471 // The mouse is over something
6472 if ( url.length() )
6473 {
6474 DOM::DOMString target = event->target();
6475 QMouseEvent *_mouse = event->qmouseEvent();
6476 DOM::Node innerNode = event->innerNode();
6477
6478 bool shiftPressed = ( _mouse->modifiers() & Qt::ShiftModifier );
6479
6480 // Image map
6481 if ( !innerNode.isNull() && innerNode.elementId() == ID_IMG )
6482 {
6483 HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
6484 if ( i && i->isServerMap() )
6485 {
6486 khtml::RenderObject *r = i->renderer();
6487 if(r)
6488 {
6489 int absx, absy;
6490 r->absolutePosition(absx, absy);
6491 int x(event->x() - absx), y(event->y() - absy);
6492
6493 d->m_overURL = url.string() + QString("?%1,%2").arg(x).arg(y);
6494 d->m_overURLTarget = target.string();
6495 overURL( d->m_overURL, target.string(), shiftPressed );
6496 return true;
6497 }
6498 }
6499 }
6500
6501 // normal link
6502 if ( d->m_overURL.isEmpty() || d->m_overURL != url || d->m_overURLTarget != target )
6503 {
6504 d->m_overURL = url.string();
6505 d->m_overURLTarget = target.string();
6506 overURL( d->m_overURL, target.string(), shiftPressed );
6507 }
6508 }
6509 else // Not over a link...
6510 {
6511 if( !d->m_overURL.isEmpty() ) // and we were over a link -> reset to "default statusbar text"
6512 {
6513 // reset to "default statusbar text"
6514 resetHoverText();
6515 }
6516 }
6517 return true;
6518}
6519
6520void KHTMLPart::handleMouseMoveEventSelection(khtml::MouseMoveEvent *event)
6521{
6522 // Mouse not pressed. Do nothing.
6523 if (!d->m_bMousePressed)
6524 return;
6525
6526#ifdef KHTML_NO_SELECTION
6527 if (d->m_doc && d->m_view) {
6528 QPoint diff( mouse->globalPos() - d->m_dragLastPos );
6529
6530 if (abs(diff.x()) > 64 || abs(diff.y()) > 64) {
6531 d->m_view->scrollBy(-diff.x(), -diff.y());
6532 d->m_dragLastPos = mouse->globalPos();
6533 }
6534 }
6535#else
6536
6537 QMouseEvent *mouse = event->qmouseEvent();
6538 DOM::Node innerNode = event->innerNode();
6539
6540 if ( (mouse->buttons() & Qt::LeftButton) == 0 || !innerNode.handle() || !innerNode.handle()->renderer() ||
6541 !innerNode.handle()->renderer()->shouldSelect())
6542 return;
6543
6544 // handle making selection
6545 extendSelectionTo(event->x(), event->y(), innerNode);
6546#endif // KHTML_NO_SELECTION
6547}
6548
6549void KHTMLPart::khtmlMouseMoveEvent( khtml::MouseMoveEvent *event )
6550{
6551 if (handleMouseMoveEventDrag(event))
6552 return;
6553
6554 if (handleMouseMoveEventOver(event))
6555 return;
6556
6557 handleMouseMoveEventSelection(event);
6558}
6559
6560void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
6561{
6562 DOM::Node innerNode = event->innerNode();
6563 d->m_mousePressNode = DOM::Node();
6564
6565 if ( d->m_bMousePressed ) {
6566 setStatusBarText(QString(), BarHoverText);
6567 stopAutoScroll();
6568 }
6569
6570 // Used to prevent mouseMoveEvent from initiating a drag before
6571 // the mouse is pressed again.
6572 d->m_bMousePressed = false;
6573
6574#ifndef QT_NO_CLIPBOARD
6575 QMouseEvent *_mouse = event->qmouseEvent();
6576 if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == Qt::MidButton) && (event->url().isNull())) {
6577 kDebug( 6050 ) << "MMB shouldOpen=" << d->m_bOpenMiddleClick;
6578
6579 if (d->m_bOpenMiddleClick) {
6580 KHTMLPart *p = this;
6581 while (p->parentPart()) p = p->parentPart();
6582 p->d->m_extension->pasteRequest();
6583 }
6584 }
6585#endif
6586
6587#ifndef KHTML_NO_SELECTION
6588 {
6589
6590 // Clear the selection if the mouse didn't move after the last mouse press.
6591 // We do this so when clicking on the selection, the selection goes away.
6592 // However, if we are editing, place the caret.
6593 if (!d->editor_context.m_beganSelectingText
6594 && d->m_dragStartPos.x() == event->x()
6595 && d->m_dragStartPos.y() == event->y()
6596 && d->editor_context.m_selection.state() == Selection::RANGE) {
6597 Selection selection;
6598#ifdef APPLE_CHANGES
6599 if (d->editor_context.m_selection.base().node()->isContentEditable())
6600#endif
6601 selection.moveTo(d->editor_context.m_selection.base().node()->positionForCoordinates(event->x(), event->y()).position());
6602 setCaret(selection);
6603 }
6604 // get selected text and paste to the clipboard
6605#ifndef QT_NO_CLIPBOARD
6606 QString text = selectedText();
6607 text.replace(QChar(0xa0), ' ');
6608 if (!text.isEmpty()) {
6609 disconnect( qApp->clipboard(), SIGNAL(selectionChanged()), this, SLOT(slotClearSelection()));
6610 qApp->clipboard()->setText(text,QClipboard::Selection);
6611 connect( qApp->clipboard(), SIGNAL(selectionChanged()), SLOT(slotClearSelection()));
6612 }
6613#endif
6614 //kDebug( 6000 ) << "selectedText = " << text;
6615 emitSelectionChanged();
6616//kDebug(6000) << "rel2: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << "), caretOfs " << d->caretOffset();
6617 }
6618#endif
6619}
6620
6621void KHTMLPart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * )
6622{
6623}
6624
6625void KHTMLPart::guiActivateEvent( KParts::GUIActivateEvent *event )
6626{
6627 if ( event->activated() )
6628 {
6629 emitSelectionChanged();
6630 emit d->m_extension->enableAction( "print", d->m_doc != 0 );
6631
6632 if ( !d->m_settings->autoLoadImages() && d->m_paLoadImages )
6633 {
6634 QList<QAction*> lst;
6635 lst.append( d->m_paLoadImages );
6636 plugActionList( "loadImages", lst );
6637 }
6638 }
6639}
6640
6641void KHTMLPart::slotPrintFrame()
6642{
6643 if ( d->m_frames.count() == 0 )
6644 return;
6645
6646 KParts::ReadOnlyPart *frame = currentFrame();
6647 if (!frame)
6648 return;
6649
6650 KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject( frame );
6651
6652 if ( !ext )
6653 return;
6654
6655
6656 const QMetaObject *mo = ext->metaObject();
6657
6658
6659 if (mo->indexOfSlot( "print()") != -1)
6660 QMetaObject::invokeMethod(ext, "print()", Qt::DirectConnection);
6661}
6662
6663void KHTMLPart::slotSelectAll()
6664{
6665 KParts::ReadOnlyPart *part = currentFrame();
6666 if (part && part->inherits("KHTMLPart"))
6667 static_cast<KHTMLPart *>(part)->selectAll();
6668}
6669
6670void KHTMLPart::startAutoScroll()
6671{
6672 connect(&d->m_scrollTimer, SIGNAL(timeout()), this, SLOT(slotAutoScroll()));
6673 d->m_scrollTimer.setSingleShot(false);
6674 d->m_scrollTimer.start(100);
6675}
6676
6677void KHTMLPart::stopAutoScroll()
6678{
6679 disconnect(&d->m_scrollTimer, SIGNAL(timeout()), this, SLOT(slotAutoScroll()));
6680 if (d->m_scrollTimer.isActive())
6681 d->m_scrollTimer.stop();
6682}
6683
6684
6685void KHTMLPart::slotAutoScroll()
6686{
6687 if (d->m_view)
6688 d->m_view->doAutoScroll();
6689 else
6690 stopAutoScroll(); // Safety
6691}
6692
6693void KHTMLPart::runAdFilter()
6694{
6695 if ( parentPart() )
6696 parentPart()->runAdFilter();
6697
6698 if ( !d->m_doc )
6699 return;
6700
6701 QSetIterator<khtml::CachedObject*> it( d->m_doc->docLoader()->m_docObjects );
6702 while (it.hasNext())
6703 {
6704 khtml::CachedObject* obj = it.next();
6705 if ( obj->type() == khtml::CachedObject::Image ) {
6706 khtml::CachedImage *image = static_cast<khtml::CachedImage *>(obj);
6707 bool wasBlocked = image->m_wasBlocked;
6708 image->m_wasBlocked = KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( image->url().string() ) );
6709 if ( image->m_wasBlocked != wasBlocked )
6710 image->do_notify(QRect(QPoint(0,0), image->pixmap_size()));
6711 }
6712 }
6713
6714 if ( KHTMLGlobal::defaultHTMLSettings()->isHideAdsEnabled() ) {
6715 for ( NodeImpl *nextNode, *node = d->m_doc; node; node = nextNode ) {
6716
6717 // We might be deleting 'node' shortly.
6718 nextNode = node->traverseNextNode();
6719
6720 if ( node->id() == ID_IMG ||
6721 node->id() == ID_IFRAME ||
6722 (node->id() == ID_INPUT && static_cast<HTMLInputElementImpl *>(node)->inputType() == HTMLInputElementImpl::IMAGE ))
6723 {
6724 if ( KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( static_cast<ElementImpl *>(node)->getAttribute(ATTR_SRC).string() ) ) )
6725 {
6726 // Since any kids of node will be deleted, too, fastforward nextNode
6727 // until we get outside of node.
6728 while (nextNode && nextNode->isAncestor(node))
6729 nextNode = nextNode->traverseNextNode();
6730
6731 node->ref();
6732 NodeImpl *parent = node->parent();
6733 if( parent )
6734 {
6735 int exception = 0;
6736 parent->removeChild(node, exception);
6737 }
6738 node->deref();
6739 }
6740 }
6741 }
6742 }
6743}
6744
6745void KHTMLPart::selectAll()
6746{
6747 if (!d->m_doc) return;
6748
6749 NodeImpl *first;
6750 if (d->m_doc->isHTMLDocument())
6751 first = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
6752 else
6753 first = d->m_doc;
6754 NodeImpl *next;
6755
6756 // Look for first text/cdata node that has a renderer,
6757 // or first childless replaced element
6758 while ( first && !(first->renderer()
6759 && ((first->nodeType() == Node::TEXT_NODE || first->nodeType() == Node::CDATA_SECTION_NODE)
6760 || (first->renderer()->isReplaced() && !first->renderer()->firstChild()))))
6761 {
6762 next = first->firstChild();
6763 if ( !next ) next = first->nextSibling();
6764 while( first && !next )
6765 {
6766 first = first->parentNode();
6767 if ( first )
6768 next = first->nextSibling();
6769 }
6770 first = next;
6771 }
6772
6773 NodeImpl *last;
6774 if (d->m_doc->isHTMLDocument())
6775 last = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
6776 else
6777 last = d->m_doc;
6778 // Look for last text/cdata node that has a renderer,
6779 // or last childless replaced element
6780 // ### Instead of changing this loop, use findLastSelectableNode
6781 // in render_table.cpp (LS)
6782 while ( last && !(last->renderer()
6783 && ((last->nodeType() == Node::TEXT_NODE || last->nodeType() == Node::CDATA_SECTION_NODE)
6784 || (last->renderer()->isReplaced() && !last->renderer()->lastChild()))))
6785 {
6786 next = last->lastChild();
6787 if ( !next ) next = last->previousSibling();
6788 while ( last && !next )
6789 {
6790 last = last->parentNode();
6791 if ( last )
6792 next = last->previousSibling();
6793 }
6794 last = next;
6795 }
6796
6797 if ( !first || !last )
6798 return;
6799 Q_ASSERT(first->renderer());
6800 Q_ASSERT(last->renderer());
6801 d->editor_context.m_selection.moveTo(Position(first, 0), Position(last, last->nodeValue().length()));
6802 d->m_doc->updateSelection();
6803
6804 emitSelectionChanged();
6805}
6806
6807bool KHTMLPart::checkLinkSecurity(const KUrl &linkURL,const KLocalizedString &message, const QString &button)
6808{
6809 bool linkAllowed = true;
6810
6811 if ( d->m_doc )
6812 linkAllowed = KAuthorized::authorizeUrlAction("redirect", url(), linkURL);
6813
6814 if ( !linkAllowed ) {
6815 khtml::Tokenizer *tokenizer = d->m_doc->tokenizer();
6816 if (tokenizer)
6817 tokenizer->setOnHold(true);
6818
6819 int response = KMessageBox::Cancel;
6820 if (!message.isEmpty())
6821 {
6822 // Dangerous flag makes the Cancel button the default
6823 response = KMessageBox::warningContinueCancel( 0,
6824 message.subs(Qt::escape(linkURL.prettyUrl())).toString(),
6825 i18n( "Security Warning" ),
6826 KGuiItem(button),
6827 KStandardGuiItem::cancel(),
6828 QString(), // no don't ask again info
6829 KMessageBox::Notify | KMessageBox::Dangerous );
6830 }
6831 else
6832 {
6833 KMessageBox::error( 0,
6834 i18n( "<qt>Access by untrusted page to<br /><b>%1</b><br /> denied.</qt>", Qt::escape(linkURL.prettyUrl())),
6835 i18n( "Security Alert" ));
6836 }
6837
6838 if (tokenizer)
6839 tokenizer->setOnHold(false);
6840 return (response==KMessageBox::Continue);
6841 }
6842 return true;
6843}
6844
6845void KHTMLPart::slotPartRemoved( KParts::Part *part )
6846{
6847// kDebug(6050) << part;
6848 if ( part == d->m_activeFrame )
6849 {
6850 d->m_activeFrame = 0L;
6851 if ( !part->inherits( "KHTMLPart" ) )
6852 {
6853 if (factory()) {
6854 factory()->removeClient( part );
6855 }
6856 if (childClients().contains(part)) {
6857 removeChildClient( part );
6858 }
6859 }
6860 }
6861}
6862
6863void KHTMLPart::slotActiveFrameChanged( KParts::Part *part )
6864{
6865// kDebug(6050) << this << "part=" << part;
6866 if ( part == this )
6867 {
6868 kError(6050) << "strange error! we activated ourselves";
6869 assert( false );
6870 return;
6871 }
6872// kDebug(6050) << "d->m_activeFrame=" << d->m_activeFrame;
6873 if ( d->m_activeFrame && d->m_activeFrame->widget() && d->m_activeFrame->widget()->inherits( "QFrame" ) )
6874 {
6875 QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
6876 if (frame->frameStyle() != QFrame::NoFrame)
6877 {
6878 frame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken);
6879 frame->repaint();
6880 }
6881 }
6882
6883 if( d->m_activeFrame && !d->m_activeFrame->inherits( "KHTMLPart" ) )
6884 {
6885 if (factory()) {
6886 factory()->removeClient( d->m_activeFrame );
6887 }
6888 removeChildClient( d->m_activeFrame );
6889 }
6890 if( part && !part->inherits( "KHTMLPart" ) )
6891 {
6892 if (factory()) {
6893 factory()->addClient( part );
6894 }
6895 insertChildClient( part );
6896 }
6897
6898
6899 d->m_activeFrame = part;
6900
6901 if ( d->m_activeFrame && d->m_activeFrame->widget()->inherits( "QFrame" ) )
6902 {
6903 QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
6904 if (frame->frameStyle() != QFrame::NoFrame)
6905 {
6906 frame->setFrameStyle( QFrame::StyledPanel | QFrame::Plain);
6907 frame->repaint();
6908 }
6909 kDebug(6050) << "new active frame " << d->m_activeFrame;
6910 }
6911
6912 updateActions();
6913
6914 // (note: childObject returns 0 if the argument is 0)
6915 d->m_extension->setExtensionProxy( KParts::BrowserExtension::childObject( d->m_activeFrame ) );
6916}
6917
6918void KHTMLPart::setActiveNode(const DOM::Node &node)
6919{
6920 if (!d->m_doc || !d->m_view)
6921 return;
6922
6923 // Set the document's active node
6924 d->m_doc->setFocusNode(node.handle());
6925
6926 // Scroll the view if necessary to ensure that the new focus node is visible
6927 QRect rect = node.handle()->getRect();
6928 d->m_view->ensureVisible(rect.right(), rect.bottom());
6929 d->m_view->ensureVisible(rect.left(), rect.top());
6930}
6931
6932DOM::Node KHTMLPart::activeNode() const
6933{
6934 return DOM::Node(d->m_doc?d->m_doc->focusNode():0);
6935}
6936
6937DOM::EventListener *KHTMLPart::createHTMLEventListener( QString code, QString name, NodeImpl* node, bool svg )
6938{
6939 KJSProxy *proxy = jScript();
6940
6941 if (!proxy)
6942 return 0;
6943
6944 return proxy->createHTMLEventHandler( url().url(), name, code, node, svg );
6945}
6946
6947KHTMLPart *KHTMLPart::opener()
6948{
6949 return d->m_opener;
6950}
6951
6952void KHTMLPart::setOpener(KHTMLPart *_opener)
6953{
6954 d->m_opener = _opener;
6955}
6956
6957bool KHTMLPart::openedByJS()
6958{
6959 return d->m_openedByJS;
6960}
6961
6962void KHTMLPart::setOpenedByJS(bool _openedByJS)
6963{
6964 d->m_openedByJS = _openedByJS;
6965}
6966
6967void KHTMLPart::preloadStyleSheet(const QString &url, const QString &stylesheet)
6968{
6969 khtml::Cache::preloadStyleSheet(url, stylesheet);
6970}
6971
6972void KHTMLPart::preloadScript(const QString &url, const QString &script)
6973{
6974 khtml::Cache::preloadScript(url, script);
6975}
6976
6977long KHTMLPart::cacheId() const
6978{
6979 return d->m_cacheId;
6980}
6981
6982bool KHTMLPart::restored() const
6983{
6984 return d->m_restored;
6985}
6986
6987bool KHTMLPart::pluginPageQuestionAsked(const QString& mimetype) const
6988{
6989 // parentPart() should be const!
6990 KHTMLPart* parent = const_cast<KHTMLPart *>(this)->parentPart();
6991 if ( parent )
6992 return parent->pluginPageQuestionAsked(mimetype);
6993
6994 return d->m_pluginPageQuestionAsked.contains(mimetype);
6995}
6996
6997void KHTMLPart::setPluginPageQuestionAsked(const QString& mimetype)
6998{
6999 if ( parentPart() )
7000 parentPart()->setPluginPageQuestionAsked(mimetype);
7001
7002 d->m_pluginPageQuestionAsked.append(mimetype);
7003}
7004
7005KEncodingDetector *KHTMLPart::createDecoder()
7006{
7007 KEncodingDetector *dec = new KEncodingDetector();
7008 if( !d->m_encoding.isNull() )
7009 dec->setEncoding( d->m_encoding.toLatin1().constData(),
7010 d->m_haveEncoding ? KEncodingDetector::UserChosenEncoding : KEncodingDetector::EncodingFromHTTPHeader);
7011 else {
7012 // Inherit the default encoding from the parent frame if there is one.
7013 QByteArray defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
7014 ? QByteArray( parentPart()->d->m_decoder->encoding() ) : settings()->encoding().toLatin1();
7015 dec->setEncoding(defaultEncoding.constData(), KEncodingDetector::DefaultEncoding);
7016 }
7017
7018 if (d->m_doc)
7019 d->m_doc->setDecoder(dec);
7020 dec->setAutoDetectLanguage( d->m_autoDetectLanguage );
7021 return dec;
7022}
7023
7024void KHTMLPart::emitCaretPositionChanged(const DOM::Position &pos) {
7025 // pos must not be already converted to range-compliant coordinates
7026 Position rng_pos = pos.equivalentRangeCompliantPosition();
7027 Node node = rng_pos.node();
7028 emit caretPositionChanged(node, rng_pos.offset());
7029}
7030
7031void KHTMLPart::restoreScrollPosition()
7032{
7033 const KParts::OpenUrlArguments args( arguments() );
7034
7035 if ( url().hasRef() && !d->m_restoreScrollPosition && !args.reload()) {
7036 if ( !d->m_doc || !d->m_doc->parsing() )
7037 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
7038 if ( !gotoAnchor(url().encodedHtmlRef()) )
7039 gotoAnchor(url().htmlRef());
7040 return;
7041 }
7042
7043 // Check whether the viewport has become large enough to encompass the stored
7044 // offsets. If the document has been fully loaded, force the new coordinates,
7045 // even if the canvas is too short (can happen when user resizes the window
7046 // during loading).
7047 if (d->m_view->contentsHeight() - d->m_view->visibleHeight() >= args.yOffset()
7048 || d->m_bComplete) {
7049 d->m_view->setContentsPos(args.xOffset(), args.yOffset());
7050 disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
7051 }
7052}
7053
7054
7055void KHTMLPart::openWallet(DOM::HTMLFormElementImpl *form)
7056{
7057#ifndef KHTML_NO_WALLET
7058 KHTMLPart *p;
7059
7060 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
7061 }
7062
7063 if (p) {
7064 p->openWallet(form);
7065 return;
7066 }
7067
7068 if (onlyLocalReferences()) { // avoid triggering on local apps, thumbnails
7069 return;
7070 }
7071
7072 if (d->m_wallet) {
7073 if (d->m_bWalletOpened) {
7074 if (d->m_wallet->isOpen()) {
7075 form->walletOpened(d->m_wallet);
7076 return;
7077 }
7078 d->m_wallet->deleteLater();
7079 d->m_wallet = 0L;
7080 d->m_bWalletOpened = false;
7081 }
7082 }
7083
7084 if (!d->m_wq) {
7085 KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
7086 d->m_wq = new KHTMLWalletQueue(this);
7087 d->m_wq->wallet = wallet;
7088 connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
7089 connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
7090 }
7091 assert(form);
7092 d->m_wq->callers.append(KHTMLWalletQueue::Caller(form, form->document()));
7093#endif // KHTML_NO_WALLET
7094}
7095
7096
7097void KHTMLPart::saveToWallet(const QString& key, const QMap<QString,QString>& data)
7098{
7099#ifndef KHTML_NO_WALLET
7100 KHTMLPart *p;
7101
7102 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
7103 }
7104
7105 if (p) {
7106 p->saveToWallet(key, data);
7107 return;
7108 }
7109
7110 if (d->m_wallet) {
7111 if (d->m_bWalletOpened) {
7112 if (d->m_wallet->isOpen()) {
7113 if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder())) {
7114 d->m_wallet->createFolder(KWallet::Wallet::FormDataFolder());
7115 }
7116 d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder());
7117 d->m_wallet->writeMap(key, data);
7118 return;
7119 }
7120 d->m_wallet->deleteLater();
7121 d->m_wallet = 0L;
7122 d->m_bWalletOpened = false;
7123 }
7124 }
7125
7126 if (!d->m_wq) {
7127 KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
7128 d->m_wq = new KHTMLWalletQueue(this);
7129 d->m_wq->wallet = wallet;
7130 connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
7131 connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
7132 }
7133 d->m_wq->savers.append(qMakePair(key, data));
7134#endif // KHTML_NO_WALLET
7135}
7136
7137
7138void KHTMLPart::dequeueWallet(DOM::HTMLFormElementImpl *form) {
7139#ifndef KHTML_NO_WALLET
7140 KHTMLPart *p;
7141
7142 for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
7143 }
7144
7145 if (p) {
7146 p->dequeueWallet(form);
7147 return;
7148 }
7149
7150 if (d->m_wq) {
7151 d->m_wq->callers.removeAll(KHTMLWalletQueue::Caller(form, form->document()));
7152 }
7153#endif // KHTML_NO_WALLET
7154}
7155
7156
7157void KHTMLPart::walletOpened(KWallet::Wallet *wallet) {
7158#ifndef KHTML_NO_WALLET
7159 assert(!d->m_wallet);
7160 assert(d->m_wq);
7161
7162 d->m_wq->deleteLater(); // safe?
7163 d->m_wq = 0L;
7164
7165 if (!wallet) {
7166 d->m_bWalletOpened = false;
7167 return;
7168 }
7169
7170 d->m_wallet = wallet;
7171 d->m_bWalletOpened = true;
7172 connect(d->m_wallet, SIGNAL(walletClosed()), SLOT(slotWalletClosed()));
7173 d->m_walletForms.clear();
7174 if (!d->m_statusBarWalletLabel) {
7175 d->m_statusBarWalletLabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
7176 d->m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum));
7177 d->m_statusBarWalletLabel->setUseCursor(false);
7178 d->m_statusBarExtension->addStatusBarItem(d->m_statusBarWalletLabel, 0, false);
7179 d->m_statusBarWalletLabel->setPixmap(SmallIcon("wallet-open"));
7180 connect(d->m_statusBarWalletLabel, SIGNAL(leftClickedUrl()), SLOT(launchWalletManager()));
7181 connect(d->m_statusBarWalletLabel, SIGNAL(rightClickedUrl()), SLOT(walletMenu()));
7182 }
7183 d->m_statusBarWalletLabel->setToolTip(i18n("The wallet '%1' is open and being used for form data and passwords.", KWallet::Wallet::NetworkWallet()));
7184#endif // KHTML_NO_WALLET
7185}
7186
7187
7188KWallet::Wallet *KHTMLPart::wallet()
7189{
7190#ifndef KHTML_NO_WALLET
7191 KHTMLPart *p;
7192
7193 for (p = parentPart(); p && p->parentPart(); p = p->parentPart())
7194 ;
7195
7196 if (p)
7197 return p->wallet();
7198
7199 return d->m_wallet;
7200#else
7201 return 0;
7202#endif // !KHTML_NO_WALLET
7203}
7204
7205
7206void KHTMLPart::slotWalletClosed()
7207{
7208#ifndef KHTML_NO_WALLET
7209 if (d->m_wallet) {
7210 d->m_wallet->deleteLater();
7211 d->m_wallet = 0L;
7212 }
7213 d->m_bWalletOpened = false;
7214 if (d->m_statusBarWalletLabel) {
7215 d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarWalletLabel);
7216 delete d->m_statusBarWalletLabel;
7217 d->m_statusBarWalletLabel = 0L;
7218 }
7219#endif // KHTML_NO_WALLET
7220}
7221
7222void KHTMLPart::launchWalletManager()
7223{
7224#ifndef KHTML_NO_WALLET
7225 QDBusInterface r("org.kde.kwalletmanager", "/kwalletmanager/MainWindow_1",
7226 "org.kde.KMainWindow");
7227 if (!r.isValid()) {
7228 KToolInvocation::startServiceByDesktopName("kwalletmanager_show");
7229 } else {
7230 r.call(QDBus::NoBlock, "show");
7231 r.call(QDBus::NoBlock, "raise");
7232 }
7233#endif // KHTML_NO_WALLET
7234}
7235
7236void KHTMLPart::walletMenu()
7237{
7238#ifndef KHTML_NO_WALLET
7239 KMenu *menu = new KMenu(0L);
7240 QActionGroup *menuActionGroup = new QActionGroup(menu);
7241 connect( menuActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(removeStoredPasswordForm(QAction*)) );
7242
7243 menu->addAction(i18n("&Close Wallet"), this, SLOT(slotWalletClosed()));
7244
7245 if (d->m_view && d->m_view->nonPasswordStorableSite(toplevelURL().host())) {
7246 menu->addAction(i18n("&Allow storing passwords for this site"), this, SLOT(delNonPasswordStorableSite()));
7247 }
7248
7249 // List currently removable form passwords
7250 for ( QStringList::ConstIterator it = d->m_walletForms.constBegin(); it != d->m_walletForms.constEnd(); ++it ) {
7251 QAction* action = menu->addAction( i18n("Remove password for form %1", *it) );
7252 action->setActionGroup(menuActionGroup);
7253 QVariant var(*it);
7254 action->setData(var);
7255 }
7256
7257 KAcceleratorManager::manage(menu);
7258 menu->popup(QCursor::pos());
7259#endif // KHTML_NO_WALLET
7260}
7261
7262void KHTMLPart::removeStoredPasswordForm(QAction* action)
7263{
7264#ifndef KHTML_NO_WALLET
7265 assert(action);
7266 assert(d->m_wallet);
7267 QVariant var(action->data());
7268
7269 if(var.isNull() || !var.isValid() || var.type() != QVariant::String)
7270 return;
7271
7272 QString key = var.toString();
7273 if (KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(),
7274 KWallet::Wallet::FormDataFolder(),
7275 key))
7276 return; // failed
7277
7278
7279 if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder()))
7280 return; // failed
7281
7282 d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder());
7283 if (d->m_wallet->removeEntry(key))
7284 return; // failed
7285
7286 d->m_walletForms.removeAll(key);
7287#endif // KHTML_NO_WALLET
7288}
7289
7290void KHTMLPart::addWalletFormKey(const QString& walletFormKey)
7291{
7292#ifndef KHTML_NO_WALLET
7293
7294 if (parentPart()) {
7295 parentPart()->addWalletFormKey(walletFormKey);
7296 return;
7297 }
7298
7299 if(!d->m_walletForms.contains(walletFormKey))
7300 d->m_walletForms.append(walletFormKey);
7301#endif // KHTML_NO_WALLET
7302}
7303
7304void KHTMLPart::delNonPasswordStorableSite()
7305{
7306#ifndef KHTML_NO_WALLET
7307 if (d->m_view)
7308 d->m_view->delNonPasswordStorableSite(toplevelURL().host());
7309#endif // KHTML_NO_WALLET
7310}
7311void KHTMLPart::saveLoginInformation(const QString& host, const QString& key, const QMap<QString, QString>& walletMap)
7312{
7313#ifndef KHTML_NO_WALLET
7314 d->m_storePass.saveLoginInformation(host, key, walletMap);
7315#endif // KHTML_NO_WALLET
7316}
7317
7318void KHTMLPart::slotToggleCaretMode()
7319{
7320 setCaretMode(d->m_paToggleCaretMode->isChecked());
7321}
7322
7323void KHTMLPart::setFormNotification(KHTMLPart::FormNotification fn) {
7324 d->m_formNotification = fn;
7325}
7326
7327KHTMLPart::FormNotification KHTMLPart::formNotification() const {
7328 return d->m_formNotification;
7329}
7330
7331KUrl KHTMLPart::toplevelURL()
7332{
7333 KHTMLPart* part = this;
7334 while (part->parentPart())
7335 part = part->parentPart();
7336
7337 if (!part)
7338 return KUrl();
7339
7340 return part->url();
7341}
7342
7343bool KHTMLPart::isModified() const
7344{
7345 if ( !d->m_doc )
7346 return false;
7347
7348 return d->m_doc->unsubmittedFormChanges();
7349}
7350
7351void KHTMLPart::setDebugScript( bool enable )
7352{
7353 unplugActionList( "debugScriptList" );
7354 if ( enable ) {
7355 if (!d->m_paDebugScript) {
7356 d->m_paDebugScript = new KAction( i18n( "JavaScript &Debugger" ), this );
7357 actionCollection()->addAction( "debugScript", d->m_paDebugScript );
7358 connect( d->m_paDebugScript, SIGNAL(triggered(bool)), this, SLOT(slotDebugScript()) );
7359 }
7360 d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
7361 QList<QAction*> lst;
7362 lst.append( d->m_paDebugScript );
7363 plugActionList( "debugScriptList", lst );
7364 }
7365 d->m_bJScriptDebugEnabled = enable;
7366}
7367
7368void KHTMLPart::setSuppressedPopupIndicator( bool enable, KHTMLPart *originPart )
7369{
7370 if ( parentPart() ) {
7371 parentPart()->setSuppressedPopupIndicator( enable, originPart );
7372 return;
7373 }
7374
7375 if ( enable && originPart ) {
7376 d->m_openableSuppressedPopups++;
7377 if ( d->m_suppressedPopupOriginParts.indexOf( originPart ) == -1 )
7378 d->m_suppressedPopupOriginParts.append( originPart );
7379 }
7380
7381 if ( enable && !d->m_statusBarPopupLabel ) {
7382 d->m_statusBarPopupLabel = new KUrlLabel( d->m_statusBarExtension->statusBar() );
7383 d->m_statusBarPopupLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ));
7384 d->m_statusBarPopupLabel->setUseCursor( false );
7385 d->m_statusBarExtension->addStatusBarItem( d->m_statusBarPopupLabel, 0, false );
7386 d->m_statusBarPopupLabel->setPixmap( SmallIcon( "window-suppressed") );
7387
7388 d->m_statusBarPopupLabel->setToolTip(i18n("This page was prevented from opening a new window via JavaScript." ) );
7389
7390 connect(d->m_statusBarPopupLabel, SIGNAL(leftClickedUrl()), SLOT(suppressedPopupMenu()));
7391 if (d->m_settings->jsPopupBlockerPassivePopup()) {
7392 QPixmap px;
7393 px = MainBarIcon( "window-suppressed" );
7394 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);
7395 }
7396 } else if ( !enable && d->m_statusBarPopupLabel ) {
7397 d->m_statusBarPopupLabel->setToolTip("" );
7398 d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarPopupLabel );
7399 delete d->m_statusBarPopupLabel;
7400 d->m_statusBarPopupLabel = 0L;
7401 }
7402}
7403
7404void KHTMLPart::suppressedPopupMenu() {
7405 KMenu *m = new KMenu(0L);
7406 if ( d->m_openableSuppressedPopups )
7407 m->addAction(i18np("&Show Blocked Popup Window","&Show %1 Blocked Popup Windows", d->m_openableSuppressedPopups), this, SLOT(showSuppressedPopups()));
7408 QAction *a = m->addAction(i18n("Show Blocked Window Passive Popup &Notification"), this, SLOT(togglePopupPassivePopup()));
7409 a->setChecked(d->m_settings->jsPopupBlockerPassivePopup());
7410 m->addAction(i18n("&Configure JavaScript New Window Policies..."), this, SLOT(launchJSConfigDialog()));
7411 m->popup(QCursor::pos());
7412}
7413
7414void KHTMLPart::togglePopupPassivePopup() {
7415 // Same hack as in disableJSErrorExtension()
7416 d->m_settings->setJSPopupBlockerPassivePopup( !d->m_settings->jsPopupBlockerPassivePopup() );
7417 emit configurationChanged();
7418}
7419
7420void KHTMLPart::showSuppressedPopups() {
7421 foreach ( KHTMLPart* part, d->m_suppressedPopupOriginParts ) {
7422 if (part) {
7423 KJS::Window *w = KJS::Window::retrieveWindow( part );
7424 if (w) {
7425 w->showSuppressedWindows();
7426 w->forgetSuppressedWindows();
7427 }
7428 }
7429 }
7430 setSuppressedPopupIndicator( false );
7431 d->m_openableSuppressedPopups = 0;
7432 d->m_suppressedPopupOriginParts.clear();
7433}
7434
7435// Extension to use for "view document source", "save as" etc.
7436// Using the right extension can help the viewer get into the right mode (#40496)
7437QString KHTMLPart::defaultExtension() const
7438{
7439 if ( !d->m_doc )
7440 return ".html";
7441 if ( !d->m_doc->isHTMLDocument() )
7442 return ".xml";
7443 return d->m_doc->htmlMode() == DOM::DocumentImpl::XHtml ? ".xhtml" : ".html";
7444}
7445
7446bool KHTMLPart::inProgress() const
7447{
7448 if (!d->m_bComplete || d->m_runningScripts || (d->m_doc && d->m_doc->parsing()))
7449 return true;
7450
7451 // Any frame that hasn't completed yet ?
7452 ConstFrameIt it = d->m_frames.constBegin();
7453 const ConstFrameIt end = d->m_frames.constEnd();
7454 for (; it != end; ++it ) {
7455 if ((*it)->m_run || !(*it)->m_bCompleted)
7456 return true;
7457 }
7458
7459 return d->m_submitForm || !d->m_redirectURL.isEmpty() || d->m_redirectionTimer.isActive() || d->m_job;
7460}
7461
7462using namespace KParts;
7463#include "khtml_part.moc"
7464#include "khtmlpart_p.moc"
7465#ifndef KHTML_NO_WALLET
7466#include "khtml_wallet_p.moc"
7467#endif
7468
7469// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;
7470