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

Skip menu "kdelibs-4.10.1 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