• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.4 API Reference
  • KDE Home
  • Contact Us
 

KHTML

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

KDE's Doxygen guidelines are available online.

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.8.4 API Reference

Skip menu "kdelibs-4.8.4 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal