• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.5 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().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  d->m_referrer = url.protocol().startsWith("http") ? url.url() : "";
2036 
2037  setUrl(url);
2038 
2039  // Note: by now, any special mimetype besides plaintext would have been
2040  // handled specially inside openURL, so we handle their cases the same
2041  // as HTML.
2042  MimeType type = d->classifyMimeType(args.mimeType());
2043  switch (type) {
2044  case MimeSVG:
2045  d->m_doc = DOMImplementationImpl::createSVGDocument( d->m_view );
2046  break;
2047  case MimeXML: // any XML derivative, except XHTML or SVG
2048  // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl
2049  d->m_doc = DOMImplementationImpl::createXMLDocument( d->m_view );
2050  break;
2051  case MimeText:
2052  d->m_doc = new HTMLTextDocumentImpl( d->m_view );
2053  break;
2054  case MimeXHTML:
2055  case MimeHTML:
2056  default:
2057  d->m_doc = DOMImplementationImpl::createHTMLDocument( d->m_view );
2058  // HTML or XHTML? (#86446)
2059  static_cast<HTMLDocumentImpl *>(d->m_doc)->setHTMLRequested( type != MimeXHTML );
2060  }
2061 
2062  d->m_doc->ref();
2063  d->m_doc->setURL( url.url() );
2064  d->m_doc->open( );
2065  if (!d->m_doc->attached())
2066  d->m_doc->attach( );
2067  d->m_doc->setBaseURL( KUrl() );
2068  d->m_doc->docLoader()->setShowAnimations( KHTMLGlobal::defaultHTMLSettings()->showAnimations() );
2069  emit docCreated();
2070 
2071  d->m_paUseStylesheet->setItems(QStringList());
2072  d->m_paUseStylesheet->setEnabled( false );
2073 
2074  setAutoloadImages( KHTMLGlobal::defaultHTMLSettings()->autoLoadImages() );
2075  QString userStyleSheet = KHTMLGlobal::defaultHTMLSettings()->userStyleSheet();
2076  if ( !userStyleSheet.isEmpty() )
2077  setUserStyleSheet( KUrl( userStyleSheet ) );
2078 
2079  d->m_doc->setRestoreState(d->m_extension->browserArguments().docState);
2080  connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2081 
2082  emit d->m_extension->enableAction( "print", true );
2083 
2084  d->m_doc->setParsing(true);
2085 }
2086 
2087 void KHTMLPart::write( const char *data, int len )
2088 {
2089  if ( !d->m_decoder )
2090  d->m_decoder = createDecoder();
2091 
2092  if ( len == -1 )
2093  len = strlen( data );
2094 
2095  if ( len == 0 )
2096  return;
2097 
2098  QString decoded=d->m_decoder->decodeWithBuffering(data,len);
2099 
2100  if(decoded.isEmpty())
2101  return;
2102 
2103  if(d->m_bFirstData)
2104  onFirstData();
2105 
2106  khtml::Tokenizer* t = d->m_doc->tokenizer();
2107  if(t)
2108  t->write( decoded, true );
2109 }
2110 
2111 // ### KDE5: remove
2112 void KHTMLPart::setAlwaysHonourDoctype( bool b )
2113 {
2114  d->m_bStrictModeQuirk = !b;
2115 }
2116 
2117 void KHTMLPart::write( const QString &str )
2118 {
2119  if ( str.isNull() )
2120  return;
2121 
2122  if(d->m_bFirstData) {
2123  // determine the parse mode
2124  if (d->m_bStrictModeQuirk) {
2125  d->m_doc->setParseMode( DocumentImpl::Strict );
2126  d->m_bFirstData = false;
2127  } else {
2128  onFirstData();
2129  }
2130  }
2131  khtml::Tokenizer* t = d->m_doc->tokenizer();
2132  if(t)
2133  t->write( str, true );
2134 }
2135 
2136 void KHTMLPart::end()
2137 {
2138  if (d->m_doc) {
2139  if (d->m_decoder)
2140  {
2141  QString decoded=d->m_decoder->flush();
2142  if (d->m_bFirstData)
2143  onFirstData();
2144  if (!decoded.isEmpty())
2145  write(decoded);
2146  }
2147  d->m_doc->finishParsing();
2148  }
2149 }
2150 
2151 void KHTMLPart::onFirstData()
2152 {
2153  assert( d->m_bFirstData );
2154 
2155  // determine the parse mode
2156  d->m_doc->determineParseMode();
2157  d->m_bFirstData = false;
2158 
2159  // ### this is still quite hacky, but should work a lot better than the old solution
2160  // Note: decoder may be null if only write(QString) is used.
2161  if (d->m_decoder && d->m_decoder->visuallyOrdered())
2162  d->m_doc->setVisuallyOrdered();
2163  // ensure part and view shares zoom-level before styling
2164  updateZoomFactor();
2165  d->m_doc->recalcStyle( NodeImpl::Force );
2166 }
2167 
2168 bool KHTMLPart::doOpenStream( const QString& mimeType )
2169 {
2170  KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases);
2171  if ( mime && ( mime->is( "text/html" ) || mime->is( "text/xml" ) ) )
2172  {
2173  begin( url() );
2174  return true;
2175  }
2176  return false;
2177 }
2178 
2179 bool KHTMLPart::doWriteStream( const QByteArray& data )
2180 {
2181  write( data.data(), data.size() );
2182  return true;
2183 }
2184 
2185 bool KHTMLPart::doCloseStream()
2186 {
2187  end();
2188  return true;
2189 }
2190 
2191 
2192 void KHTMLPart::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
2193 {
2194  if (!d->m_view) return;
2195  d->m_view->paint(p, rc, yOff, more);
2196 }
2197 
2198 void KHTMLPart::stopAnimations()
2199 {
2200  if ( d->m_doc )
2201  d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
2202 
2203  ConstFrameIt it = d->m_frames.constBegin();
2204  const ConstFrameIt end = d->m_frames.constEnd();
2205  for (; it != end; ++it ) {
2206  if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
2207  p->stopAnimations();
2208  }
2209 }
2210 
2211 void KHTMLPart::resetFromScript()
2212 {
2213  closeUrl();
2214  d->m_bComplete = false;
2215  d->m_bLoadEventEmitted = false;
2216  disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2217  connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2218  d->m_doc->setParsing(true);
2219 
2220  emit started( 0L );
2221 }
2222 
2223 void KHTMLPart::slotFinishedParsing()
2224 {
2225  d->m_doc->setParsing(false);
2226  d->m_doc->dispatchHTMLEvent(EventImpl::KHTML_CONTENTLOADED_EVENT, true, false);
2227  checkEmitLoadEvent();
2228  disconnect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
2229 
2230  if (!d->m_view)
2231  return; // We are probably being destructed.
2232 
2233  checkCompleted();
2234 }
2235 
2236 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
2237 {
2238  if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
2239  KHTMLPart* p = this;
2240  while ( p ) {
2241  KHTMLPart* const op = p;
2242  ++(p->d->m_totalObjectCount);
2243  p = p->parentPart();
2244  if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount
2245  && !op->d->m_progressUpdateTimer.isActive()) {
2246  op->d->m_progressUpdateTimer.setSingleShot( true );
2247  op->d->m_progressUpdateTimer.start( 200 );
2248  }
2249  }
2250  }
2251 }
2252 
2253 static bool isAncestorOrSamePart(KHTMLPart* p1, KHTMLPart* p2)
2254 {
2255  KHTMLPart* p = p2;
2256  do {
2257  if (p == p1)
2258  return true;
2259  } while ((p = p->parentPart()));
2260  return false;
2261 }
2262 
2263 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
2264 {
2265  if ( obj && obj->type() == khtml::CachedObject::Image && d->m_doc && d->m_doc->docLoader() == dl ) {
2266  KHTMLPart* p = this;
2267  while ( p ) {
2268  KHTMLPart* const op = p;
2269  ++(p->d->m_loadedObjects);
2270  p = p->parentPart();
2271  if ( !p && op->d->m_loadedObjects <= op->d->m_totalObjectCount && op->d->m_jobPercent <= 100
2272  && !op->d->m_progressUpdateTimer.isActive()) {
2273  op->d->m_progressUpdateTimer.setSingleShot( true );
2274  op->d->m_progressUpdateTimer.start( 200 );
2275  }
2276  }
2277  }
2279  // then our loading state can't possibly be affected : don't waste time checking for completion.
2280  if (!d->m_doc || !dl->doc()->part() || !isAncestorOrSamePart(this, dl->doc()->part()))
2281  return;
2282  checkCompleted();
2283 }
2284 
2285 void KHTMLPart::slotProgressUpdate()
2286 {
2287  int percent;
2288  if ( d->m_loadedObjects < d->m_totalObjectCount )
2289  percent = d->m_jobPercent / 4 + ( d->m_loadedObjects*300 ) / ( 4*d->m_totalObjectCount );
2290  else
2291  percent = d->m_jobPercent;
2292 
2293  if( d->m_bComplete )
2294  percent = 100;
2295 
2296  if (d->m_statusMessagesEnabled) {
2297  if( d->m_bComplete )
2298  emit d->m_extension->infoMessage( i18n( "Page loaded." ));
2299  else if ( d->m_loadedObjects < d->m_totalObjectCount && percent >= 75 )
2300  emit d->m_extension->infoMessage( i18np( "%1 Image of %2 loaded.", "%1 Images of %2 loaded.", d->m_loadedObjects, d->m_totalObjectCount) );
2301  }
2302 
2303  emit d->m_extension->loadingProgress( percent );
2304 }
2305 
2306 void KHTMLPart::slotJobSpeed( KJob* /*job*/, unsigned long speed )
2307 {
2308  d->m_jobspeed = speed;
2309  if (!parentPart())
2310  setStatusBarText(jsStatusBarText(), BarOverrideText);
2311 }
2312 
2313 void KHTMLPart::slotJobPercent( KJob* /*job*/, unsigned long percent )
2314 {
2315  d->m_jobPercent = percent;
2316 
2317  if ( !parentPart() ) {
2318  d->m_progressUpdateTimer.setSingleShot( true );
2319  d->m_progressUpdateTimer.start( 0 );
2320  }
2321 }
2322 
2323 void KHTMLPart::slotJobDone( KJob* /*job*/ )
2324 {
2325  d->m_jobPercent = 100;
2326 
2327  if ( !parentPart() ) {
2328  d->m_progressUpdateTimer.setSingleShot( true );
2329  d->m_progressUpdateTimer.start( 0 );
2330  }
2331 }
2332 
2333 void KHTMLPart::slotUserSheetStatDone( KJob *_job )
2334 {
2335  using namespace KIO;
2336 
2337  if ( _job->error() ) {
2338  showError( _job );
2339  return;
2340  }
2341 
2342  const UDSEntry entry = dynamic_cast<KIO::StatJob *>( _job )->statResult();
2343  const time_t lastModified = entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, -1 );
2344 
2345  // If the filesystem supports modification times, only reload the
2346  // user-defined stylesheet if necessary - otherwise always reload.
2347  if ( lastModified != static_cast<time_t>(-1) ) {
2348  if ( d->m_userStyleSheetLastModified >= lastModified ) {
2349  return;
2350  }
2351  d->m_userStyleSheetLastModified = lastModified;
2352  }
2353 
2354  setUserStyleSheet( KUrl( settings()->userStyleSheet() ) );
2355 }
2356 
2357 bool KHTMLPartPrivate::isFullyLoaded(bool* pendingRedirections) const
2358 {
2359  *pendingRedirections = false;
2360 
2361  // Any frame that hasn't completed yet ?
2362  ConstFrameIt it = m_frames.constBegin();
2363  const ConstFrameIt end = m_frames.constEnd();
2364  for (; it != end; ++it ) {
2365  if ( !(*it)->m_bCompleted || (*it)->m_run )
2366  {
2367  //kDebug( 6050 ) << this << " is waiting for " << (*it)->m_part;
2368  return false;
2369  }
2370  // Check for frames with pending redirections
2371  if ( (*it)->m_bPendingRedirection )
2372  *pendingRedirections = true;
2373  }
2374 
2375  // Any object that hasn't completed yet ?
2376  {
2377  ConstFrameIt oi = m_objects.constBegin();
2378  const ConstFrameIt oiEnd = m_objects.constEnd();
2379 
2380  for (; oi != oiEnd; ++oi )
2381  if ( !(*oi)->m_bCompleted )
2382  return false;
2383  }
2384 
2385  // Are we still parsing
2386  if ( m_doc && m_doc->parsing() )
2387  return false;
2388 
2389  // Still waiting for images/scripts from the loader ?
2390  int requests = 0;
2391  if ( m_doc && m_doc->docLoader() )
2392  requests = khtml::Cache::loader()->numRequests( m_doc->docLoader() );
2393 
2394  if ( requests > 0 )
2395  {
2396  //kDebug(6050) << "still waiting for images/scripts from the loader - requests:" << requests;
2397  return false;
2398  }
2399 
2400  return true;
2401 }
2402 
2403 void KHTMLPart::checkCompleted()
2404 {
2405 // kDebug( 6050 ) << this;
2406 // kDebug( 6050 ) << " parsing: " << (d->m_doc && d->m_doc->parsing());
2407 // kDebug( 6050 ) << " complete: " << d->m_bComplete;
2408 
2409  // restore the cursor position
2410  if (d->m_doc && !d->m_doc->parsing() && !d->m_focusNodeRestored)
2411  {
2412  if (d->m_focusNodeNumber >= 0)
2413  d->m_doc->setFocusNode(d->m_doc->nodeWithAbsIndex(d->m_focusNodeNumber));
2414 
2415  d->m_focusNodeRestored = true;
2416  }
2417 
2418  bool fullyLoaded, pendingChildRedirections;
2419  fullyLoaded = d->isFullyLoaded(&pendingChildRedirections);
2420 
2421  // Are we still loading, or already have done the relevant work?
2422  if (!fullyLoaded || d->m_bComplete)
2423  return;
2424 
2425  // OK, completed.
2426  // Now do what should be done when we are really completed.
2427  d->m_bComplete = true;
2428  d->m_cachePolicy = KProtocolManager::cacheControl(); // reset cache policy
2429  d->m_totalObjectCount = 0;
2430  d->m_loadedObjects = 0;
2431 
2432  KHTMLPart* p = this;
2433  while ( p ) {
2434  KHTMLPart* op = p;
2435  p = p->parentPart();
2436  if ( !p && !op->d->m_progressUpdateTimer.isActive()) {
2437  op->d->m_progressUpdateTimer.setSingleShot( true );
2438  op->d->m_progressUpdateTimer.start( 0 );
2439  }
2440  }
2441 
2442  checkEmitLoadEvent(); // if we didn't do it before
2443 
2444  bool pendingAction = false;
2445 
2446  if ( !d->m_redirectURL.isEmpty() )
2447  {
2448  // DA: Do not start redirection for frames here! That action is
2449  // deferred until the parent emits a completed signal.
2450  if ( parentPart() == 0 ) {
2451  //kDebug(6050) << this << " starting redirection timer";
2452  d->m_redirectionTimer.setSingleShot( true );
2453  d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
2454  } else {
2455  //kDebug(6050) << this << " not toplevel -> not starting redirection timer. Waiting for slotParentCompleted.";
2456  }
2457 
2458  pendingAction = true;
2459  }
2460  else if ( pendingChildRedirections )
2461  {
2462  pendingAction = true;
2463  }
2464 
2465  // the view will emit completed on our behalf,
2466  // either now or at next repaint if one is pending
2467 
2468  //kDebug(6050) << this << " asks the view to emit completed. pendingAction=" << pendingAction;
2469  d->m_view->complete( pendingAction );
2470 
2471  // find the alternate stylesheets
2472  QStringList sheets;
2473  if (d->m_doc)
2474  sheets = d->m_doc->availableStyleSheets();
2475  sheets.prepend( i18n( "Automatic Detection" ) );
2476  d->m_paUseStylesheet->setItems( sheets );
2477 
2478  d->m_paUseStylesheet->setEnabled( sheets.count() > 2);
2479  if (sheets.count() > 2)
2480  {
2481  d->m_paUseStylesheet->setCurrentItem(qMax(sheets.indexOf(d->m_sheetUsed), 0));
2482  slotUseStylesheet();
2483  }
2484 
2485  setJSDefaultStatusBarText(QString());
2486 
2487 #ifdef SPEED_DEBUG
2488  if (!parentPart())
2489  kDebug(6080) << "DONE:" <<d->m_parsetime.elapsed();
2490 #endif
2491 }
2492 
2493 void KHTMLPart::checkEmitLoadEvent()
2494 {
2495  bool fullyLoaded, pendingChildRedirections;
2496  fullyLoaded = d->isFullyLoaded(&pendingChildRedirections);
2497 
2498  // ### might want to wait on pendingChildRedirections here, too
2499  if ( d->m_bLoadEventEmitted || !d->m_doc || !fullyLoaded ) return;
2500 
2501  d->m_bLoadEventEmitted = true;
2502  if (d->m_doc)
2503  d->m_doc->close();
2504 }
2505 
2506 const KHTMLSettings *KHTMLPart::settings() const
2507 {
2508  return d->m_settings;
2509 }
2510 
2511 #ifndef KDE_NO_COMPAT // KDE5: remove this ifndef, keep the method (renamed to baseUrl)
2512 KUrl KHTMLPart::baseURL() const
2513 {
2514  if ( !d->m_doc ) return KUrl();
2515 
2516  return d->m_doc->baseURL();
2517 }
2518 #endif
2519 
2520 KUrl KHTMLPart::completeURL( const QString &url )
2521 {
2522  if ( !d->m_doc ) return KUrl( url );
2523 
2524 #if 0
2525  if (d->m_decoder)
2526  return KUrl(d->m_doc->completeURL(url), d->m_decoder->codec()->mibEnum());
2527 #endif
2528 
2529  return KUrl( d->m_doc->completeURL( url ) );
2530 }
2531 
2532 QString KHTMLPartPrivate::codeForJavaScriptURL(const QString &u)
2533 {
2534  return KUrl::fromPercentEncoding( u.right( u.length() - 11 ).toUtf8() );
2535 }
2536 
2537 void KHTMLPartPrivate::executeJavascriptURL(const QString &u)
2538 {
2539  QString script = codeForJavaScriptURL(u);
2540  kDebug( 6050 ) << "script=" << script;
2541  QVariant res = q->executeScript( DOM::Node(), script );
2542  if ( res.type() == QVariant::String ) {
2543  q->begin( q->url() );
2544  q->setAlwaysHonourDoctype(); // Disable public API compat; it messes with doctype
2545  q->write( res.toString() );
2546  q->end();
2547  }
2548  emit q->completed();
2549 }
2550 
2551 bool KHTMLPartPrivate::isJavaScriptURL(const QString& url)
2552 {
2553  return url.indexOf( QLatin1String( "javascript:" ), 0, Qt::CaseInsensitive ) == 0;
2554 }
2555 
2556 // Called by ecma/kjs_window in case of redirections from Javascript,
2557 // and by xml/dom_docimpl.cpp in case of http-equiv meta refresh.
2558 void KHTMLPart::scheduleRedirection( int delay, const QString &url, bool doLockHistory )
2559 {
2560  kDebug(6050) << "delay=" << delay << " url=" << url << " from=" << this->url() << "parent=" << parentPart();
2561  kDebug(6050) << "current redirectURL=" << d->m_redirectURL << " with delay " << d->m_delayRedirect;
2562 
2563  // In case of JS redirections, some, such as jump to anchors, and javascript:
2564  // evaluation should actually be handled immediately, and not waiting until
2565  // the end of the script. (Besides, we don't want to abort the tokenizer for those)
2566  if ( delay == -1 && d->isInPageURL(url) ) {
2567  d->executeInPageURL(url, doLockHistory);
2568  return;
2569  }
2570 
2571  if( delay < 24*60*60 &&
2572  ( d->m_redirectURL.isEmpty() || delay <= d->m_delayRedirect) ) {
2573  d->m_delayRedirect = delay;
2574  d->m_redirectURL = url;
2575  d->m_redirectLockHistory = doLockHistory;
2576  kDebug(6050) << " d->m_bComplete=" << d->m_bComplete;
2577 
2578  if ( d->m_bComplete ) {
2579  d->m_redirectionTimer.stop();
2580  d->m_redirectionTimer.setSingleShot( true );
2581  d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
2582  }
2583  }
2584 }
2585 
2586 void KHTMLPartPrivate::clearRedirection()
2587 {
2588  m_delayRedirect = 0;
2589  m_redirectURL.clear();
2590  m_redirectionTimer.stop();
2591 }
2592 
2593 void KHTMLPart::slotRedirect()
2594 {
2595  kDebug(6050) << this;
2596  QString u = d->m_redirectURL;
2597  KUrl url( u );
2598  d->clearRedirection();
2599 
2600  if ( d->isInPageURL(u) )
2601  {
2602  d->executeInPageURL(u, d->m_redirectLockHistory);
2603  return;
2604  }
2605 
2606  KParts::OpenUrlArguments args;
2607  KUrl cUrl( this->url() );
2608 
2609  // handle windows opened by JS
2610  if ( openedByJS() && d->m_opener )
2611  cUrl = d->m_opener->url();
2612 
2613  if (!KAuthorized::authorizeUrlAction("redirect", cUrl, url))
2614  {
2615  kWarning(6050) << "KHTMLPart::scheduleRedirection: Redirection from " << cUrl << " to " << url << " REJECTED!";
2616  emit completed();
2617  return;
2618  }
2619 
2620  if ( url.equals(this->url(),
2621  KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment | KUrl::AllowEmptyPath) )
2622  {
2623  args.metaData().insert("referrer", d->m_pageReferrer);
2624  }
2625 
2626  // For javascript and META-tag based redirections:
2627  // - We don't take cross-domain-ness in consideration if we are the
2628  // toplevel frame because the new URL may be in a different domain as the current URL
2629  // but that's ok.
2630  // - If we are not the toplevel frame then we check against the toplevelURL()
2631  if (parentPart())
2632  args.metaData().insert("cross-domain", toplevelURL().url());
2633 
2634  KParts::BrowserArguments browserArgs;
2635  browserArgs.setLockHistory( d->m_redirectLockHistory );
2636  // _self: make sure we don't use any <base target=>'s
2637 
2638  if ( !urlSelected( u, 0, 0, "_self", args, browserArgs ) ) {
2639  // urlSelected didn't open a url, so emit completed ourselves
2640  emit completed();
2641  }
2642 }
2643 
2644 void KHTMLPart::slotRedirection(KIO::Job*, const KUrl& url)
2645 {
2646  // the slave told us that we got redirected
2647  //kDebug( 6050 ) << "redirection by KIO to" << url;
2648  emit d->m_extension->setLocationBarUrl( url.prettyUrl() );
2649  d->m_workingURL = url;
2650 }
2651 
2652 bool KHTMLPart::setEncoding( const QString &name, bool override )
2653 {
2654  d->m_encoding = name;
2655  d->m_haveEncoding = override;
2656 
2657  if( !url().isEmpty() ) {
2658  // reload document
2659  closeUrl();
2660  KUrl oldUrl = url();
2661  setUrl(KUrl());
2662  d->m_restored = true;
2663  openUrl(oldUrl);
2664  d->m_restored = false;
2665  }
2666 
2667  return true;
2668 }
2669 
2670 QString KHTMLPart::encoding() const
2671 {
2672  if(d->m_haveEncoding && !d->m_encoding.isEmpty())
2673  return d->m_encoding;
2674 
2675  if(d->m_decoder && d->m_decoder->encoding())
2676  return QString(d->m_decoder->encoding());
2677 
2678  return defaultEncoding();
2679 }
2680 
2681 QString KHTMLPart::defaultEncoding() const
2682 {
2683  QString encoding = settings()->encoding();
2684  if ( !encoding.isEmpty() )
2685  return encoding;
2686  // HTTP requires the default encoding to be latin1, when neither
2687  // the user nor the page requested a particular encoding.
2688  if ( url().protocol().startsWith( "http" ) )
2689  return "iso-8859-1";
2690  else
2691  return KGlobal::locale()->encoding();
2692 }
2693 
2694 void KHTMLPart::setUserStyleSheet(const KUrl &url)
2695 {
2696  if ( d->m_doc && d->m_doc->docLoader() )
2697  (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
2698 }
2699 
2700 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
2701 {
2702  if ( d->m_doc )
2703  d->m_doc->setUserStyleSheet( styleSheet );
2704 }
2705 
2706 bool KHTMLPart::gotoAnchor( const QString &name )
2707 {
2708  if (!d->m_doc)
2709  return false;
2710 
2711  HTMLCollectionImpl *anchors =
2712  new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
2713  anchors->ref();
2714  NodeImpl *n = anchors->namedItem(name);
2715  anchors->deref();
2716 
2717  if(!n) {
2718  n = d->m_doc->getElementById( name );
2719  }
2720 
2721  d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
2722 
2723  // Implement the rule that "" and "top" both mean top of page as in other browsers.
2724  bool quirkyName = !n && !d->m_doc->inStrictMode() && (name.isEmpty() || name.toLower() == "top");
2725 
2726  if (quirkyName) {
2727  d->m_view->setContentsPos( d->m_view->contentsX(), 0);
2728  return true;
2729  } else if (!n) {
2730  kDebug(6050) << name << "not found";
2731  return false;
2732  }
2733 
2734  int x = 0, y = 0;
2735  int gox, dummy;
2736  HTMLElementImpl *a = static_cast<HTMLElementImpl *>(n);
2737 
2738  a->getUpperLeftCorner(x, y);
2739  if (x <= d->m_view->contentsX())
2740  gox = x - 10;
2741  else {
2742  gox = d->m_view->contentsX();
2743  if ( x + 10 > d->m_view->contentsX()+d->m_view->visibleWidth()) {
2744  a->getLowerRightCorner(x, dummy);
2745  gox = x - d->m_view->visibleWidth() + 10;
2746  }
2747  }
2748 
2749  d->m_view->setContentsPos(gox, y);
2750 
2751  return true;
2752 }
2753 
2754 bool KHTMLPart::nextAnchor()
2755 {
2756  if (!d->m_doc)
2757  return false;
2758  d->m_view->focusNextPrevNode ( true );
2759 
2760  return true;
2761 }
2762 
2763 bool KHTMLPart::prevAnchor()
2764 {
2765  if (!d->m_doc)
2766  return false;
2767  d->m_view->focusNextPrevNode ( false );
2768 
2769  return true;
2770 }
2771 
2772 void KHTMLPart::setStandardFont( const QString &name )
2773 {
2774  d->m_settings->setStdFontName(name);
2775 }
2776 
2777 void KHTMLPart::setFixedFont( const QString &name )
2778 {
2779  d->m_settings->setFixedFontName(name);
2780 }
2781 
2782 void KHTMLPart::setURLCursor( const QCursor &c )
2783 {
2784  d->m_linkCursor = c;
2785 }
2786 
2787 QCursor KHTMLPart::urlCursor() const
2788 {
2789  return d->m_linkCursor;
2790 }
2791 
2792 bool KHTMLPart::onlyLocalReferences() const
2793 {
2794  return d->m_onlyLocalReferences;
2795 }
2796 
2797 void KHTMLPart::setOnlyLocalReferences(bool enable)
2798 {
2799  d->m_onlyLocalReferences = enable;
2800 }
2801 
2802 bool KHTMLPart::forcePermitLocalImages() const
2803 {
2804  return d->m_forcePermitLocalImages;
2805 }
2806 
2807 void KHTMLPart::setForcePermitLocalImages(bool enable)
2808 {
2809  d->m_forcePermitLocalImages = enable;
2810 }
2811 
2812 void KHTMLPartPrivate::setFlagRecursively(
2813  bool KHTMLPartPrivate::*flag, bool value)
2814 {
2815  // first set it on the current one
2816  this->*flag = value;
2817 
2818  // descend into child frames recursively
2819  {
2820  QList<khtml::ChildFrame*>::Iterator it = m_frames.begin();
2821  const QList<khtml::ChildFrame*>::Iterator itEnd = m_frames.end();
2822  for (; it != itEnd; ++it) {
2823  KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part.data() );
2824  if (part)
2825  part->d->setFlagRecursively(flag, value);
2826  }/*next it*/
2827  }
2828  // do the same again for objects
2829  {
2830  QList<khtml::ChildFrame*>::Iterator it = m_objects.begin();
2831  const QList<khtml::ChildFrame*>::Iterator itEnd = m_objects.end();
2832  for (; it != itEnd; ++it) {
2833  KHTMLPart* const part = qobject_cast<KHTMLPart *>( (*it)->m_part.data() );
2834  if (part)
2835  part->d->setFlagRecursively(flag, value);
2836  }/*next it*/
2837  }
2838 }
2839 
2840 void KHTMLPart::initCaret()
2841 {
2842  // initialize caret if not used yet
2843  if (d->editor_context.m_selection.state() == Selection::NONE) {
2844  if (d->m_doc) {
2845  NodeImpl *node;
2846  if (d->m_doc->isHTMLDocument()) {
2847  HTMLDocumentImpl* htmlDoc = static_cast<HTMLDocumentImpl*>(d->m_doc);
2848  node = htmlDoc->body();
2849  } else
2850  node = d->m_doc;
2851  if (!node) return;
2852  d->editor_context.m_selection.moveTo(Position(node, 0));
2853  d->editor_context.m_selection.setNeedsLayout();
2854  d->editor_context.m_selection.needsCaretRepaint();
2855  }
2856  }
2857 }
2858 
2859 static void setCaretInvisibleIfNeeded(KHTMLPart *part)
2860 {
2861  // On contenteditable nodes, don't hide the caret
2862  if (!khtml::KHTMLPartAccessor::caret(part).caretPos().node()->isContentEditable())
2863  part->setCaretVisible(false);
2864 }
2865 
2866 void KHTMLPart::setCaretMode(bool enable)
2867 {
2868  kDebug(6200) << enable;
2869  if (isCaretMode() == enable) return;
2870  d->setFlagRecursively(&KHTMLPartPrivate::m_caretMode, enable);
2871  // FIXME: this won't work on frames as expected
2872  if (!isEditable()) {
2873  if (enable) {
2874  initCaret();
2875  setCaretVisible(true);
2876 // view()->ensureCaretVisible();
2877  } else {
2878  setCaretInvisibleIfNeeded(this);
2879  }
2880  }
2881 }
2882 
2883 bool KHTMLPart::isCaretMode() const
2884 {
2885  return d->m_caretMode;
2886 }
2887 
2888 void KHTMLPart::setEditable(bool enable)
2889 {
2890  if (isEditable() == enable) return;
2891  d->setFlagRecursively(&KHTMLPartPrivate::m_designMode, enable);
2892  // FIXME: this won't work on frames as expected
2893  if (!isCaretMode()) {
2894  if (enable) {
2895  initCaret();
2896  setCaretVisible(true);
2897 // view()->ensureCaretVisible();
2898  } else
2899  setCaretInvisibleIfNeeded(this);
2900  }
2901 }
2902 
2903 bool KHTMLPart::isEditable() const
2904 {
2905  return d->m_designMode;
2906 }
2907 
2908 khtml::EditorContext *KHTMLPart::editorContext() const {
2909  return &d->editor_context;
2910 }
2911 
2912 void KHTMLPart::setCaretPosition(DOM::Node node, long offset, bool extendSelection)
2913 {
2914  Q_UNUSED(node);
2915  Q_UNUSED(offset);
2916  Q_UNUSED(extendSelection);
2917 #ifndef KHTML_NO_CARET
2918 #if 0
2919  kDebug(6200) << "node: " << node.handle() << " nodeName: "
2920  << node.nodeName().string() << " offset: " << offset
2921  << " extendSelection " << extendSelection;
2922  if (view()->moveCaretTo(node.handle(), offset, !extendSelection))
2923  emitSelectionChanged();
2924  view()->ensureCaretVisible();
2925 #endif
2926 #endif // KHTML_NO_CARET
2927 }
2928 
2929 KHTMLPart::CaretDisplayPolicy KHTMLPart::caretDisplayPolicyNonFocused() const
2930 {
2931 #if 0
2932 #ifndef KHTML_NO_CARET
2933  return (CaretDisplayPolicy)view()->caretDisplayPolicyNonFocused();
2934 #else // KHTML_NO_CARET
2935  return CaretInvisible;
2936 #endif // KHTML_NO_CARET
2937 #endif
2938  return CaretInvisible;
2939 }
2940 
2941 void KHTMLPart::setCaretDisplayPolicyNonFocused(CaretDisplayPolicy policy)
2942 {
2943  Q_UNUSED(policy);
2944 #if 0
2945 #ifndef KHTML_NO_CARET
2946  view()->setCaretDisplayPolicyNonFocused(policy);
2947 #endif // KHTML_NO_CARET
2948 #endif
2949 }
2950 
2951 void KHTMLPart::setCaretVisible(bool show)
2952 {
2953  if (show) {
2954  NodeImpl *caretNode = d->editor_context.m_selection.caretPos().node();
2955  if (isCaretMode() || (caretNode && caretNode->isContentEditable())) {
2956  invalidateSelection();
2957  enableFindAheadActions(false);
2958  }
2959  } else {
2960 
2961  if (d->editor_context.m_caretBlinkTimer >= 0)
2962  killTimer(d->editor_context.m_caretBlinkTimer);
2963  clearCaretRectIfNeeded();
2964 
2965  }
2966 }
2967 
2968 void KHTMLPart::findTextBegin()
2969 {
2970  d->m_find.findTextBegin();
2971 }
2972 
2973 bool KHTMLPart::initFindNode( bool selection, bool reverse, bool fromCursor )
2974 {
2975  return d->m_find.initFindNode(selection, reverse, fromCursor);
2976 }
2977 
2978 void KHTMLPart::slotFind()
2979 {
2980  KParts::ReadOnlyPart *part = currentFrame();
2981  if (!part)
2982  return;
2983  if (!part->inherits("KHTMLPart") )
2984  {
2985  kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2986  return;
2987  }
2988  static_cast<KHTMLPart *>( part )->findText();
2989 }
2990 
2991 void KHTMLPart::slotFindNext()
2992 {
2993  KParts::ReadOnlyPart *part = currentFrame();
2994  if (!part)
2995  return;
2996  if (!part->inherits("KHTMLPart") )
2997  {
2998  kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
2999  return;
3000  }
3001  static_cast<KHTMLPart *>( part )->findTextNext();
3002 }
3003 
3004 void KHTMLPart::slotFindPrev()
3005 {
3006  KParts::ReadOnlyPart *part = currentFrame();
3007  if (!part)
3008  return;
3009  if (!part->inherits("KHTMLPart") )
3010  {
3011  kError(6000) << "part is a" << part->metaObject()->className() << ", can't do a search into it";
3012  return;
3013  }
3014  static_cast<KHTMLPart *>( part )->findTextNext( true ); // reverse
3015 }
3016 
3017 void KHTMLPart::slotFindDone()
3018 {
3019  // ### remove me
3020 }
3021 
3022 void KHTMLPart::slotFindAheadText()
3023 {
3024  KHTMLPart *part = qobject_cast<KHTMLPart*>(currentFrame());
3025  if (!part)
3026  return;
3027  part->findText();
3028  KHTMLFindBar* findBar = part->d->m_find.findBar();
3029  findBar->setOptions(findBar->options() & ~FindLinksOnly);
3030 }
3031 
3032 void KHTMLPart::slotFindAheadLink()
3033 {
3034  KHTMLPart *part = qobject_cast<KHTMLPart*>(currentFrame());
3035  if (!part)
3036  return;
3037  part->findText();
3038  KHTMLFindBar* findBar = part->d->m_find.findBar();
3039  findBar->setOptions(findBar->options() | FindLinksOnly);
3040 }
3041 
3042 void KHTMLPart::enableFindAheadActions( bool )
3043 {
3044  // ### remove me
3045 }
3046 
3047 void KHTMLPart::slotFindDialogDestroyed()
3048 {
3049  // ### remove me
3050 }
3051 
3052 void KHTMLPart::findText()
3053 {
3054  if (parentPart())
3055  return parentPart()->findText();
3056  d->m_find.activate();
3057 }
3058 
3059 void KHTMLPart::findText( const QString &str, long options, QWidget *parent, KFindDialog *findDialog )
3060 {
3061  if (parentPart())
3062  return parentPart()->findText(str, options, parent, findDialog);
3063  d->m_find.createNewKFind(str, options, parent, findDialog );
3064 }
3065 
3066 // New method
3067 bool KHTMLPart::findTextNext( bool reverse )
3068 {
3069  if (parentPart())
3070  return parentPart()->findTextNext( reverse );
3071  return d->m_find.findTextNext( reverse );
3072 }
3073 
3074 bool KHTMLPart::pFindTextNextInThisFrame( bool reverse )
3075 {
3076  return d->m_find.findTextNext( reverse );
3077 }
3078 
3079 QString KHTMLPart::selectedTextAsHTML() const
3080 {
3081  const Selection &sel = d->editor_context.m_selection;
3082  if(!hasSelection()) {
3083  kDebug() << "Selection is not valid. Returning empty selection";
3084  return QString();
3085  }
3086  if(sel.start().offset() < 0 || sel.end().offset() < 0) {
3087  kDebug() << "invalid values for end/startOffset " << sel.start().offset() << " " << sel.end().offset();
3088  return QString();
3089  }
3090  DOM::Range r = selection();
3091  if(r.isNull() || r.isDetached())
3092  return QString();
3093  int exceptioncode = 0; //ignore the result
3094  return r.handle()->toHTML(exceptioncode).string();
3095 }
3096 
3097 QString KHTMLPart::selectedText() const
3098 {
3099  bool hasNewLine = true;
3100  bool seenTDTag = false;
3101  QString text;
3102  const Selection &sel = d->editor_context.m_selection;
3103  DOM::Node n = sel.start().node();
3104  while(!n.isNull()) {
3105  if(n.nodeType() == DOM::Node::TEXT_NODE && n.handle()->renderer()) {
3106  DOM::DOMStringImpl *dstr = static_cast<DOM::TextImpl*>(n.handle())->renderString();
3107  QString str(dstr->s, dstr->l);
3108  if(!str.isEmpty()) {
3109  if(seenTDTag) {
3110  text += " ";
3111  seenTDTag = false;
3112  }
3113  hasNewLine = false;
3114  if(n == sel.start().node() && n == sel.end().node()) {
3115  int s = khtml::RenderPosition::fromDOMPosition(sel.start()).renderedOffset();
3116  int e = khtml::RenderPosition::fromDOMPosition(sel.end()).renderedOffset();
3117  text = str.mid(s, e-s);
3118  } else if(n == sel.start().node()) {
3119  text = str.mid(khtml::RenderPosition::fromDOMPosition(sel.start()).renderedOffset());
3120  } else if(n == sel.end().node()) {
3121  text += str.left(khtml::RenderPosition::fromDOMPosition(sel.end()).renderedOffset());
3122  } else
3123  text += str;
3124  }
3125  }
3126  else {
3127  // This is our simple HTML -> ASCII transformation:
3128  unsigned short id = n.elementId();
3129  switch(id) {
3130  case ID_TEXTAREA:
3131  text += static_cast<HTMLTextAreaElementImpl*>(n.handle())->value().string();
3132  break;
3133  case ID_INPUT:
3134  if (static_cast<HTMLInputElementImpl*>(n.handle())->inputType() != HTMLInputElementImpl::PASSWORD)
3135  text += static_cast<HTMLInputElementImpl*>(n.handle())->value().string();
3136  break;
3137  case ID_SELECT:
3138  text += static_cast<HTMLSelectElementImpl*>(n.handle())->value().string();
3139  break;
3140  case ID_BR:
3141  text += "\n";
3142  hasNewLine = true;
3143  break;
3144  case ID_IMG:
3145  text += static_cast<HTMLImageElementImpl*>(n.handle())->altText().string();
3146  break;
3147  case ID_TD:
3148  break;
3149  case ID_TH:
3150  case ID_HR:
3151  case ID_OL:
3152  case ID_UL:
3153  case ID_LI:
3154  case ID_DD:
3155  case ID_DL:
3156  case ID_DT:
3157  case ID_PRE:
3158  case ID_LISTING:
3159  case ID_BLOCKQUOTE:
3160  case ID_DIV:
3161  if (!hasNewLine)
3162  text += "\n";
3163  hasNewLine = true;
3164  break;
3165  case ID_P:
3166  case ID_TR:
3167  case ID_H1:
3168  case ID_H2:
3169  case ID_H3:
3170  case ID_H4:
3171  case ID_H5:
3172  case ID_H6:
3173  if (!hasNewLine)
3174  text += "\n";
3175  hasNewLine = true;
3176  break;
3177  }
3178  }
3179  if(n == sel.end().node()) break;
3180  DOM::Node next = n.firstChild();
3181  if(next.isNull()) next = n.nextSibling();
3182  while( next.isNull() && !n.parentNode().isNull() ) {
3183  n = n.parentNode();
3184  next = n.nextSibling();
3185  unsigned short id = n.elementId();
3186  switch(id) {
3187  case ID_TD:
3188  seenTDTag = true; //Add two spaces after a td if then followed by text.
3189  break;
3190  case ID_TH:
3191  case ID_HR:
3192  case ID_OL:
3193  case ID_UL:
3194  case ID_LI:
3195  case ID_DD:
3196  case ID_DL:
3197  case ID_DT:
3198  case ID_PRE:
3199  case ID_LISTING:
3200  case ID_BLOCKQUOTE:
3201  case ID_DIV:
3202  seenTDTag = false;
3203  if (!hasNewLine)
3204  text += "\n";
3205  hasNewLine = true;
3206  break;
3207  case ID_P:
3208  case ID_TR:
3209  case ID_H1:
3210  case ID_H2:
3211  case ID_H3:
3212  case ID_H4:
3213  case ID_H5:
3214  case ID_H6:
3215  if (!hasNewLine)
3216  text += "\n";
3217 // text += "\n";
3218  hasNewLine = true;
3219  break;
3220  }
3221  }
3222 
3223  n = next;
3224  }
3225 
3226  if(text.isEmpty())
3227  return QString();
3228 
3229  int start = 0;
3230  int end = text.length();
3231 
3232  // Strip leading LFs
3233  while ((start < end) && (text[start] == '\n'))
3234  ++start;
3235 
3236  // Strip excessive trailing LFs
3237  while ((start < (end-1)) && (text[end-1] == '\n') && (text[end-2] == '\n'))
3238  --end;
3239 
3240  return text.mid(start, end-start);
3241 }
3242 
3243 QString KHTMLPart::simplifiedSelectedText() const
3244 {
3245  QString text = selectedText();
3246  text.replace(QChar(0xa0), ' ');
3247  // remove leading and trailing whitespace
3248  while (!text.isEmpty() && text[0].isSpace())
3249  text = text.mid(1);
3250  while (!text.isEmpty() && text[text.length()-1].isSpace())
3251  text.truncate(text.length()-1);
3252  return text;
3253 }
3254 
3255 bool KHTMLPart::hasSelection() const
3256 {
3257  return !d->editor_context.m_selection.isEmpty() && !d->editor_context.m_selection.isCollapsed();
3258 }
3259 
3260 DOM::Range KHTMLPart::selection() const
3261 {
3262  return d->editor_context.m_selection.toRange();
3263 }
3264 
3265 void KHTMLPart::selection(DOM::Node &s, long &so, DOM::Node &e, long &eo) const
3266 {
3267  DOM::Range r = d->editor_context.m_selection.toRange();
3268  s = r.startContainer();
3269  so = r.startOffset();
3270  e = r.endContainer();
3271  eo = r.endOffset();
3272 }
3273 
3274 void KHTMLPart::setSelection( const DOM::Range &r )
3275 {
3276  setCaret(r);
3277 }
3278 
3279 const Selection &KHTMLPart::caret() const
3280 {
3281  return d->editor_context.m_selection;
3282 }
3283 
3284 const Selection &KHTMLPart::dragCaret() const
3285 {
3286  return d->editor_context.m_dragCaret;
3287 }
3288 
3289 void KHTMLPart::setCaret(const Selection &s, bool closeTyping)
3290 {
3291  if (d->editor_context.m_selection != s) {
3292  clearCaretRectIfNeeded();
3293  setFocusNodeIfNeeded(s);
3294  d->editor_context.m_selection = s;
3295  notifySelectionChanged(closeTyping);
3296  }
3297 }
3298 
3299 void KHTMLPart::setDragCaret(const DOM::Selection &dragCaret)
3300 {
3301  if (d->editor_context.m_dragCaret != dragCaret) {
3302  d->editor_context.m_dragCaret.needsCaretRepaint();
3303  d->editor_context.m_dragCaret = dragCaret;
3304  d->editor_context.m_dragCaret.needsCaretRepaint();
3305  }
3306 }
3307 
3308 void KHTMLPart::clearSelection()
3309 {
3310  clearCaretRectIfNeeded();
3311  setFocusNodeIfNeeded(d->editor_context.m_selection);
3312 #ifdef APPLE_CHANGES
3313  d->editor_context.m_selection.clear();
3314 #else
3315  d->editor_context.m_selection.collapse();
3316 #endif
3317  notifySelectionChanged();
3318 }
3319 
3320 void KHTMLPart::invalidateSelection()
3321 {
3322  clearCaretRectIfNeeded();
3323  d->editor_context.m_selection.setNeedsLayout();
3324  selectionLayoutChanged();
3325 }
3326 
3327 void KHTMLPart::setSelectionVisible(bool flag)
3328 {
3329  if (d->editor_context.m_caretVisible == flag)
3330  return;
3331 
3332  clearCaretRectIfNeeded();
3333  setFocusNodeIfNeeded(d->editor_context.m_selection);
3334  d->editor_context.m_caretVisible = flag;
3335 // notifySelectionChanged();
3336 }
3337 
3338 #if 1
3339 void KHTMLPart::slotClearSelection()
3340 {
3341  if (!isCaretMode()
3342  && d->editor_context.m_selection.state() != Selection::NONE
3343  && !d->editor_context.m_selection.caretPos().node()->isContentEditable())
3344  clearCaretRectIfNeeded();
3345  bool hadSelection = hasSelection();
3346 #ifdef APPLE_CHANGES
3347  d->editor_context.m_selection.clear();
3348 #else
3349  d->editor_context.m_selection.collapse();
3350 #endif
3351  if (hadSelection)
3352  notifySelectionChanged();
3353 }
3354 #endif
3355 
3356 void KHTMLPart::clearCaretRectIfNeeded()
3357 {
3358  if (d->editor_context.m_caretPaint) {
3359  d->editor_context.m_caretPaint = false;
3360  d->editor_context.m_selection.needsCaretRepaint();
3361  }
3362 }
3363 
3364 void KHTMLPart::setFocusNodeIfNeeded(const Selection &s)
3365 {
3366  if (!xmlDocImpl() || s.state() == Selection::NONE)
3367  return;
3368 
3369  NodeImpl *n = s.start().node();
3370  NodeImpl *target = (n && n->isContentEditable()) ? n : 0;
3371  if (!target) {
3372  while (n && n != s.end().node()) {
3373  if (n->isContentEditable()) {
3374  target = n;
3375  break;
3376  }
3377  n = n->traverseNextNode();
3378  }
3379  }
3380  assert(target == 0 || target->isContentEditable());
3381 
3382  if (target) {
3383  for ( ; target && !target->isFocusable(); target = target->parentNode())
3384  {}
3385  if (target && target->isMouseFocusable())
3386  xmlDocImpl()->setFocusNode(target);
3387  else if (!target || !target->focused())
3388  xmlDocImpl()->setFocusNode(0);
3389  }
3390 }
3391 
3392 void KHTMLPart::selectionLayoutChanged()
3393 {
3394  // kill any caret blink timer now running
3395  if (d->editor_context.m_caretBlinkTimer >= 0) {
3396  killTimer(d->editor_context.m_caretBlinkTimer);
3397  d->editor_context.m_caretBlinkTimer = -1;
3398  }
3399 
3400  // see if a new caret blink timer needs to be started
3401  if (d->editor_context.m_caretVisible
3402  && d->editor_context.m_selection.state() != Selection::NONE) {
3403  d->editor_context.m_caretPaint = isCaretMode()
3404  || d->editor_context.m_selection.caretPos().node()->isContentEditable();
3405  if (d->editor_context.m_caretBlinks && d->editor_context.m_caretPaint)
3406  d->editor_context.m_caretBlinkTimer = startTimer(qApp->cursorFlashTime() / 2);
3407  d->editor_context.m_selection.needsCaretRepaint();
3408  // make sure that caret is visible
3409  QRect r(d->editor_context.m_selection.getRepaintRect());
3410  if (d->editor_context.m_caretPaint)
3411  d->m_view->ensureVisible(r.x(), r.y());
3412  }
3413 
3414  if (d->m_doc)
3415  d->m_doc->updateSelection();
3416 
3417  // Always clear the x position used for vertical arrow navigation.
3418  // It will be restored by the vertical arrow navigation code if necessary.
3419  d->editor_context.m_xPosForVerticalArrowNavigation = d->editor_context.NoXPosForVerticalArrowNavigation;
3420 }
3421 
3422 void KHTMLPart::notifySelectionChanged(bool closeTyping)
3423 {
3424  Editor *ed = d->editor_context.m_editor;
3425  selectionLayoutChanged();
3426  if (ed) {
3427  ed->clearTypingStyle();
3428 
3429  if (closeTyping)
3430  ed->closeTyping();
3431  }
3432 
3433  emitSelectionChanged();
3434 }
3435 
3436 void KHTMLPart::timerEvent(QTimerEvent *e)
3437 {
3438  if (e->timerId() == d->editor_context.m_caretBlinkTimer) {
3439  if (d->editor_context.m_caretBlinks &&
3440  d->editor_context.m_selection.state() != Selection::NONE) {
3441  d->editor_context.m_caretPaint = !d->editor_context.m_caretPaint;
3442  d->editor_context.m_selection.needsCaretRepaint();
3443  }
3444  } else if (e->timerId() == d->m_DNSPrefetchTimer) {
3445  // kDebug( 6050 ) << "will lookup " << d->m_DNSPrefetchQueue.head() << d->m_numDNSPrefetchedNames;
3446  KIO::HostInfo::prefetchHost( d->m_DNSPrefetchQueue.dequeue() );
3447  if (d->m_DNSPrefetchQueue.isEmpty()) {
3448  killTimer( d->m_DNSPrefetchTimer );
3449  d->m_DNSPrefetchTimer = -1;
3450  }
3451  } else if (e->timerId() == d->m_DNSTTLTimer) {
3452  foreach (const QString &name, d->m_lookedupHosts)
3453  d->m_DNSPrefetchQueue.enqueue(name);
3454  if (d->m_DNSPrefetchTimer <= 0)
3455  d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay );
3456  }
3457 }
3458 
3459 bool KHTMLPart::mayPrefetchHostname( const QString& name )
3460 {
3461  if (d->m_bDNSPrefetch == DNSPrefetchDisabled)
3462  return false;
3463 
3464  if (d->m_numDNSPrefetchedNames >= sMaxDNSPrefetchPerPage)
3465  return false;
3466 
3467  if (d->m_bDNSPrefetch == DNSPrefetchOnlyWWWAndSLD) {
3468  int dots = name.count('.');
3469  if (dots > 2 || (dots == 2 && !name.startsWith("www.")))
3470  return false;
3471  }
3472 
3473  if ( d->m_lookedupHosts.contains( name ) )
3474  return false;
3475 
3476  d->m_DNSPrefetchQueue.enqueue( name );
3477  d->m_lookedupHosts.insert( name );
3478  d->m_numDNSPrefetchedNames++;
3479 
3480  if (d->m_DNSPrefetchTimer < 1)
3481  d->m_DNSPrefetchTimer = startTimer( sDNSPrefetchTimerDelay );
3482  if (d->m_DNSTTLTimer < 1)
3483  d->m_DNSTTLTimer = startTimer( sDNSTTLSeconds*1000 + 1 );
3484 
3485  return true;
3486 }
3487 
3488 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
3489 {
3490  if (d->editor_context.m_caretPaint)
3491  d->editor_context.m_selection.paintCaret(p, rect);
3492 }
3493 
3494 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
3495 {
3496  d->editor_context.m_dragCaret.paintCaret(p, rect);
3497 }
3498 
3499 DOM::Editor *KHTMLPart::editor() const {
3500  if (!d->editor_context.m_editor)
3501  const_cast<KHTMLPart *>(this)->d->editor_context.m_editor = new DOM::Editor(const_cast<KHTMLPart *>(this));
3502  return d->editor_context.m_editor;
3503 }
3504 
3505 void KHTMLPart::resetHoverText()
3506 {
3507  if( !d->m_overURL.isEmpty() ) // Only if we were showing a link
3508  {
3509  d->m_overURL.clear();
3510  d->m_overURLTarget.clear();
3511  emit onURL( QString() );
3512  // revert to default statusbar text
3513  setStatusBarText(QString(), BarHoverText);
3514  emit d->m_extension->mouseOverInfo(KFileItem());
3515  }
3516 }
3517 
3518 void KHTMLPart::overURL( const QString &url, const QString &target, bool /*shiftPressed*/ )
3519 {
3520  KUrl u = completeURL(url);
3521 
3522  // special case for <a href="">
3523  if ( url.isEmpty() )
3524  u.setFileName( url );
3525 
3526  emit onURL( url );
3527 
3528  if ( url.isEmpty() ) {
3529  setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText);
3530  return;
3531  }
3532 
3533  if ( d->isJavaScriptURL(url) ) {
3534  QString jscode = d->codeForJavaScriptURL( url );
3535  jscode = KStringHandler::rsqueeze( jscode, 80 ); // truncate if too long
3536  if (url.startsWith("javascript:window.open"))
3537  jscode += i18n(" (In new window)");
3538  setStatusBarText( Qt::escape( jscode ), BarHoverText );
3539  return;
3540  }
3541 
3542  KFileItem item(u, QString(), KFileItem::Unknown);
3543  emit d->m_extension->mouseOverInfo(item);
3544 
3545  QString com;
3546 
3547  KMimeType::Ptr typ = KMimeType::findByUrl( u );
3548 
3549  if ( typ )
3550  com = typ->comment( u );
3551 
3552  if ( !u.isValid() ) {
3553  setStatusBarText(Qt::escape(u.prettyUrl()), BarHoverText);
3554  return;
3555  }
3556 
3557  if ( u.isLocalFile() )
3558  {
3559  // TODO : use KIO::stat() and create a KFileItem out of its result,
3560  // to use KFileItem::statusBarText()
3561  const QString path = QFile::encodeName( u.toLocalFile() );
3562 
3563  KDE_struct_stat buff;
3564  bool ok = !KDE::stat( path, &buff );
3565 
3566  KDE_struct_stat lbuff;
3567  if (ok) ok = !KDE::lstat( path, &lbuff );
3568 
3569  QString text = Qt::escape(u.prettyUrl());
3570  QString text2 = text;
3571 
3572  if (ok && S_ISLNK( lbuff.st_mode ) )
3573  {
3574  QString tmp;
3575  if ( com.isNull() )
3576  tmp = i18n( "Symbolic Link");
3577  else
3578  tmp = i18n("%1 (Link)", com);
3579  char buff_two[1024];
3580  text += " -> ";
3581  int n = readlink ( path.toLocal8Bit().data(), buff_two, 1022);
3582  if (n == -1)
3583  {
3584  text2 += " ";
3585  text2 += tmp;
3586  setStatusBarText(text2, BarHoverText);
3587  return;
3588  }
3589  buff_two[n] = 0;
3590 
3591  text += buff_two;
3592  text += " ";
3593  text += tmp;
3594  }
3595  else if ( ok && S_ISREG( buff.st_mode ) )
3596  {
3597  if (buff.st_size < 1024)
3598  text = i18np("%2 (%1 byte)", "%2 (%1 bytes)", (long) buff.st_size, text2); // always put the URL last, in case it contains '%'
3599  else
3600  {
3601  float d = (float) buff.st_size/1024.0;
3602  text = i18n("%2 (%1 K)", KGlobal::locale()->formatNumber(d, 2), text2); // was %.2f
3603  }
3604  text += " ";
3605  text += com;
3606  }
3607  else if ( ok && S_ISDIR( buff.st_mode ) )
3608  {
3609  text += " ";
3610  text += com;
3611  }
3612  else
3613  {
3614  text += " ";
3615  text += com;
3616  }
3617  setStatusBarText(text, BarHoverText);
3618  }
3619  else
3620  {
3621  QString extra;
3622  if (target.toLower() == "_blank")
3623  {
3624  extra = i18n(" (In new window)");
3625  }
3626  else if (!target.isEmpty() &&
3627  (target.toLower() != "_top") &&
3628  (target.toLower() != "_self") &&
3629  (target.toLower() != "_parent"))
3630  {
3631  KHTMLPart *p = this;
3632  while (p->parentPart())
3633  p = p->parentPart();
3634  if (!p->frameExists(target))
3635  extra = i18n(" (In new window)");
3636  else
3637  extra = i18n(" (In other frame)");
3638  }
3639 
3640  if (u.protocol() == QLatin1String("mailto")) {
3641  QString mailtoMsg /* = QString::fromLatin1("<img src=%1>").arg(locate("icon", QString::fromLatin1("locolor/16x16/actions/mail_send.png")))*/;
3642  mailtoMsg += i18n("Email to: ") + KUrl::fromPercentEncoding(u.path().toLatin1());
3643  const QStringList queries = u.query().mid(1).split('&');
3644  QStringList::ConstIterator it = queries.begin();
3645  const QStringList::ConstIterator itEnd = queries.end();
3646  for (; it != itEnd; ++it)
3647  if ((*it).startsWith(QLatin1String("subject=")))
3648  mailtoMsg += i18n(" - Subject: ") + KUrl::fromPercentEncoding((*it).mid(8).toLatin1());
3649  else if ((*it).startsWith(QLatin1String("cc=")))
3650  mailtoMsg += i18n(" - CC: ") + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
3651  else if ((*it).startsWith(QLatin1String("bcc=")))
3652  mailtoMsg += i18n(" - BCC: ") + KUrl::fromPercentEncoding((*it).mid(4).toLatin1());
3653  mailtoMsg = Qt::escape(mailtoMsg);
3654  mailtoMsg.replace(QRegExp("([\n\r\t]|[ ]{10})"), QString());
3655  setStatusBarText("<qt>"+mailtoMsg, BarHoverText);
3656  return;
3657  }
3658  // Is this check necessary at all? (Frerich)
3659 #if 0
3660  else if (u.protocol() == QLatin1String("http")) {
3661  DOM::Node hrefNode = nodeUnderMouse().parentNode();
3662  while (hrefNode.nodeName().string() != QLatin1String("A") && !hrefNode.isNull())
3663  hrefNode = hrefNode.parentNode();
3664 
3665  if (!hrefNode.isNull()) {
3666  DOM::Node hreflangNode = hrefNode.attributes().getNamedItem("HREFLANG");
3667  if (!hreflangNode.isNull()) {
3668  QString countryCode = hreflangNode.nodeValue().string().toLower();
3669  // Map the language code to an appropriate country code.
3670  if (countryCode == QLatin1String("en"))
3671  countryCode = QLatin1String("gb");
3672  QString flagImg = QLatin1String("<img src=%1>").arg(
3673  locate("locale", QLatin1String("l10n/")
3674  + countryCode
3675  + QLatin1String("/flag.png")));
3676  emit setStatusBarText(flagImg + u.prettyUrl() + extra);
3677  }
3678  }
3679  }
3680 #endif
3681  setStatusBarText(Qt::escape(u.prettyUrl()) + extra, BarHoverText);
3682  }
3683 }
3684 
3685 //
3686 // This executes in the active part on a click or other url selection action in
3687 // that active part.
3688 //
3689 bool KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target, const KParts::OpenUrlArguments& _args, const KParts::BrowserArguments& _browserArgs )
3690 {
3691  KParts::OpenUrlArguments args = _args;
3692  KParts::BrowserArguments browserArgs = _browserArgs;
3693  bool hasTarget = false;
3694 
3695  QString target = _target;
3696  if ( target.isEmpty() && d->m_doc )
3697  target = d->m_doc->baseTarget();
3698  if ( !target.isEmpty() )
3699  hasTarget = true;
3700 
3701  if ( d->isJavaScriptURL(url) )
3702  {
3703  crossFrameExecuteScript( target, d->codeForJavaScriptURL(url) );
3704  return false;
3705  }
3706 
3707  KUrl cURL = completeURL(url);
3708  // special case for <a href=""> (IE removes filename, mozilla doesn't)
3709  if ( url.isEmpty() )
3710  cURL.setFileName( url ); // removes filename
3711 
3712  if ( !cURL.isValid() )
3713  // ### ERROR HANDLING
3714  return false;
3715 
3716  kDebug(6050) << this << "complete URL:" << cURL.url() << "target=" << target;
3717 
3718  if ( state & Qt::ControlModifier )
3719  {
3720  emit d->m_extension->createNewWindow( cURL, args, browserArgs );
3721  return true;
3722  }
3723 
3724  if ( button == Qt::LeftButton && ( state & Qt::ShiftModifier ) )
3725  {
3726  KIO::MetaData metaData;
3727  metaData.insert( "referrer", d->m_referrer );
3728  KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), cURL, metaData );
3729  return false;
3730  }
3731 
3732  if (!checkLinkSecurity(cURL,
3733  ki18n( "<qt>This untrusted page links to<br /><b>%1</b>.<br />Do you want to follow the link?</qt>" ),
3734  i18n( "Follow" )))
3735  return false;
3736 
3737  browserArgs.frameName = target;
3738 
3739  args.metaData().insert("main_frame_request",
3740  parentPart() == 0 ? "TRUE":"FALSE");
3741  args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
3742  args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
3743  args.metaData().insert("PropagateHttpHeader", "true");
3744  args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
3745  args.metaData().insert("ssl_activate_warnings", "TRUE");
3746 
3747  if ( hasTarget && target != "_self" && target != "_top" && target != "_blank" && target != "_parent" )
3748  {
3749  // unknown frame names should open in a new window.
3750  khtml::ChildFrame *frame = recursiveFrameRequest( this, cURL, args, browserArgs, false );
3751  if ( frame )
3752  {
3753  args.metaData()["referrer"] = d->m_referrer;
3754  requestObject( frame, cURL, args, browserArgs );
3755  return true;
3756  }
3757  }
3758 
3759  if (!d->m_referrer.isEmpty() && !args.metaData().contains("referrer"))
3760  args.metaData()["referrer"] = d->m_referrer;
3761 
3762  if ( button == Qt::NoButton && (state & Qt::ShiftModifier) && (state & Qt::ControlModifier) )
3763  {
3764  emit d->m_extension->createNewWindow( cURL, args, browserArgs );
3765  return true;
3766  }
3767 
3768  if ( state & Qt::ShiftModifier)
3769  {
3770  KParts::WindowArgs winArgs;
3771  winArgs.setLowerWindow(true);
3772  emit d->m_extension->createNewWindow( cURL, args, browserArgs, winArgs );
3773  return true;
3774  }
3775 
3776  //If we're asked to open up an anchor in the current URL, in current window,
3777  //merely gotoanchor, and do not reload the new page. Note that this does
3778  //not apply if the URL is the same page, but without a ref
3779  if (cURL.hasRef() && (!hasTarget || target == "_self"))
3780  {
3781  if (d->isLocalAnchorJump(cURL))
3782  {
3783  d->executeAnchorJump(cURL, browserArgs.lockHistory() );
3784  return false; // we jumped, but we didn't open a URL
3785  }
3786  }
3787 
3788  if ( !d->m_bComplete && !hasTarget )
3789  closeUrl();
3790 
3791  view()->viewport()->unsetCursor();
3792  emit d->m_extension->openUrlRequest( cURL, args, browserArgs );
3793  return true;
3794 }
3795 
3796 void KHTMLPart::slotViewDocumentSource()
3797 {
3798  KUrl currentUrl(this->url());
3799  bool isTempFile = false;
3800  if (!(currentUrl.isLocalFile()) && KHTMLPageCache::self()->isComplete(d->m_cacheId))
3801  {
3802  KTemporaryFile sourceFile;
3803  sourceFile.setSuffix(defaultExtension());
3804  sourceFile.setAutoRemove(false);
3805  if (sourceFile.open())
3806  {
3807  QDataStream stream ( &sourceFile );
3808  KHTMLPageCache::self()->saveData(d->m_cacheId, &stream);
3809  currentUrl = KUrl();
3810  currentUrl.setPath(sourceFile.fileName());
3811  isTempFile = true;
3812  }
3813  }
3814 
3815  (void) KRun::runUrl( currentUrl, QLatin1String("text/plain"), view(), isTempFile );
3816 }
3817 
3818 void KHTMLPart::slotViewPageInfo()
3819 {
3820  Ui_KHTMLInfoDlg ui;
3821 
3822  QDialog *dlg = new QDialog(0);
3823  dlg->setAttribute(Qt::WA_DeleteOnClose);
3824  dlg->setObjectName("KHTML Page Info Dialog");
3825  ui.setupUi(dlg);
3826 
3827  ui._close->setGuiItem(KStandardGuiItem::close());
3828 
3829  connect(ui._close, SIGNAL(clicked()), dlg, SLOT(accept()));
3830  if (d->m_doc)
3831  ui._title->setText(d->m_doc->title().string());
3832 
3833  // If it's a frame, set the caption to "Frame Information"
3834  if ( parentPart() && d->m_doc && d->m_doc->isHTMLDocument() ) {
3835  dlg->setWindowTitle(i18n("Frame Information"));
3836  }
3837 
3838  QString editStr;
3839 
3840  if (!d->m_pageServices.isEmpty())
3841  editStr = i18n(" <a href=\"%1\">[Properties]</a>", d->m_pageServices);
3842 
3843  QString squeezedURL = KStringHandler::csqueeze( url().prettyUrl(), 80 );
3844  ui._url->setText("<a href=\"" + url().url() + "\">" + squeezedURL + "</a>" + editStr);
3845  if (lastModified().isEmpty())
3846  {
3847  ui._lastModified->hide();
3848  ui._lmLabel->hide();
3849  }
3850  else
3851  ui._lastModified->setText(lastModified());
3852 
3853  const QString& enc = encoding();
3854  if (enc.isEmpty()) {
3855  ui._eLabel->hide();
3856  ui._encoding->hide();
3857  } else {
3858  ui._encoding->setText(enc);
3859  }
3860 
3861  if (!xmlDocImpl() || xmlDocImpl()->parseMode() == DOM::DocumentImpl::Unknown) {
3862  ui._mode->hide();
3863  ui._modeLabel->hide();
3864  } else {
3865  switch (xmlDocImpl()->parseMode()) {
3866  case DOM::DocumentImpl::Compat:
3867  ui._mode->setText(i18nc("HTML rendering mode (see http://en.wikipedia.org/wiki/Quirks_mode)", "Quirks"));
3868  break;
3869  case DOM::DocumentImpl::Transitional:
3870  ui._mode->setText(i18nc("HTML rendering mode (see http://en.wikipedia.org/wiki/Quirks_mode)", "Almost standards"));
3871  break;
3872  case DOM::DocumentImpl::Strict:
3873  default: // others handled above
3874  ui._mode->setText(i18nc("HTML rendering mode (see http://en.wikipedia.org/wiki/Quirks_mode)", "Strict"));
3875  break;
3876  }
3877  }
3878 
3879  /* populate the list view now */
3880  const QStringList headers = d->m_httpHeaders.split("\n");
3881 
3882  QStringList::ConstIterator it = headers.begin();
3883  const QStringList::ConstIterator itEnd = headers.end();
3884 
3885  for (; it != itEnd; ++it) {
3886  const QStringList header = (*it).split(QRegExp(":[ ]+"));
3887  if (header.count() != 2)
3888  continue;
3889  QTreeWidgetItem *item = new QTreeWidgetItem(ui._headers);
3890  item->setText(0, header[0]);
3891  item->setText(1, header[1]);
3892  }
3893 
3894  dlg->show();
3895  /* put no code here */
3896 }
3897 
3898 
3899 void KHTMLPart::slotViewFrameSource()
3900 {
3901  KParts::ReadOnlyPart *frame = currentFrame();
3902  if ( !frame )
3903  return;
3904 
3905  KUrl url = frame->url();
3906  bool isTempFile = false;
3907  if (!(url.isLocalFile()) && frame->inherits("KHTMLPart"))
3908  {
3909  long cacheId = static_cast<KHTMLPart *>(frame)->d->m_cacheId;
3910 
3911  if (KHTMLPageCache::self()->isComplete(cacheId))
3912  {
3913  KTemporaryFile sourceFile;
3914  sourceFile.setSuffix(defaultExtension());
3915  sourceFile.setAutoRemove(false);
3916  if (sourceFile.open())
3917  {
3918  QDataStream stream ( &sourceFile );
3919  KHTMLPageCache::self()->saveData(cacheId, &stream);
3920  url = KUrl();
3921  url.setPath(sourceFile.fileName());
3922  isTempFile = true;
3923  }
3924  }
3925  }
3926 
3927  (void) KRun::runUrl( url, QLatin1String("text/plain"), view(), isTempFile );
3928 }
3929 
3930 KUrl KHTMLPart::backgroundURL() const
3931 {
3932  // ### what about XML documents? get from CSS?
3933  if (!d->m_doc || !d->m_doc->isHTMLDocument())
3934  return KUrl();
3935 
3936  QString relURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
3937 
3938  return KUrl( url(), relURL );
3939 }
3940 
3941 void KHTMLPart::slotSaveBackground()
3942 {
3943  KIO::MetaData metaData;
3944  metaData["referrer"] = d->m_referrer;
3945  KHTMLPopupGUIClient::saveURL( d->m_view, i18n("Save Background Image As"), backgroundURL(), metaData );
3946 }
3947 
3948 void KHTMLPart::slotSaveDocument()
3949 {
3950  KUrl srcURL( url() );
3951 
3952  if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() )
3953  srcURL.setFileName( "index" + defaultExtension() );
3954 
3955  KIO::MetaData metaData;
3956  // Referre unknown?
3957  KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save As" ), srcURL, metaData, "text/html", d->m_cacheId );
3958 }
3959 
3960 void KHTMLPart::slotSecurity()
3961 {
3962 // kDebug( 6050 ) << "Meta Data:" << endl
3963 // << d->m_ssl_peer_cert_subject
3964 // << endl
3965 // << d->m_ssl_peer_cert_issuer
3966 // << endl
3967 // << d->m_ssl_cipher
3968 // << endl
3969 // << d->m_ssl_cipher_desc
3970 // << endl
3971 // << d->m_ssl_cipher_version
3972 // << endl
3973 // << d->m_ssl_good_from
3974 // << endl
3975 // << d->m_ssl_good_until
3976 // << endl
3977 // << d->m_ssl_cert_state
3978 // << endl;
3979 
3980  //### reenable with new signature
3981 #if 0
3982  KSslInfoDialog *kid = new KSslInfoDialog(d->m_ssl_in_use, widget(), "kssl_info_dlg", true );
3983 
3984  const QStringList sl = d->m_ssl_peer_chain.split('\n', QString::SkipEmptyParts);
3985  QList<QSslCertificate> certChain;
3986  bool certChainOk = d->m_ssl_in_use;
3987  if (certChainOk) {
3988  foreach (const QString &s, sl) {
3989  certChain.append(QSslCertificate(s.toLatin1())); //or is it toLocal8Bit or whatever?
3990  if (certChain.last().isNull()) {
3991  certChainOk = false;
3992  break;
3993  }
3994  }
3995  }
3996  if (certChainOk) {
3997  kid->setup(certChain,
3998  d->m_ssl_peer_ip,
3999  url().url(),
4000  d->m_ssl_cipher,
4001  d->m_ssl_cipher_desc,
4002  d->m_ssl_cipher_version,
4003  d->m_ssl_cipher_used_bits.toInt(),
4004  d->m_ssl_cipher_bits.toInt(),
4005  (KSSLCertificate::KSSLValidation) d->m_ssl_cert_state.toInt());
4006  }
4007  kid->exec();
4008  //the dialog deletes itself on close
4009 #endif
4010 
4011  KSslInfoDialog *kid = new KSslInfoDialog(0);
4012  //### This is boilerplate code and it's copied from SlaveInterface.
4013  QStringList sl = d->m_ssl_peer_chain.split('\x01', QString::SkipEmptyParts);
4014  QList<QSslCertificate> certChain;
4015  bool decodedOk = true;
4016  foreach (const QString &s, sl) {
4017  certChain.append(QSslCertificate(s.toLatin1())); //or is it toLocal8Bit or whatever?
4018  if (certChain.last().isNull()) {
4019  decodedOk = false;
4020  break;
4021  }
4022  }
4023 
4024  if (decodedOk || true /*H4X*/) {
4025  kid->setSslInfo(certChain,
4026  d->m_ssl_peer_ip,
4027  url().host(),
4028  d->m_ssl_protocol_version,
4029  d->m_ssl_cipher,
4030  d->m_ssl_cipher_used_bits.toInt(),
4031  d->m_ssl_cipher_bits.toInt(),
4032  KSslInfoDialog::errorsFromString(d->m_ssl_cert_errors));
4033  kDebug(7024) << "Showing SSL Info dialog";
4034  kid->exec();
4035  kDebug(7024) << "SSL Info dialog closed";
4036  } else {
4037  KMessageBox::information(0, i18n("The peer SSL certificate chain "
4038  "appears to be corrupt."),
4039  i18n("SSL"));
4040  }
4041 }
4042 
4043 void KHTMLPart::slotSaveFrame()
4044 {
4045  KParts::ReadOnlyPart *frame = currentFrame();
4046  if ( !frame )
4047  return;
4048 
4049  KUrl srcURL( frame->url() );
4050 
4051  if ( srcURL.fileName(KUrl::ObeyTrailingSlash).isEmpty() )
4052  srcURL.setFileName( "index" + defaultExtension() );
4053 
4054  KIO::MetaData metaData;
4055  // Referrer unknown?
4056  KHTMLPopupGUIClient::saveURL( d->m_view, i18n( "Save Frame As" ), srcURL, metaData, "text/html" );
4057 }
4058 
4059 void KHTMLPart::slotSetEncoding(const QString &enc)
4060 {
4061  d->m_autoDetectLanguage=KEncodingDetector::None;
4062  setEncoding( enc, true);
4063 }
4064 
4065 void KHTMLPart::slotAutomaticDetectionLanguage(KEncodingDetector::AutoDetectScript scri)
4066 {
4067  d->m_autoDetectLanguage=scri;
4068  setEncoding( QString(), false );
4069 }
4070 
4071 void KHTMLPart::slotUseStylesheet()
4072 {
4073  if (d->m_doc)
4074  {
4075  bool autoselect = (d->m_paUseStylesheet->currentItem() == 0);
4076  d->m_sheetUsed = autoselect ? QString() : d->m_paUseStylesheet->currentText();
4077  d->m_doc->updateStyleSelector();
4078  }
4079 }
4080 
4081 void KHTMLPart::updateActions()
4082 {
4083  bool frames = false;
4084 
4085  QList<khtml::ChildFrame*>::ConstIterator it = d->m_frames.constBegin();
4086  const QList<khtml::ChildFrame*>::ConstIterator end = d->m_frames.constEnd();
4087  for (; it != end; ++it )
4088  if ( (*it)->m_type == khtml::ChildFrame::Frame )
4089  {
4090  frames = true;
4091  break;
4092  }
4093 
4094  if (d->m_paViewFrame)
4095  d->m_paViewFrame->setEnabled( frames );
4096  if (d->m_paSaveFrame)
4097  d->m_paSaveFrame->setEnabled( frames );
4098 
4099  if ( frames )
4100  d->m_paFind->setText( i18n( "&Find in Frame..." ) );
4101  else
4102  d->m_paFind->setText( i18n( "&Find..." ) );
4103 
4104  KParts::Part *frame = 0;
4105 
4106  if ( frames )
4107  frame = currentFrame();
4108 
4109  bool enableFindAndSelectAll = true;
4110 
4111  if ( frame )
4112  enableFindAndSelectAll = frame->inherits( "KHTMLPart" );
4113 
4114  d->m_paFind->setEnabled( enableFindAndSelectAll );
4115  d->m_paSelectAll->setEnabled( enableFindAndSelectAll );
4116 
4117  bool enablePrintFrame = false;
4118 
4119  if ( frame )
4120  {
4121  QObject *ext = KParts::BrowserExtension::childObject( frame );
4122  if ( ext )
4123  enablePrintFrame = ext->metaObject()->indexOfSlot( "print()" ) != -1;
4124  }
4125 
4126  d->m_paPrintFrame->setEnabled( enablePrintFrame );
4127 
4128  QString bgURL;
4129 
4130  // ### frames
4131  if ( d->m_doc && d->m_doc->isHTMLDocument() && static_cast<HTMLDocumentImpl*>(d->m_doc)->body() && !d->m_bClearing )
4132  bgURL = static_cast<HTMLDocumentImpl*>(d->m_doc)->body()->getAttribute( ATTR_BACKGROUND ).string();
4133 
4134  if (d->m_paSaveBackground)
4135  d->m_paSaveBackground->setEnabled( !bgURL.isEmpty() );
4136 
4137  if ( d->m_paDebugScript )
4138  d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
4139 }
4140 
4141 KParts::ScriptableExtension *KHTMLPart::scriptableExtension( const DOM::NodeImpl *frame) {
4142  const ConstFrameIt end = d->m_objects.constEnd();
4143  for(ConstFrameIt it = d->m_objects.constBegin(); it != end; ++it )
4144  if ((*it)->m_partContainerElement.data() == frame)
4145  return (*it)->m_scriptable.data();
4146  return 0L;
4147 }
4148 
4149 void KHTMLPart::loadFrameElement( DOM::HTMLPartContainerElementImpl *frame, const QString &url,
4150  const QString &frameName, const QStringList &params, bool isIFrame )
4151 {
4152  //kDebug( 6050 ) << this << " requestFrame( ..., " << url << ", " << frameName << " )";
4153  khtml::ChildFrame* child;
4154 
4155  FrameIt it = d->m_frames.find( frameName );
4156  if ( it == d->m_frames.end() ) {
4157  child = new khtml::ChildFrame;
4158  //kDebug( 6050 ) << "inserting new frame into frame map " << frameName;
4159  child->m_name = frameName;
4160  d->m_frames.insert( d->m_frames.end(), child );
4161  } else {
4162  child = *it;
4163  }
4164 
4165  child->m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
4166  child->m_partContainerElement = frame;
4167  child->m_params = params;
4168 
4169  // If we do not have a part, make sure we create one.
4170  if (!child->m_part) {
4171  QStringList dummy; // the list of servicetypes handled by the part is now unused.
4172  QString khtml = QString::fromLatin1("khtml");
4173  KParts::ReadOnlyPart* part = createPart(d->m_view->viewport(), this,
4174  QString::fromLatin1("text/html"),
4175  khtml, dummy, QStringList());
4176  // We navigate it to about:blank to setup an empty one, but we do it
4177  // before hooking up the signals and extensions, so that any sync emit
4178  // of completed by the kid doesn't cause us to be marked as completed.
4179  // (async ones are discovered by the presence of the KHTMLRun)
4180  // ### load event on the kid?
4181  navigateLocalProtocol(child, part, KUrl("about:blank"));
4182  connectToChildPart(child, part, "text/html" /* mimetype of the part, not what's being loaded */);
4183  }
4184 
4185  KUrl u = url.isEmpty() ? KUrl() : completeURL( url );
4186 
4187  // Since we don't specify args here a KHTMLRun will be used to determine the
4188  // mimetype, which will then be passed down at the bottom of processObjectRequest
4189  // inside URLArgs to the part. In our particular case, this means that we can
4190  // use that inside KHTMLPart::openUrl to route things appropriately.
4191  child->m_bCompleted = false;
4192  if (!requestObject( child, u ) && !child->m_run) {
4193  child->m_bCompleted = true;
4194  }
4195 }
4196 
4197 QString KHTMLPart::requestFrameName()
4198 {
4199  return QString::fromLatin1("<!--frame %1-->").arg(d->m_frameNameId++);
4200 }
4201 
4202 bool KHTMLPart::loadObjectElement( DOM::HTMLPartContainerElementImpl *frame, const QString &url,
4203  const QString &serviceType, const QStringList &params )
4204 {
4205  //kDebug( 6031 ) << this << "frame=" << frame;
4206  khtml::ChildFrame *child = new khtml::ChildFrame;
4207  FrameIt it = d->m_objects.insert( d->m_objects.end(), child );
4208  (*it)->m_partContainerElement = frame;
4209  (*it)->m_type = khtml::ChildFrame::Object;
4210  (*it)->m_params = params;
4211 
4212  KParts::OpenUrlArguments args;
4213  args.setMimeType(serviceType);
4214  if (!requestObject( *it, completeURL( url ), args ) && !(*it)->m_run) {
4215  (*it)->m_bCompleted = true;
4216  return false;
4217  }
4218  return true;
4219 }
4220 
4221 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KUrl &url, const KParts::OpenUrlArguments &_args,
4222  const KParts::BrowserArguments& browserArgs )
4223 {
4224  // we always permit javascript: URLs here since they're basically just
4225  // empty pages (and checkLinkSecurity/KAuthorized doesn't know what to do with them)
4226  if (!d->isJavaScriptURL(url.url()) && !checkLinkSecurity(url))
4227  {
4228  kDebug(6031) << this << "checkLinkSecurity refused";
4229  return false;
4230  }
4231 
4232  if (d->m_bClearing)
4233  {
4234  return false;
4235  }
4236 
4237  if ( child->m_bPreloaded )
4238  {
4239  if ( child->m_partContainerElement && child->m_part )
4240  child->m_partContainerElement.data()->setWidget( child->m_part.data()->widget() );
4241 
4242  child->m_bPreloaded = false;
4243  return true;
4244  }
4245 
4246  //kDebug(6031) << "child=" << child << "child->m_part=" << child->m_part;
4247 
4248  KParts::OpenUrlArguments args( _args );
4249 
4250  if ( child->m_run ) {
4251  kDebug(6031) << "navigating ChildFrame while mimetype resolution was in progress...";
4252  child->m_run.data()->abort();
4253  }
4254 
4255  // ### Dubious -- the whole dir/ vs. img thing
4256  if ( child->m_part && !args.reload() && child->m_part.data()->url().equals( url,
4257  KUrl::CompareWithoutTrailingSlash | KUrl::CompareWithoutFragment | KUrl::AllowEmptyPath ) )
4258  args.setMimeType(child->m_serviceType);
4259 
4260  child->m_browserArgs = browserArgs;
4261  child->m_args = args;
4262 
4263  // reload/soft-reload arguments are always inherited from parent
4264  child->m_args.setReload( arguments().reload() );
4265  child->m_browserArgs.softReload = d->m_extension->browserArguments().softReload;
4266 
4267  child->m_serviceName.clear();
4268  if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
4269  child->m_args.metaData()["referrer"] = d->m_referrer;
4270 
4271  child->m_args.metaData().insert("PropagateHttpHeader", "true");
4272  child->m_args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
4273  child->m_args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
4274  child->m_args.metaData().insert("main_frame_request",
4275  parentPart() == 0 ? "TRUE":"FALSE");
4276  child->m_args.metaData().insert("ssl_was_in_use",
4277  d->m_ssl_in_use ? "TRUE":"FALSE");
4278  child->m_args.metaData().insert("ssl_activate_warnings", "TRUE");
4279  child->m_args.metaData().insert("cross-domain", toplevelURL().url());
4280 
4281  // We know the frame will be text/html if the HTML says <frame src=""> or <frame src="about:blank">,
4282  // no need to KHTMLRun to figure out the mimetype"
4283  // ### What if we're inside an XML document?
4284  if ((url.isEmpty() || url.url() == "about:blank" || url.protocol() == "javascript") && args.mimeType().isEmpty())
4285  args.setMimeType(QLatin1String("text/html"));
4286 
4287  if ( args.mimeType().isEmpty() ) {
4288  kDebug(6031) << "Running new KHTMLRun for" << this << "and child=" << child;
4289  child->m_run = new KHTMLRun( this, child, url, child->m_args, child->m_browserArgs, true );
4290  d->m_bComplete = false; // ensures we stop it in checkCompleted...
4291  return false;
4292  } else {
4293  return processObjectRequest( child, url, args.mimeType() );
4294  }
4295 }
4296 
4297 void KHTMLPart::childLoadFailure( khtml::ChildFrame *child )
4298 {
4299  child->m_bCompleted = true;
4300  if ( child->m_partContainerElement )
4301  child->m_partContainerElement.data()->partLoadingErrorNotify();
4302 
4303  checkCompleted();
4304 }
4305 
4306 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KUrl &_url, const QString &mimetype )
4307 {
4308  kDebug( 6031 ) << "trying to create part for" << mimetype << _url;
4309 
4310  // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
4311  // by an emitting frame part (emit openUrlRequest( blahurl, ... ) . A few lines below we delete the part
4312  // though -> the reference becomes invalid -> crash is likely
4313  KUrl url( _url );
4314 
4315  // khtmlrun called us with empty url + mimetype to indicate a loading error,
4316  // we obviosuly failed; but we can return true here since we don't want it
4317  // doing anything more, while childLoadFailure is enough to notify our kid.
4318  if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) ) {
4319  childLoadFailure(child);
4320  return true;
4321  }
4322 
4323  // we also want to ignore any spurious requests due to closing when parser is being cleared. These should be
4324  // ignored entirely --- the tail end of ::clear will clean things up.
4325  if (d->m_bClearing)
4326  return false;
4327 
4328  if (child->m_bNotify) {
4329  child->m_bNotify = false;
4330  if ( !child->m_browserArgs.lockHistory() )
4331  emit d->m_extension->openUrlNotify();
4332  }
4333 
4334  // Now, depending on mimetype and current state of the world, we may have
4335  // to create a new part or ask the user to save things, etc.
4336  //
4337  // We need a new part if there isn't one at all (doh) or the one that's there
4338  // is not for the mimetype we're loading.
4339  //
4340  // For these new types, we may have to ask the user to save it or not
4341  // (we don't if it's navigating the same type).
4342  // Further, we will want to ask if content-disposition suggests we ask for
4343  // saving, even if we're re-navigating.
4344  if ( !child->m_part || child->m_serviceType != mimetype ||
4345  (child->m_run && child->m_run.data()->serverSuggestsSave())) {
4346  // We often get here if we didn't know the mimetype in advance, and had to rely
4347  // on KRun to figure it out. In this case, we let the element check if it wants to
4348  // handle this mimetype itself, for e.g. objects containing images.
4349  if ( child->m_partContainerElement &&
4350  child->m_partContainerElement.data()->mimetypeHandledInternally(mimetype) ) {
4351  child->m_bCompleted = true;
4352  checkCompleted();
4353  return true;
4354  }
4355 
4356  // Before attempting to load a part, check if the user wants that.
4357  // Many don't like getting ZIP files embedded.
4358  // However we don't want to ask for flash and other plugin things.
4359  //
4360  // Note: this is fine for frames, since we will merely effectively ignore
4361  // the navigation if this happens
4362  if ( child->m_type != khtml::ChildFrame::Object && child->m_type != khtml::ChildFrame::IFrame ) {
4363  QString suggestedFileName;
4364  int disposition = 0;
4365  if ( KHTMLRun* run = child->m_run.data() ) {
4366  suggestedFileName = run->suggestedFileName();
4367  disposition = run->serverSuggestsSave() ?
4368  KParts::BrowserRun::AttachmentDisposition :
4369  KParts::BrowserRun::InlineDisposition;
4370  }
4371 
4372  KParts::BrowserOpenOrSaveQuestion dlg( widget(), url, mimetype );
4373  dlg.setSuggestedFileName( suggestedFileName );
4374  const KParts::BrowserOpenOrSaveQuestion::Result res = dlg.askEmbedOrSave( disposition );
4375 
4376  switch( res ) {
4377  case KParts::BrowserOpenOrSaveQuestion::Save:
4378  KHTMLPopupGUIClient::saveURL( widget(), i18n( "Save As" ), url, child->m_args.metaData(), QString(), 0, suggestedFileName );
4379  // fall-through
4380  case KParts::BrowserOpenOrSaveQuestion::Cancel:
4381  child->m_bCompleted = true;
4382  checkCompleted();
4383  return true; // done
4384  default: // Embed
4385  break;
4386  }
4387  }
4388 
4389  // Now, for frames and iframes, we always create a KHTMLPart anyway,
4390  // doing it in advance when registering the frame. So we want the
4391  // actual creation only for objects here.
4392  if ( child->m_type == khtml::ChildFrame::Object ) {
4393  KMimeType::Ptr mime = KMimeType::mimeType(mimetype);
4394  if (mime) {
4395  // Even for objects, however, we want to force a KHTMLPart for
4396  // html & xml, even if the normally preferred part is another one,
4397  // so that we can script the target natively via contentDocument method.
4398  if (mime->is("text/html")
4399  || mime->is("application/xml")) { // this includes xhtml and svg
4400  child->m_serviceName = "khtml";
4401  }
4402  }
4403 
4404  QStringList dummy; // the list of servicetypes handled by the part is now unused.
4405  KParts::ReadOnlyPart *part = createPart( d->m_view->viewport(), this, mimetype, child->m_serviceName, dummy, child->m_params );
4406 
4407  if ( !part ) {
4408  childLoadFailure(child);
4409  return false;
4410  }
4411 
4412  connectToChildPart( child, part, mimetype );
4413  }
4414  }
4415 
4416  checkEmitLoadEvent();
4417 
4418  // Some JS code in the load event may have destroyed the part
4419  // In that case, abort
4420  if ( !child->m_part )
4421  return false;
4422 
4423  if ( child->m_bPreloaded ) {
4424  if ( child->m_partContainerElement && child->m_part )
4425  child->m_partContainerElement.data()->setWidget( child->m_part.data()->widget() );
4426 
4427  child->m_bPreloaded = false;
4428  return true;
4429  }
4430 
4431  // reload/soft-reload arguments are always inherited from parent
4432  child->m_args.setReload( arguments().reload() );
4433  child->m_browserArgs.softReload = d->m_extension->browserArguments().softReload;
4434 
4435  // make sure the part has a way to find out about the mimetype.
4436  // we actually set it in child->m_args in requestObject already,
4437  // but it's useless if we had to use a KHTMLRun instance, as the
4438  // point the run object is to find out exactly the mimetype.
4439  child->m_args.setMimeType(mimetype);
4440  child->m_part.data()->setArguments( child->m_args );
4441 
4442  // if not a frame set child as completed
4443  // ### dubious.
4444  child->m_bCompleted = child->m_type == khtml::ChildFrame::Object;
4445 
4446  if ( child->m_extension )
4447  child->m_extension.data()->setBrowserArguments( child->m_browserArgs );
4448 
4449  return navigateChild( child, url );
4450 }
4451 
4452 bool KHTMLPart::navigateLocalProtocol( khtml::ChildFrame* /*child*/, KParts::ReadOnlyPart *inPart,
4453  const KUrl& url )
4454 {
4455  if (!qobject_cast<KHTMLPart*>(inPart))
4456  return false;
4457 
4458  KHTMLPart* p = static_cast<KHTMLPart*>(static_cast<KParts::ReadOnlyPart *>(inPart));
4459 
4460  p->begin();
4461 
4462  // We may have to re-propagate the domain here if we go here due to navigation
4463  d->propagateInitialDomainAndBaseTo(p);
4464 
4465  // Support for javascript: sources
4466  if (d->isJavaScriptURL(url.url())) {
4467  // See if we want to replace content with javascript: output..
4468  QVariant res = p->executeScript( DOM::Node(),
4469  d->codeForJavaScriptURL(url.url()));
4470  if (res.type() == QVariant::String && p->d->m_redirectURL.isEmpty()) {
4471  p->begin();
4472  p->setAlwaysHonourDoctype(); // Disable public API compat; it messes with doctype
4473  // We recreated the document, so propagate domain again.
4474  d->propagateInitialDomainAndBaseTo(p);
4475  p->write( res.toString() );
4476  p->end();
4477  }
4478  } else {
4479  p->setUrl(url);
4480  // we need a body element. testcase: <iframe id="a"></iframe><script>alert(a.document.body);</script>
4481  p->write("<HTML><TITLE></TITLE><BODY></BODY></HTML>");
4482  }
4483  p->end();
4484  // we don't need to worry about child completion explicitly for KHTMLPart...
4485  // or do we?
4486  return true;
4487 }
4488 
4489 bool KHTMLPart::navigateChild( khtml::ChildFrame *child, const KUrl& url )
4490 {
4491  if (url.protocol() == "javascript" || url.url() == "about:blank") {
4492  return navigateLocalProtocol(child, child->m_part.data(), url);
4493  } else if ( !url.isEmpty() ) {
4494  kDebug( 6031 ) << "opening" << url << "in frame" << child->m_part;
4495  bool b = child->m_part.data()->openUrl( url );
4496  if (child->m_bCompleted)
4497  checkCompleted();
4498  return b;
4499  } else {
4500  // empty URL -> no need to navigate
4501  child->m_bCompleted = true;
4502  checkCompleted();
4503  return true;
4504  }
4505 }
4506 
4507 void KHTMLPart::connectToChildPart( khtml::ChildFrame *child, KParts::ReadOnlyPart *part,
4508  const QString& mimetype)
4509 {
4510  kDebug(6031) << "we:" << this << "kid:" << child << part << mimetype;
4511 
4512  part->setObjectName( child->m_name );
4513 
4514  // Cleanup any previous part for this childframe and its connections
4515  if ( KParts::ReadOnlyPart* p = child->m_part.data() ) {
4516  if (!qobject_cast<KHTMLPart*>(p) && child->m_jscript)
4517  child->m_jscript->clear();
4518  partManager()->removePart( p );
4519  delete p;
4520  child->m_scriptable.clear();
4521  }
4522 
4523  child->m_part = part;
4524 
4525  child->m_serviceType = mimetype;
4526  if ( child->m_partContainerElement && part->widget() )
4527  child->m_partContainerElement.data()->setWidget( part->widget() );
4528 
4529  if ( child->m_type != khtml::ChildFrame::Object )
4530  partManager()->addPart( part, false );
4531 // else
4532 // kDebug(6031) << "AH! NO FRAME!!!!!";
4533 
4534  if (qobject_cast<KHTMLPart*>(part)) {
4535  static_cast<KHTMLPart*>(part)->d->m_frame = child;
4536  } else if (child->m_partContainerElement) {
4537  // See if this can be scripted..
4538  KParts::ScriptableExtension* scriptExt = KParts::ScriptableExtension::childObject(part);
4539  if (!scriptExt) {
4540  // Try to fall back to LiveConnectExtension compat
4541  KParts::LiveConnectExtension* lc = KParts::LiveConnectExtension::childObject(part);
4542  if (lc)
4543  scriptExt = KParts::ScriptableExtension::adapterFromLiveConnect(part, lc);
4544  }
4545 
4546  if (scriptExt)
4547  scriptExt->setHost(d->m_scriptableExtension);
4548  child->m_scriptable = scriptExt;
4549  }
4550  KParts::StatusBarExtension *sb = KParts::StatusBarExtension::childObject(part);
4551  if (sb)
4552  sb->setStatusBar( d->m_statusBarExtension->statusBar() );
4553 
4554  connect( part, SIGNAL(started(KIO::Job*)),
4555  this, SLOT(slotChildStarted(KIO::Job*)) );
4556  connect( part, SIGNAL(completed()),
4557  this, SLOT(slotChildCompleted()) );
4558  connect( part, SIGNAL(completed(bool)),
4559  this, SLOT(slotChildCompleted(bool)) );
4560  connect( part, SIGNAL(setStatusBarText(QString)),
4561  this, SIGNAL(setStatusBarText(QString)) );
4562  if ( part->inherits( "KHTMLPart" ) )
4563  {
4564  connect( this, SIGNAL(completed()),
4565  part, SLOT(slotParentCompleted()) );
4566  connect( this, SIGNAL(completed(bool)),
4567  part, SLOT(slotParentCompleted()) );
4568  // As soon as the child's document is created, we need to set its domain
4569  // (but we do so only once, so it can't be simply done in the child)
4570  connect( part, SIGNAL(docCreated()),
4571  this, SLOT(slotChildDocCreated()) );
4572  }
4573 
4574  child->m_extension = KParts::BrowserExtension::childObject( part );
4575 
4576  if ( KParts::BrowserExtension* kidBrowserExt = child->m_extension.data() )
4577  {
4578  connect( kidBrowserExt, SIGNAL(openUrlNotify()),
4579  d->m_extension, SIGNAL(openUrlNotify()) );
4580 
4581  connect( kidBrowserExt, SIGNAL(openUrlRequestDelayed(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)),
4582  this, SLOT(slotChildURLRequest(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)) );
4583 
4584  connect( kidBrowserExt, SIGNAL(createNewWindow(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**)),
4585  d->m_extension, SIGNAL(createNewWindow(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**)) );
4586 
4587  connect( kidBrowserExt, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)),
4588  d->m_extension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) );
4589  connect( kidBrowserExt, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)),
4590  d->m_extension, SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)) );
4591 
4592  connect( kidBrowserExt, SIGNAL(infoMessage(QString)),
4593  d->m_extension, SIGNAL(infoMessage(QString)) );
4594 
4595  connect( kidBrowserExt, SIGNAL(requestFocus(KParts::ReadOnlyPart*)),
4596  this, SLOT(slotRequestFocus(KParts::ReadOnlyPart*)) );
4597 
4598  kidBrowserExt->setBrowserInterface( d->m_extension->browserInterface() );
4599  }
4600 }
4601 
4602 KParts::ReadOnlyPart *KHTMLPart::createPart( QWidget *parentWidget,
4603  QObject *parent, const QString &mimetype,
4604  QString &serviceName, QStringList &serviceTypes,
4605  const QStringList &params )
4606 {
4607  QString constr;
4608  if ( !serviceName.isEmpty() )
4609  constr.append( QString::fromLatin1( "DesktopEntryName == '%1'" ).arg( serviceName ) );
4610 
4611  KService::List offers = KMimeTypeTrader::self()->query( mimetype, "KParts/ReadOnlyPart", constr );
4612 
4613  if ( offers.isEmpty() ) {
4614  int pos = mimetype.indexOf( "-plugin" );
4615  if (pos < 0)
4616  return 0L;
4617  QString stripped_mime = mimetype.left( pos );
4618  offers = KMimeTypeTrader::self()->query( stripped_mime, "KParts/ReadOnlyPart", constr );
4619  if ( offers.isEmpty() )
4620  return 0L;
4621  }
4622 
4623  KService::List::ConstIterator it = offers.constBegin();
4624  const KService::List::ConstIterator itEnd = offers.constEnd();
4625  for ( ; it != itEnd; ++it )
4626  {
4627  KService::Ptr service = (*it);
4628 
4629  KPluginLoader loader( *service, KHTMLGlobal::componentData() );
4630  KPluginFactory* const factory = loader.factory();
4631  if ( factory ) {
4632  // Turn params into a QVariantList as expected by KPluginFactory
4633  QVariantList variantlist;
4634  Q_FOREACH(const QString& str, params)
4635  variantlist << QVariant(str);
4636 
4637  if ( service->serviceTypes().contains( "Browser/View" ) )
4638  variantlist << QString("Browser/View");
4639 
4640  KParts::ReadOnlyPart* part = factory->create<KParts::ReadOnlyPart>(parentWidget, parent, QString(), variantlist);
4641  if ( part ) {
4642  serviceTypes = service->serviceTypes();
4643  serviceName = service->name();
4644  return part;
4645  }
4646  } else {
4647  // TODO KMessageBox::error and i18n, like in KonqFactory::createView?
4648  kWarning() << QString("There was an error loading the module %1.\nThe diagnostics is:\n%2")
4649  .arg(service->name()).arg(loader.errorString());
4650  }
4651  }
4652  return 0;
4653 }
4654 
4655 KParts::PartManager *KHTMLPart::partManager()
4656 {
4657  if ( !d->m_manager && d->m_view )
4658  {
4659  d->m_manager = new KParts::PartManager( d->m_view->topLevelWidget(), this );
4660  d->m_manager->setObjectName( "khtml part manager" );
4661  d->m_manager->setAllowNestedParts( true );
4662  connect( d->m_manager, SIGNAL(activePartChanged(KParts::Part*)),
4663  this, SLOT(slotActiveFrameChanged(KParts::Part*)) );
4664  connect( d->m_manager, SIGNAL(partRemoved(KParts::Part*)),
4665  this, SLOT(slotPartRemoved(KParts::Part*)) );
4666  }
4667 
4668  return d->m_manager;
4669 }
4670 
4671 void KHTMLPart::submitFormAgain()
4672 {
4673  disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
4674  if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
4675  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 );
4676 
4677  delete d->m_submitForm;
4678  d->m_submitForm = 0;
4679 }
4680 
4681 void KHTMLPart::submitFormProxy( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
4682 {
4683  submitForm(action, url, formData, _target, contentType, boundary);
4684 }
4685 
4686 void KHTMLPart::submitForm( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
4687 {
4688  kDebug(6000) << this << "target=" << _target << "url=" << url;
4689  if (d->m_formNotification == KHTMLPart::Only) {
4690  emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
4691  return;
4692  } else if (d->m_formNotification == KHTMLPart::Before) {
4693  emit formSubmitNotification(action, url, formData, _target, contentType, boundary);
4694  }
4695 
4696  KUrl u = completeURL( url );
4697 
4698  if ( !u.isValid() )
4699  {
4700  // ### ERROR HANDLING!
4701  return;
4702  }
4703 
4704  // Form security checks
4705  //
4706  /*
4707  * If these form security checks are still in this place in a month or two
4708  * I'm going to simply delete them.
4709  */
4710 
4711  /* This is separate for a reason. It has to be _before_ all script, etc,
4712  * AND I don't want to break anything that uses checkLinkSecurity() in
4713  * other places.
4714  */
4715 
4716  if (!d->m_submitForm) {
4717  if (u.protocol() != "https" && u.protocol() != "mailto") {
4718  if (d->m_ssl_in_use) { // Going from SSL -> nonSSL
4719  int rc = KMessageBox::warningContinueCancel(NULL, i18n("Warning: This is a secure form but it is attempting to send your data back unencrypted."
4720  "\nA third party may be able to intercept and view this information."
4721  "\nAre you sure you wish to continue?"),
4722  i18n("Network Transmission"),KGuiItem(i18n("&Send Unencrypted")));
4723  if (rc == KMessageBox::Cancel)
4724  return;
4725  } else { // Going from nonSSL -> nonSSL
4726  KSSLSettings kss(true);
4727  if (kss.warnOnUnencrypted()) {
4728  int rc = KMessageBox::warningContinueCancel(NULL,
4729  i18n("Warning: Your data is about to be transmitted across the network unencrypted."
4730  "\nAre you sure you wish to continue?"),
4731  i18n("Network Transmission"),
4732  KGuiItem(i18n("&Send Unencrypted")),
4733  KStandardGuiItem::cancel(),
4734  "WarnOnUnencryptedForm");
4735  // Move this setting into KSSL instead
4736  QString grpNotifMsgs = QLatin1String("Notification Messages");
4737  KConfigGroup cg( KGlobal::config(), grpNotifMsgs );
4738 
4739  if (!cg.readEntry("WarnOnUnencryptedForm", true)) {
4740  cg.deleteEntry("WarnOnUnencryptedForm");
4741  cg.sync();
4742  kss.setWarnOnUnencrypted(false);
4743  kss.save();
4744  }
4745  if (rc == KMessageBox::Cancel)
4746  return;
4747  }
4748  }
4749  }
4750 
4751  if (u.protocol() == "mailto") {
4752  int rc = KMessageBox::warningContinueCancel(NULL,
4753  i18n("This site is attempting to submit form data via email.\n"
4754  "Do you want to continue?"),
4755  i18n("Network Transmission"),
4756  KGuiItem(i18n("&Send Email")),
4757  KStandardGuiItem::cancel(),
4758  "WarnTriedEmailSubmit");
4759 
4760  if (rc == KMessageBox::Cancel) {
4761  return;
4762  }
4763  }
4764  }
4765 
4766  // End form security checks
4767  //
4768 
4769  QString urlstring = u.url();
4770 
4771  if ( d->isJavaScriptURL(urlstring) ) {
4772  crossFrameExecuteScript( _target, d->codeForJavaScriptURL(urlstring) );
4773  return;
4774  }
4775 
4776  if (!checkLinkSecurity(u,
4777  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>" ),
4778  i18n( "Submit" )))
4779  return;
4780 
4781  // OK. We're actually going to submit stuff. Clear any redirections,
4782  // we should win over them
4783  d->clearRedirection();
4784 
4785  KParts::OpenUrlArguments args;
4786 
4787  if (!d->m_referrer.isEmpty())
4788  args.metaData()["referrer"] = d->m_referrer;
4789 
4790  args.metaData().insert("PropagateHttpHeader", "true");
4791  args.metaData().insert("ssl_parent_ip", d->m_ssl_parent_ip);
4792  args.metaData().insert("ssl_parent_cert", d->m_ssl_parent_cert);
4793  args.metaData().insert("main_frame_request",
4794  parentPart() == 0 ? "TRUE":"FALSE");
4795  args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
4796  args.metaData().insert("ssl_activate_warnings", "TRUE");
4797 //WABA: When we post a form we should treat it as the main url
4798 //the request should never be considered cross-domain
4799 //args.metaData().insert("cross-domain", toplevelURL().url());
4800  KParts::BrowserArguments browserArgs;
4801  browserArgs.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
4802 
4803  // Handle mailto: forms
4804  if (u.protocol() == "mailto") {
4805  // 1) Check for attach= and strip it
4806  QString q = u.query().mid(1);
4807  QStringList nvps = q.split("&");
4808  bool triedToAttach = false;
4809 
4810  QStringList::Iterator nvp = nvps.begin();
4811  const QStringList::Iterator nvpEnd = nvps.end();
4812 
4813 // cannot be a for loop as if something is removed we don't want to do ++nvp, as
4814 // remove returns an iterator pointing to the next item
4815 
4816  while (nvp != nvpEnd) {
4817  const QStringList pair = (*nvp).split("=");
4818  if (pair.count() >= 2) {
4819  if (pair.first().toLower() == "attach") {
4820  nvp = nvps.erase(nvp);
4821  triedToAttach = true;
4822  } else {
4823  ++nvp;
4824  }
4825  } else {
4826  ++nvp;
4827  }
4828  }
4829 
4830  if (triedToAttach)
4831  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");
4832 
4833  // 2) Append body=
4834  QString bodyEnc;
4835  if (contentType.toLower() == "multipart/form-data") {
4836  // FIXME: is this correct? I suspect not
4837  bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(),
4838  formData.size())));
4839  } else if (contentType.toLower() == "text/plain") {
4840  // Convention seems to be to decode, and s/&/\n/
4841  QString tmpbody = QString::fromLatin1(formData.data(),
4842  formData.size());
4843  tmpbody.replace(QRegExp("[&]"), "\n");
4844  tmpbody.replace(QRegExp("[+]"), " ");
4845  tmpbody = KUrl::fromPercentEncoding(tmpbody.toLatin1()); // Decode the rest of it
4846  bodyEnc = QLatin1String( KUrl::toPercentEncoding(tmpbody) ); // Recode for the URL
4847  } else {
4848  bodyEnc = QLatin1String( KUrl::toPercentEncoding(QString::fromLatin1(formData.data(),
4849  formData.size())) );
4850  }
4851 
4852  nvps.append(QString("body=%1").arg(bodyEnc));
4853  q = nvps.join("&");
4854  u.setQuery(q);
4855  }
4856 
4857  if ( strcmp( action, "get" ) == 0 ) {
4858  if (u.protocol() != "mailto")
4859  u.setQuery( QString::fromLatin1( formData.data(), formData.size() ) );
4860  browserArgs.setDoPost( false );
4861  }
4862  else {
4863  browserArgs.postData = formData;
4864  browserArgs.setDoPost( true );
4865 
4866  // construct some user headers if necessary
4867  if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
4868  browserArgs.setContentType( "Content-Type: application/x-www-form-urlencoded" );
4869  else // contentType must be "multipart/form-data"
4870  browserArgs.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
4871  }
4872 
4873  if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
4874  if( d->m_submitForm ) {
4875  kDebug(6000) << "ABORTING!";
4876  return;
4877  }
4878  d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
4879  d->m_submitForm->submitAction = action;
4880  d->m_submitForm->submitUrl = url;
4881  d->m_submitForm->submitFormData = formData;
4882  d->m_submitForm->target = _target;
4883  d->m_submitForm->submitContentType = contentType;
4884  d->m_submitForm->submitBoundary = boundary;
4885  connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
4886  }
4887  else
4888  {
4889  emit d->m_extension->openUrlRequest( u, args, browserArgs );
4890  }
4891 }
4892 
4893 void KHTMLPart::popupMenu( const QString &linkUrl )
4894 {
4895  KUrl popupURL;
4896  KUrl linkKUrl;
4897  KParts::OpenUrlArguments args;
4898  KParts::BrowserArguments browserArgs;
4899  QString referrer;
4900  KParts::BrowserExtension::PopupFlags itemflags=KParts::BrowserExtension::ShowBookmark | KParts::BrowserExtension::ShowReload;
4901 
4902  if ( linkUrl.isEmpty() ) { // click on background
4903  KHTMLPart* khtmlPart = this;
4904  while ( khtmlPart->parentPart() )
4905  {
4906  khtmlPart=khtmlPart->parentPart();
4907  }
4908  popupURL = khtmlPart->url();
4909  referrer = khtmlPart->pageReferrer();
4910  if (hasSelection())
4911  itemflags = KParts::BrowserExtension::ShowTextSelectionItems;
4912  else
4913  itemflags |= KParts::BrowserExtension::ShowNavigationItems;
4914  } else { // click on link
4915  popupURL = completeURL( linkUrl );
4916  linkKUrl = popupURL;
4917  referrer = this->referrer();
4918  itemflags |= KParts::BrowserExtension::IsLink;
4919 
4920  if (!(d->m_strSelectedURLTarget).isEmpty() &&
4921  (d->m_strSelectedURLTarget.toLower() != "_top") &&
4922  (d->m_strSelectedURLTarget.toLower() != "_self") &&
4923  (d->m_strSelectedURLTarget.toLower() != "_parent")) {
4924  if (d->m_strSelectedURLTarget.toLower() == "_blank")
4925  browserArgs.setForcesNewWindow(true);
4926  else {
4927  KHTMLPart *p = this;
4928  while (p->parentPart())
4929  p = p->parentPart();
4930  if (!p->frameExists(d->m_strSelectedURLTarget))
4931  browserArgs.setForcesNewWindow(true);
4932  }
4933  }
4934  }
4935 
4936  // Danger, Will Robinson. The Popup might stay around for a much
4937  // longer time than KHTMLPart. Deal with it.
4938  KHTMLPopupGUIClient* client = new KHTMLPopupGUIClient( this, linkKUrl );
4939  QPointer<QObject> guard( client );
4940 
4941  QString mimetype = QLatin1String( "text/html" );
4942  args.metaData()["referrer"] = referrer;
4943 
4944  if (!linkUrl.isEmpty()) // over a link
4945  {
4946  if (popupURL.isLocalFile()) // safe to do this
4947  {
4948  mimetype = KMimeType::findByUrl(popupURL,0,true,false)->name();
4949  }
4950  else // look at "extension" of link
4951  {
4952  const QString fname(popupURL.fileName(KUrl::ObeyTrailingSlash));
4953  if (!fname.isEmpty() && !popupURL.hasRef() && popupURL.query().isEmpty())
4954  {
4955  KMimeType::Ptr pmt = KMimeType::findByPath(fname,0,true);
4956 
4957  // Further check for mime types guessed from the extension which,
4958  // on a web page, are more likely to be a script delivering content
4959  // of undecidable type. If the mime type from the extension is one
4960  // of these, don't use it. Retain the original type 'text/html'.
4961  if (pmt->name() != KMimeType::defaultMimeType() &&
4962  !pmt->is("application/x-perl") &&
4963  !pmt->is("application/x-perl-module") &&
4964  !pmt->is("application/x-php") &&
4965  !pmt->is("application/x-python-bytecode") &&
4966  !pmt->is("application/x-python") &&
4967  !pmt->is("application/x-shellscript"))
4968  mimetype = pmt->name();
4969  }
4970  }
4971  }
4972 
4973  args.setMimeType(mimetype);
4974 
4975  emit d->m_extension->popupMenu( QCursor::pos(), popupURL, S_IFREG /*always a file*/,
4976  args, browserArgs, itemflags,
4977  client->actionGroups() );
4978 
4979  if ( !guard.isNull() ) {
4980  delete client;
4981  emit popupMenu(linkUrl, QCursor::pos());
4982  d->m_strSelectedURL.clear();
4983  d->m_strSelectedURLTarget.clear();
4984  }
4985 }
4986 
4987 void KHTMLPart::slotParentCompleted()
4988 {
4989  //kDebug(6050) << this;
4990  if ( !d->m_redirectURL.isEmpty() && !d->m_redirectionTimer.isActive() )
4991  {
4992  //kDebug(6050) << this << ": starting timer for child redirection -> " << d->m_redirectURL;
4993  d->m_redirectionTimer.setSingleShot( true );
4994  d->m_redirectionTimer.start( qMax(0, 1000 * d->m_delayRedirect) );
4995  }
4996 }
4997 
4998 void KHTMLPart::slotChildStarted( KIO::Job *job )
4999 {
5000  khtml::ChildFrame *child = frame( sender() );
5001 
5002  assert( child );
5003 
5004  child->m_bCompleted = false;
5005 
5006  if ( d->m_bComplete )
5007  {
5008 #if 0
5009  // WABA: Looks like this belongs somewhere else
5010  if ( !parentPart() ) // "toplevel" html document? if yes, then notify the hosting browser about the document (url) changes
5011  {
5012  emit d->m_extension->openURLNotify();
5013  }
5014 #endif
5015  d->m_bComplete = false;
5016  emit started( job );
5017  }
5018 }
5019 
5020 void KHTMLPart::slotChildCompleted()
5021 {
5022  slotChildCompleted( false );
5023 }
5024 
5025 void KHTMLPart::slotChildCompleted( bool pendingAction )
5026 {
5027  khtml::ChildFrame *child = frame( sender() );
5028 
5029  if ( child ) {
5030  kDebug(6031) << this << "child=" << child << "m_partContainerElement=" << child->m_partContainerElement;
5031  child->m_bCompleted = true;
5032  child->m_bPendingRedirection = pendingAction;
5033  child->m_args = KParts::OpenUrlArguments();
5034  child->m_browserArgs = KParts::BrowserArguments();
5035  // dispatch load event. We don't do that for KHTMLPart's since their internal
5036  // load will be forwarded inside NodeImpl::dispatchWindowEvent
5037  if (!qobject_cast<KHTMLPart*>(child->m_part))
5038  QTimer::singleShot(0, child->m_partContainerElement.data(), SLOT(slotEmitLoadEvent()));
5039  }
5040  checkCompleted();
5041 }
5042 
5043 void KHTMLPart::slotChildDocCreated()
5044 {
5045  // Set domain to the frameset's domain
5046  // This must only be done when loading the frameset initially (#22039),
5047  // not when following a link in a frame (#44162).
5048  if (KHTMLPart* htmlFrame = qobject_cast<KHTMLPart*>(sender()))
5049  d->propagateInitialDomainAndBaseTo(htmlFrame);
5050 
5051  // So it only happens once
5052  disconnect( sender(), SIGNAL(docCreated()), this, SLOT(slotChildDocCreated()) );
5053 }
5054 
5055 void KHTMLPartPrivate::propagateInitialDomainAndBaseTo(KHTMLPart* kid)
5056 {
5057  // This method is used to propagate our domain and base information for
5058  // child frames, to provide them for about: or JavaScript: URLs
5059  if ( m_doc && kid->d->m_doc ) {
5060  DocumentImpl* kidDoc = kid->d->m_doc;
5061  if ( kidDoc->origin()->isEmpty() ) {
5062  kidDoc->setOrigin ( m_doc->origin() );
5063  kidDoc->setBaseURL( m_doc->baseURL() );
5064  }
5065  }
5066 }
5067 
5068 void KHTMLPart::slotChildURLRequest( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs )
5069 {
5070  khtml::ChildFrame *child = frame( sender()->parent() );
5071  KHTMLPart *callingHtmlPart = const_cast<KHTMLPart *>(dynamic_cast<const KHTMLPart *>(sender()->parent()));
5072 
5073  // TODO: handle child target correctly! currently the script are always executed for the parent
5074  QString urlStr = url.url();
5075  if ( d->isJavaScriptURL(urlStr) ) {
5076  executeScript( DOM::Node(), d->codeForJavaScriptURL(urlStr) );
5077  return;
5078  }
5079 
5080  QString frameName = browserArgs.frameName.toLower();
5081  if ( !frameName.isEmpty() ) {
5082  if ( frameName == QLatin1String( "_top" ) )
5083  {
5084  emit d->m_extension->openUrlRequest( url, args, browserArgs );
5085  return;
5086  }
5087  else if ( frameName == QLatin1String( "_blank" ) )
5088  {
5089  emit d->m_extension->createNewWindow( url, args, browserArgs );
5090  return;
5091  }
5092  else if ( frameName == QLatin1String( "_parent" ) )
5093  {
5094  KParts::BrowserArguments newBrowserArgs( browserArgs );
5095  newBrowserArgs.frameName.clear();
5096  emit d->m_extension->openUrlRequest( url, args, newBrowserArgs );
5097  return;
5098  }
5099  else if ( frameName != QLatin1String( "_self" ) )
5100  {
5101  khtml::ChildFrame *_frame = recursiveFrameRequest( callingHtmlPart, url, args, browserArgs );
5102 
5103  if ( !_frame )
5104  {
5105  emit d->m_extension->openUrlRequest( url, args, browserArgs );
5106  return;
5107  }
5108 
5109  child = _frame;
5110  }
5111  }
5112 
5113  if ( child && child->m_type != khtml::ChildFrame::Object ) {
5114  // Inform someone that we are about to show something else.
5115  child->m_bNotify = true;
5116  requestObject( child, url, args, browserArgs );
5117  } else if ( frameName== "_self" ) // this is for embedded objects (via <object>) which want to replace the current document
5118  {
5119  KParts::BrowserArguments newBrowserArgs( browserArgs );
5120  newBrowserArgs.frameName.clear();
5121  emit d->m_extension->openUrlRequest( url, args, newBrowserArgs );
5122  }
5123 }
5124 
5125 void KHTMLPart::slotRequestFocus( KParts::ReadOnlyPart * )
5126 {
5127  emit d->m_extension->requestFocus(this);
5128 }
5129 
5130 khtml::ChildFrame *KHTMLPart::frame( const QObject *obj )
5131 {
5132  assert( obj->inherits( "KParts::ReadOnlyPart" ) );
5133  const KParts::ReadOnlyPart* const part = static_cast<const KParts::ReadOnlyPart *>( obj );
5134 
5135  FrameIt it = d->m_frames.begin();
5136  const FrameIt end = d->m_frames.end();
5137  for (; it != end; ++it ) {
5138  if ((*it)->m_part.data() == part )
5139  return *it;
5140  }
5141 
5142  FrameIt oi = d->m_objects.begin();
5143  const FrameIt oiEnd = d->m_objects.end();
5144  for (; oi != oiEnd; ++oi ) {
5145  if ((*oi)->m_part.data() == part)
5146  return *oi;
5147  }
5148 
5149  return 0L;
5150 }
5151 
5152 //#define DEBUG_FINDFRAME
5153 
5154 bool KHTMLPart::checkFrameAccess(KHTMLPart *callingHtmlPart)
5155 {
5156  if (callingHtmlPart == this)
5157  return true; // trivial
5158 
5159  if (!xmlDocImpl()) {
5160 #ifdef DEBUG_FINDFRAME
5161  kDebug(6050) << "Empty part" << this << "URL = " << url();
5162 #endif
5163  return false; // we are empty?
5164  }
5165 
5166  // now compare the domains
5167  if (callingHtmlPart && callingHtmlPart->xmlDocImpl() && xmlDocImpl()) {
5168  khtml::SecurityOrigin* actDomain = callingHtmlPart->xmlDocImpl()->origin();
5169  khtml::SecurityOrigin* destDomain = xmlDocImpl()->origin();
5170 
5171  if (actDomain->canAccess(destDomain))
5172  return true;
5173  }
5174 #ifdef DEBUG_FINDFRAME
5175  else
5176  {
5177  kDebug(6050) << "Unknown part/domain" << callingHtmlPart << "tries to access part" << this;
5178  }
5179 #endif
5180  return false;
5181 }
5182 
5183 KHTMLPart *
5184 KHTMLPart::findFrameParent( KParts::ReadOnlyPart *callingPart, const QString &f, khtml::ChildFrame **childFrame )
5185 {
5186  return d->findFrameParent(callingPart, f, childFrame, false);
5187 }
5188 
5189 KHTMLPart* KHTMLPartPrivate::findFrameParent(KParts::ReadOnlyPart* callingPart,
5190  const QString& f, khtml::ChildFrame **childFrame, bool checkForNavigation)
5191 {
5192 #ifdef DEBUG_FINDFRAME
5193  kDebug(6050) << q << "URL =" << q->url() << "name =" << q->objectName() << "findFrameParent(" << f << ")";
5194 #endif
5195  // Check access
5196  KHTMLPart* const callingHtmlPart = qobject_cast<KHTMLPart *>(callingPart);
5197 
5198  if (!callingHtmlPart)
5199  return 0;
5200 
5201  if (!checkForNavigation && !q->checkFrameAccess(callingHtmlPart))
5202  return 0;
5203 
5204  if (!childFrame && !q->parentPart() && (q->objectName() == f)) {
5205  if (!checkForNavigation || callingHtmlPart->d->canNavigate(q))
5206  return q;
5207  }
5208 
5209  FrameIt it = m_frames.find( f );
5210  const FrameIt end = m_frames.end();
5211  if ( it != end )
5212  {
5213 #ifdef DEBUG_FINDFRAME
5214  kDebug(6050) << "FOUND!";
5215 #endif
5216  if (!checkForNavigation || callingHtmlPart->d->canNavigate((*it)->m_part.data())) {
5217  if (childFrame)
5218  *childFrame = *it;
5219  return q;
5220  }
5221  }
5222 
5223  it = m_frames.begin();
5224  for (; it != end; ++it )
5225  {
5226  if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
5227  {
5228  KHTMLPart* const frameParent = p->d->findFrameParent(callingPart, f, childFrame, checkForNavigation);
5229  if (frameParent)
5230  return frameParent;
5231  }
5232  }
5233  return 0;
5234 }
5235 
5236 KHTMLPart* KHTMLPartPrivate::top()
5237 {
5238  KHTMLPart* t = q;
5239  while (t->parentPart())
5240  t = t->parentPart();
5241  return t;
5242 }
5243 
5244 bool KHTMLPartPrivate::canNavigate(KParts::ReadOnlyPart* bCand)
5245 {
5246  if (!bCand) // No part here (e.g. invalid url), reuse that frame
5247  return true;
5248 
5249  KHTMLPart* b = qobject_cast<KHTMLPart*>(bCand);
5250  if (!b) // Another kind of part? Not sure what to do...
5251  return false;
5252 
5253  // HTML5 gives conditions for this (a) being able to navigate b
5254 
5255  // 1) Same domain
5256  if (q->checkFrameAccess(b))
5257  return true;
5258 
5259  // 2) A is nested, with B its top
5260  if (q->parentPart() && top() == b)
5261  return true;
5262 
5263  // 3) B is 'auxilary' -- window.open with opener,
5264  // and A can navigate B's opener
5265  if (b->opener() && canNavigate(b->opener()))
5266  return true;
5267 
5268  // 4) B is not top-level, but an ancestor of it has same origin as A
5269  for (KHTMLPart* anc = b->parentPart(); anc; anc = anc->parentPart()) {
5270  if (anc->checkFrameAccess(q))
5271  return true;
5272  }
5273 
5274  return false;
5275 }
5276 
5277 KHTMLPart *KHTMLPart::findFrame( const QString &f )
5278 {
5279  khtml::ChildFrame *childFrame;
5280  KHTMLPart *parentFrame = findFrameParent(this, f, &childFrame);
5281  if (parentFrame)
5282  return qobject_cast<KHTMLPart*>(childFrame->m_part.data());
5283 
5284  return 0;
5285 }
5286 
5287 KParts::ReadOnlyPart *KHTMLPart::findFramePart(const QString &f)
5288 {
5289  khtml::ChildFrame *childFrame;
5290  return findFrameParent(this, f, &childFrame) ? childFrame->m_part.data() : 0L;
5291 }
5292 
5293 KParts::ReadOnlyPart *KHTMLPart::currentFrame() const
5294 {
5295  KParts::ReadOnlyPart* part = (KParts::ReadOnlyPart*)(this);
5296  // Find active part in our frame manager, in case we are a frameset
5297  // and keep doing that (in case of nested framesets).
5298  // Just realized we could also do this recursively, calling part->currentFrame()...
5299  while ( part && part->inherits("KHTMLPart") &&
5300  static_cast<KHTMLPart *>(part)->d->m_frames.count() > 0 ) {
5301  KHTMLPart* frameset = static_cast<KHTMLPart *>(part);
5302  part = static_cast<KParts::ReadOnlyPart *>(frameset->partManager()->activePart());
5303  if ( !part ) return frameset;
5304  }
5305  return part;
5306 }
5307 
5308 bool KHTMLPart::frameExists( const QString &frameName )
5309 {
5310  FrameIt it = d->m_frames.find( frameName );
5311  if ( it == d->m_frames.end() )
5312  return false;
5313 
5314  // WABA: We only return true if the child actually has a frame
5315  // set. Otherwise we might find our preloaded-selve.
5316  // This happens when we restore the frameset.
5317  return (!(*it)->m_partContainerElement.isNull());
5318 }
5319 
5320 void KHTMLPartPrivate::renameFrameForContainer(DOM::HTMLPartContainerElementImpl* cont,
5321  const QString& newName)
5322 {
5323  for (int i = 0; i < m_frames.size(); ++i) {
5324  khtml::ChildFrame* f = m_frames[i];
5325  if (f->m_partContainerElement.data() == cont)
5326  f->m_name = newName;
5327  }
5328 }
5329 
5330 KJSProxy *KHTMLPart::framejScript(KParts::ReadOnlyPart *framePart)
5331 {
5332  KHTMLPart* const kp = qobject_cast<KHTMLPart*>(framePart);
5333  if (kp)
5334  return kp->jScript();
5335 
5336  FrameIt it = d->m_frames.begin();
5337  const FrameIt itEnd = d->m_frames.end();
5338 
5339  for (; it != itEnd; ++it) {
5340  khtml::ChildFrame* frame = *it;
5341  if (framePart == frame->m_part.data()) {
5342  if (!frame->m_jscript)
5343  frame->m_jscript = new KJSProxy(frame);
5344  return frame->m_jscript;
5345  }
5346  }
5347  return 0L;
5348 }
5349 
5350 KHTMLPart *KHTMLPart::parentPart()
5351 {
5352  return qobject_cast<KHTMLPart*>( parent() );
5353 }
5354 
5355 khtml::ChildFrame *KHTMLPart::recursiveFrameRequest( KHTMLPart *callingHtmlPart, const KUrl &url,
5356  const KParts::OpenUrlArguments &args,
5357  const KParts::BrowserArguments &browserArgs, bool callParent )
5358 {
5359 #ifdef DEBUG_FINDFRAME
5360  kDebug( 6050 ) << this << "frame = " << args.frameName << "url = " << url;
5361 #endif
5362  khtml::ChildFrame *childFrame;
5363  KHTMLPart *childPart = findFrameParent(callingHtmlPart, browserArgs.frameName, &childFrame);
5364  if (childPart)
5365  {
5366  if (childPart == this)
5367  return childFrame;
5368 
5369  childPart->requestObject( childFrame, url, args, browserArgs );
5370  return 0;
5371  }
5372 
5373  if ( parentPart() && callParent )
5374  {
5375  khtml::ChildFrame *res = parentPart()->recursiveFrameRequest( callingHtmlPart, url, args, browserArgs, callParent );
5376 
5377  if ( res )
5378  parentPart()->requestObject( res, url, args, browserArgs );
5379  }
5380 
5381  return 0L;
5382 }
5383 
5384 #ifdef DEBUG_SAVESTATE
5385 static int s_saveStateIndentLevel = 0;
5386 #endif
5387 
5388 void KHTMLPart::saveState( QDataStream &stream )
5389 {
5390 #ifdef DEBUG_SAVESTATE
5391  QString indent= QString().leftJustified( s_saveStateIndentLevel * 4, ' ' );
5392  const int indentLevel = s_saveStateIndentLevel++;
5393  kDebug( 6050 ) << indent << "saveState this=" << this << " '" << objectName() << "' saving URL " << url().url();
5394 #endif
5395 
5396  stream << url() << (qint32)d->m_view->contentsX() << (qint32)d->m_view->contentsY()
5397  << (qint32) d->m_view->contentsWidth() << (qint32) d->m_view->contentsHeight() << (qint32) d->m_view->marginWidth() << (qint32) d->m_view->marginHeight();
5398 
5399  // save link cursor position
5400  int focusNodeNumber;
5401  if (!d->m_focusNodeRestored)
5402  focusNodeNumber = d->m_focusNodeNumber;
5403  else if (d->m_doc && d->m_doc->focusNode())
5404  focusNodeNumber = d->m_doc->nodeAbsIndex(d->m_doc->focusNode());
5405  else
5406  focusNodeNumber = -1;
5407  stream << focusNodeNumber;
5408 
5409  // Save the doc's cache id.
5410  stream << d->m_cacheId;
5411 
5412  // Save the state of the document (Most notably the state of any forms)
5413  QStringList docState;
5414  if (d->m_doc)
5415  {
5416  docState = d->m_doc->docState();
5417  }
5418  stream << d->m_encoding << d->m_sheetUsed << docState;
5419 
5420  stream << d->m_zoomFactor;
5421  stream << d->m_fontScaleFactor;
5422 
5423  stream << d->m_httpHeaders;
5424  stream << d->m_pageServices;
5425  stream << d->m_pageReferrer;
5426 
5427  // Save ssl data
5428  stream << d->m_ssl_in_use
5429  << d->m_ssl_peer_chain
5430  << d->m_ssl_peer_ip
5431  << d->m_ssl_cipher
5432  << d->m_ssl_protocol_version
5433  << d->m_ssl_cipher_used_bits
5434  << d->m_ssl_cipher_bits
5435  << d->m_ssl_cert_errors
5436  << d->m_ssl_parent_ip
5437  << d->m_ssl_parent_cert;
5438 
5439 
5440  QStringList frameNameLst, frameServiceTypeLst, frameServiceNameLst;
5441  KUrl::List frameURLLst;
5442  QList<QByteArray> frameStateBufferLst;
5443  QList<int> frameTypeLst;
5444 
5445  ConstFrameIt it = d->m_frames.constBegin();
5446  const ConstFrameIt end = d->m_frames.constEnd();
5447  for (; it != end; ++it )
5448  {
5449  if ( !(*it)->m_part )
5450  continue;
5451 
5452  frameNameLst << (*it)->m_name;
5453  frameServiceTypeLst << (*it)->m_serviceType;
5454  frameServiceNameLst << (*it)->m_serviceName;
5455  frameURLLst << (*it)->m_part.data()->url();
5456 
5457  QByteArray state;
5458  QDataStream frameStream( &state, QIODevice::WriteOnly );
5459 
5460  if ( (*it)->m_extension )
5461  (*it)->m_extension.data()->saveState( frameStream );
5462 
5463  frameStateBufferLst << state;
5464 
5465  frameTypeLst << int( (*it)->m_type );
5466  }
5467 
5468  // Save frame data
5469  stream << (quint32) frameNameLst.count();
5470  stream << frameNameLst << frameServiceTypeLst << frameServiceNameLst << frameURLLst << frameStateBufferLst << frameTypeLst;
5471 #ifdef DEBUG_SAVESTATE
5472  s_saveStateIndentLevel = indentLevel;
5473 #endif
5474 }
5475 
5476 void KHTMLPart::restoreState( QDataStream &stream )
5477 {
5478  KUrl u;
5479  qint32 xOffset, yOffset, wContents, hContents, mWidth, mHeight;
5480  quint32 frameCount;
5481  QStringList frameNames, frameServiceTypes, docState, frameServiceNames;
5482  QList<int> frameTypes;
5483  KUrl::List frameURLs;
5484  QList<QByteArray> frameStateBuffers;
5485  QList<int> fSizes;
5486  QString encoding, sheetUsed;
5487  long old_cacheId = d->m_cacheId;
5488 
5489  stream >> u >> xOffset >> yOffset >> wContents >> hContents >> mWidth >> mHeight;
5490 
5491  d->m_view->setMarginWidth( mWidth );
5492  d->m_view->setMarginHeight( mHeight );
5493 
5494  // restore link cursor position
5495  // nth node is active. value is set in checkCompleted()
5496  stream >> d->m_focusNodeNumber;
5497  d->m_focusNodeRestored = false;
5498 
5499  stream >> d->m_cacheId;
5500 
5501  stream >> encoding >> sheetUsed >> docState;
5502 
5503  d->m_encoding = encoding;
5504  d->m_sheetUsed = sheetUsed;
5505 
5506  int zoomFactor;
5507  stream >> zoomFactor;
5508  setZoomFactor(zoomFactor);
5509 
5510  int fontScaleFactor;
5511  stream >> fontScaleFactor;
5512  setFontScaleFactor(fontScaleFactor);
5513 
5514  stream >> d->m_httpHeaders;
5515  stream >> d->m_pageServices;
5516  stream >> d->m_pageReferrer;
5517 
5518  // Restore ssl data
5519  stream >> d->m_ssl_in_use
5520  >> d->m_ssl_peer_chain
5521  >> d->m_ssl_peer_ip
5522  >> d->m_ssl_cipher
5523  >> d->m_ssl_protocol_version
5524  >> d->m_ssl_cipher_used_bits
5525  >> d->m_ssl_cipher_bits
5526  >> d->m_ssl_cert_errors
5527  >> d->m_ssl_parent_ip
5528  >> d->m_ssl_parent_cert;
5529 
5530  setPageSecurity( d->m_ssl_in_use ? Encrypted : NotCrypted );
5531 
5532  stream >> frameCount >> frameNames >> frameServiceTypes >> frameServiceNames
5533  >> frameURLs >> frameStateBuffers >> frameTypes;
5534 
5535  d->m_bComplete = false;
5536  d->m_bLoadEventEmitted = false;
5537 
5538 // kDebug( 6050 ) << "docState.count() = " << docState.count();
5539 // kDebug( 6050 ) << "m_url " << url().url() << " <-> " << u.url();
5540 // kDebug( 6050 ) << "m_frames.count() " << d->m_frames.count() << " <-> " << frameCount;
5541 
5542  if (d->m_cacheId == old_cacheId && signed(frameCount) == d->m_frames.count())
5543  {
5544  // Partial restore
5545  d->m_redirectionTimer.stop();
5546 
5547  FrameIt fIt = d->m_frames.begin();
5548  const FrameIt fEnd = d->m_frames.end();
5549 
5550  for (; fIt != fEnd; ++fIt )
5551  (*fIt)->m_bCompleted = false;
5552 
5553  fIt = d->m_frames.begin();
5554 
5555  QStringList::ConstIterator fNameIt = frameNames.constBegin();
5556  QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin();
5557  QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin();
5558  KUrl::List::ConstIterator fURLIt = frameURLs.constBegin();
5559  QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin();
5560  QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin();
5561 
5562  for (; fIt != fEnd; ++fIt, ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt )
5563  {
5564  khtml::ChildFrame* const child = *fIt;
5565 
5566 // kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt;
5567 
5568  if ( child->m_name != *fNameIt || child->m_serviceType != *fServiceTypeIt )
5569  {
5570  child->m_bPreloaded = true;
5571  child->m_name = *fNameIt;
5572  child->m_serviceName = *fServiceNameIt;
5573  child->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt);
5574  processObjectRequest( child, *fURLIt, *fServiceTypeIt );
5575  }
5576  if ( child->m_part )
5577  {
5578  child->m_bCompleted = false;
5579  if ( child->m_extension && !(*fBufferIt).isEmpty() )
5580  {
5581  QDataStream frameStream( *fBufferIt );
5582  child->m_extension.data()->restoreState( frameStream );
5583  }
5584  else
5585  child->m_part.data()->openUrl( *fURLIt );
5586  }
5587  }
5588 
5589  KParts::OpenUrlArguments args( arguments() );
5590  args.setXOffset(xOffset);
5591  args.setYOffset(yOffset);
5592  setArguments(args);
5593 
5594  KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
5595  browserArgs.docState = docState;
5596  d->m_extension->setBrowserArguments(browserArgs);
5597 
5598  d->m_view->resizeContents( wContents, hContents );
5599  d->m_view->setContentsPos( xOffset, yOffset );
5600 
5601  setUrl(u);
5602  }
5603  else
5604  {
5605  // Full restore.
5606  closeUrl();
5607  // We must force a clear because we want to be sure to delete all
5608  // frames.
5609  d->m_bCleared = false;
5610  clear();
5611  d->m_encoding = encoding;
5612  d->m_sheetUsed = sheetUsed;
5613 
5614  QStringList::ConstIterator fNameIt = frameNames.constBegin();
5615  const QStringList::ConstIterator fNameEnd = frameNames.constEnd();
5616 
5617  QStringList::ConstIterator fServiceTypeIt = frameServiceTypes.constBegin();
5618  QStringList::ConstIterator fServiceNameIt = frameServiceNames.constBegin();
5619  KUrl::List::ConstIterator fURLIt = frameURLs.constBegin();
5620  QList<QByteArray>::ConstIterator fBufferIt = frameStateBuffers.constBegin();
5621  QList<int>::ConstIterator fFrameTypeIt = frameTypes.constBegin();
5622 
5623  for (; fNameIt != fNameEnd; ++fNameIt, ++fServiceTypeIt, ++fServiceNameIt, ++fURLIt, ++fBufferIt, ++fFrameTypeIt )
5624  {
5625  khtml::ChildFrame* const newChild = new khtml::ChildFrame;
5626  newChild->m_bPreloaded = true;
5627  newChild->m_name = *fNameIt;
5628  newChild->m_serviceName = *fServiceNameIt;
5629  newChild->m_type = static_cast<khtml::ChildFrame::Type>(*fFrameTypeIt);
5630 
5631 // kDebug( 6050 ) << *fNameIt << " ---- " << *fServiceTypeIt;
5632 
5633  const FrameIt childFrame = d->m_frames.insert( d->m_frames.end(), newChild );
5634 
5635  processObjectRequest( *childFrame, *fURLIt, *fServiceTypeIt );
5636 
5637  (*childFrame)->m_bPreloaded = true;
5638 
5639  if ( (*childFrame)->m_part )
5640  {
5641  if ( (*childFrame)->m_extension && !(*fBufferIt).isEmpty() )
5642  {
5643  QDataStream frameStream( *fBufferIt );
5644  (*childFrame)->m_extension.data()->restoreState( frameStream );
5645  }
5646  else
5647  (*childFrame)->m_part.data()->openUrl( *fURLIt );
5648  }
5649  }
5650 
5651  KParts::OpenUrlArguments args( arguments() );
5652  args.setXOffset(xOffset);
5653  args.setYOffset(yOffset);
5654  setArguments(args);
5655 
5656  KParts::BrowserArguments browserArgs( d->m_extension->browserArguments() );
5657  browserArgs.docState = docState;
5658  d->m_extension->setBrowserArguments(browserArgs);
5659 
5660  if (!KHTMLPageCache::self()->isComplete(d->m_cacheId))
5661  {
5662  d->m_restored = true;
5663  openUrl( u );
5664  d->m_restored = false;
5665  }
5666  else
5667  {
5668  restoreURL( u );
5669  }
5670  }
5671 
5672 }
5673 
5674 void KHTMLPart::show()
5675 {
5676  if ( widget() )
5677  widget()->show();
5678 }
5679 
5680 void KHTMLPart::hide()
5681 {
5682  if ( widget() )
5683  widget()->hide();
5684 }
5685 
5686 DOM::Node KHTMLPart::nodeUnderMouse() const
5687 {
5688  return d->m_view->nodeUnderMouse();
5689 }
5690 
5691 DOM::Node KHTMLPart::nonSharedNodeUnderMouse() const
5692 {
5693  return d->m_view->nonSharedNodeUnderMouse();
5694 }
5695 
5696 void KHTMLPart::emitSelectionChanged()
5697 {
5698  // Don't emit signals about our selection if this is a frameset;
5699  // the active frame has the selection (#187403)
5700  if (!d->m_activeFrame)
5701  {
5702  emit d->m_extension->enableAction( "copy", hasSelection() );
5703  emit d->m_extension->selectionInfo( selectedText() );
5704  emit selectionChanged();
5705  }
5706 }
5707 
5708 int KHTMLPart::zoomFactor() const
5709 {
5710  return d->m_zoomFactor;
5711 }
5712 
5713 // ### make the list configurable ?
5714 static const int zoomSizes[] = { 20, 40, 60, 80, 90, 95, 100, 105, 110, 120, 140, 160, 180, 200, 250, 300 };
5715 static const int zoomSizeCount = (sizeof(zoomSizes) / sizeof(int));
5716 static const int minZoom = 20;
5717 static const int maxZoom = 300;
5718 
5719 // My idea of useful stepping ;-) (LS)
5720 extern const int KDE_NO_EXPORT fastZoomSizes[] = { 20, 50, 75, 90, 100, 120, 150, 200, 300 };
5721 extern const int KDE_NO_EXPORT fastZoomSizeCount = sizeof fastZoomSizes / sizeof fastZoomSizes[0];
5722 
5723 void KHTMLPart::slotIncZoom()
5724 {
5725  zoomIn(zoomSizes, zoomSizeCount);
5726 }
5727 
5728 void KHTMLPart::slotDecZoom()
5729 {
5730  zoomOut(zoomSizes, zoomSizeCount);
5731 }
5732 
5733 void KHTMLPart::slotIncZoomFast()
5734 {
5735  zoomIn(fastZoomSizes, fastZoomSizeCount);
5736 }
5737 
5738 void KHTMLPart::slotDecZoomFast()
5739 {
5740  zoomOut(fastZoomSizes, fastZoomSizeCount);
5741 }
5742 
5743 void KHTMLPart::zoomIn(const int stepping[], int count)
5744 {
5745  int zoomFactor = d->m_zoomFactor;
5746 
5747  if (zoomFactor < maxZoom) {
5748  // find the entry nearest to the given zoomsizes
5749  for (int i = 0; i < count; ++i)
5750  if (stepping[i] > zoomFactor) {
5751  zoomFactor = stepping[i];
5752  break;
5753  }
5754  setZoomFactor(zoomFactor);
5755  }
5756 }
5757 
5758 void KHTMLPart::zoomOut(const int stepping[], int count)
5759 {
5760  int zoomFactor = d->m_zoomFactor;
5761  if (zoomFactor > minZoom) {
5762  // find the entry nearest to the given zoomsizes
5763  for (int i = count-1; i >= 0; --i)
5764  if (stepping[i] < zoomFactor) {
5765  zoomFactor = stepping[i];
5766  break;
5767  }
5768  setZoomFactor(zoomFactor);
5769  }
5770 }
5771 
5772 void KHTMLPart::setZoomFactor (int percent)
5773 {
5774  // ### zooming under 100% is majorly botched,
5775  // so disable that for now.
5776  if (percent < 100) percent = 100;
5777  // ### if (percent < minZoom) percent = minZoom;
5778 
5779  if (percent > maxZoom) percent = maxZoom;
5780  if (d->m_zoomFactor == percent) return;
5781  d->m_zoomFactor = percent;
5782 
5783  updateZoomFactor();
5784 }
5785 
5786 
5787 void KHTMLPart::updateZoomFactor ()
5788 {
5789  if(d->m_view) {
5790  QApplication::setOverrideCursor( Qt::WaitCursor );
5791  d->m_view->setZoomLevel( d->m_zoomFactor );
5792  QApplication::restoreOverrideCursor();
5793  }
5794 
5795  ConstFrameIt it = d->m_frames.constBegin();
5796  const ConstFrameIt end = d->m_frames.constEnd();
5797  for (; it != end; ++it ) {
5798  if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
5799  p->setZoomFactor(d->m_zoomFactor);
5800  }
5801 
5802  if ( d->m_guiProfile == BrowserViewGUI ) {
5803  d->m_paDecZoomFactor->setEnabled( d->m_zoomFactor > minZoom );
5804  d->m_paIncZoomFactor->setEnabled( d->m_zoomFactor < maxZoom );
5805  }
5806 }
5807 
5808 void KHTMLPart::slotIncFontSize()
5809 {
5810  incFontSize(zoomSizes, zoomSizeCount);
5811 }
5812 
5813 void KHTMLPart::slotDecFontSize()
5814 {
5815  decFontSize(zoomSizes, zoomSizeCount);
5816 }
5817 
5818 void KHTMLPart::slotIncFontSizeFast()
5819 {
5820  incFontSize(fastZoomSizes, fastZoomSizeCount);
5821 }
5822 
5823 void KHTMLPart::slotDecFontSizeFast()
5824 {
5825  decFontSize(fastZoomSizes, fastZoomSizeCount);
5826 }
5827 
5828 void KHTMLPart::incFontSize(const int stepping[], int count)
5829 {
5830  int zoomFactor = d->m_fontScaleFactor;
5831 
5832  if (zoomFactor < maxZoom) {
5833  // find the entry nearest to the given zoomsizes
5834  for (int i = 0; i < count; ++i)
5835  if (stepping[i] > zoomFactor) {
5836  zoomFactor = stepping[i];
5837  break;
5838  }
5839  setFontScaleFactor(zoomFactor);
5840  }
5841 }
5842 
5843 void KHTMLPart::decFontSize(const int stepping[], int count)
5844 {
5845  int zoomFactor = d->m_fontScaleFactor;
5846  if (zoomFactor > minZoom) {
5847  // find the entry nearest to the given zoomsizes
5848  for (int i = count-1; i >= 0; --i)
5849  if (stepping[i] < zoomFactor) {
5850  zoomFactor = stepping[i];
5851  break;
5852  }
5853  setFontScaleFactor(zoomFactor);
5854  }
5855 }
5856 
5857 void KHTMLPart::setFontScaleFactor(int percent)
5858 {
5859  if (percent < minZoom) percent = minZoom;
5860  if (percent > maxZoom) percent = maxZoom;
5861  if (d->m_fontScaleFactor == percent) return;
5862  d->m_fontScaleFactor = percent;
5863 
5864  if (d->m_view && d->m_doc) {
5865  QApplication::setOverrideCursor( Qt::WaitCursor );
5866  if (d->m_doc->styleSelector())
5867  d->m_doc->styleSelector()->computeFontSizes(d->m_doc->logicalDpiY(), d->m_fontScaleFactor);
5868  d->m_doc->recalcStyle( NodeImpl::Force );
5869  QApplication::restoreOverrideCursor();
5870  }
5871 
5872  ConstFrameIt it = d->m_frames.constBegin();
5873  const ConstFrameIt end = d->m_frames.constEnd();
5874  for (; it != end; ++it ) {
5875  if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
5876  p->setFontScaleFactor(d->m_fontScaleFactor);
5877  }
5878 }
5879 
5880 int KHTMLPart::fontScaleFactor() const
5881 {
5882  return d->m_fontScaleFactor;
5883 }
5884 
5885 void KHTMLPart::slotZoomView( int delta )
5886 {
5887  if ( delta < 0 )
5888  slotIncZoom();
5889  else
5890  slotDecZoom();
5891 }
5892 
5893 void KHTMLPart::setStatusBarText( const QString& text, StatusBarPriority p)
5894 {
5895  if (!d->m_statusMessagesEnabled)
5896  return;
5897 
5898  d->m_statusBarText[p] = text;
5899 
5900  // shift handling ?
5901  QString tobe = d->m_statusBarText[BarHoverText];
5902  if (tobe.isEmpty())
5903  tobe = d->m_statusBarText[BarOverrideText];
5904  if (tobe.isEmpty()) {
5905  tobe = d->m_statusBarText[BarDefaultText];
5906  if (!tobe.isEmpty() && d->m_jobspeed)
5907  tobe += " ";
5908  if (d->m_jobspeed)
5909  tobe += i18n( "(%1/s)" , KIO::convertSize( d->m_jobspeed ) );
5910  }
5911  tobe = "<qt>"+tobe;
5912 
5913  emit ReadOnlyPart::setStatusBarText(tobe);
5914 }
5915 
5916 
5917 void KHTMLPart::setJSStatusBarText( const QString &text )
5918 {
5919  setStatusBarText(text, BarOverrideText);
5920 }
5921 
5922 void KHTMLPart::setJSDefaultStatusBarText( const QString &text )
5923 {
5924  setStatusBarText(text, BarDefaultText);
5925 }
5926 
5927 QString KHTMLPart::jsStatusBarText() const
5928 {
5929  return d->m_statusBarText[BarOverrideText];
5930 }
5931 
5932 QString KHTMLPart::jsDefaultStatusBarText() const
5933 {
5934  return d->m_statusBarText[BarDefaultText];
5935 }
5936 
5937 QString KHTMLPart::referrer() const
5938 {
5939  return d->m_referrer;
5940 }
5941 
5942 QString KHTMLPart::pageReferrer() const
5943 {
5944  KUrl referrerURL = KUrl( d->m_pageReferrer );
5945  if (referrerURL.isValid())
5946  {
5947  QString protocol = referrerURL.protocol();
5948 
5949  if ((protocol == "http") ||
5950  ((protocol == "https") && (url().protocol() == "https")))
5951  {
5952  referrerURL.setRef(QString());
5953  referrerURL.setUser(QString());
5954  referrerURL.setPass(QString());
5955  return referrerURL.url();
5956  }
5957  }
5958 
5959  return QString();
5960 }
5961 
5962 
5963 QString KHTMLPart::lastModified() const
5964 {
5965  if ( d->m_lastModified.isEmpty() && url().isLocalFile() ) {
5966  // Local file: set last-modified from the file's mtime.
5967  // Done on demand to save time when this isn't needed - but can lead
5968  // to slightly wrong results if updating the file on disk w/o reloading.
5969  QDateTime lastModif = QFileInfo( url().toLocalFile() ).lastModified();
5970  d->m_lastModified = lastModif.toString( Qt::LocalDate );
5971  }
5972  //kDebug(6050) << d->m_lastModified;
5973  return d->m_lastModified;
5974 }
5975 
5976 void KHTMLPart::slotLoadImages()
5977 {
5978  if (d->m_doc )
5979  d->m_doc->docLoader()->setAutoloadImages( !d->m_doc->docLoader()->autoloadImages() );
5980 
5981  ConstFrameIt it = d->m_frames.constBegin();
5982  const ConstFrameIt end = d->m_frames.constEnd();
5983  for (; it != end; ++it ) {
5984  if ( KHTMLPart* p = qobject_cast<KHTMLPart*>((*it)->m_part.data()) )
5985  p->slotLoadImages();
5986  }
5987 }
5988 
5989 void KHTMLPart::reparseConfiguration()
5990 {
5991  KHTMLSettings *settings = KHTMLGlobal::defaultHTMLSettings();
5992  settings->init();
5993 
5994  setAutoloadImages( settings->autoLoadImages() );
5995  if (d->m_doc)
5996  d->m_doc->docLoader()->setShowAnimations( settings->showAnimations() );
5997 
5998  d->m_bOpenMiddleClick = settings->isOpenMiddleClickEnabled();
5999  d->m_bJScriptEnabled = settings->isJavaScriptEnabled(url().host());
6000  setDebugScript( settings->isJavaScriptDebugEnabled() );
6001  d->m_bJavaEnabled = settings->isJavaEnabled(url().host());
6002  d->m_bPluginsEnabled = settings->isPluginsEnabled(url().host());
6003  d->m_metaRefreshEnabled = settings->isAutoDelayedActionsEnabled ();
6004 
6005  delete d->m_settings;
6006  d->m_settings = new KHTMLSettings(*KHTMLGlobal::defaultHTMLSettings());
6007 
6008  QApplication::setOverrideCursor( Qt::WaitCursor );
6009  khtml::CSSStyleSelector::reparseConfiguration();
6010  if(d->m_doc) d->m_doc->updateStyleSelector();
6011  QApplication::restoreOverrideCursor();
6012 
6013  if (d->m_view) {
6014  KHTMLSettings::KSmoothScrollingMode ssm = d->m_settings->smoothScrolling();
6015  if (ssm == KHTMLSettings::KSmoothScrollingDisabled)
6016  d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMDisabled);
6017  else if (ssm == KHTMLSettings::KSmoothScrollingWhenEfficient)
6018  d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMWhenEfficient);
6019  else
6020  d->m_view->setSmoothScrollingModeDefault(KHTMLView::SSMEnabled);
6021  }
6022 
6023  if (KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled())
6024  runAdFilter();
6025 }
6026 
6027 QStringList KHTMLPart::frameNames() const
6028 {
6029  QStringList res;
6030 
6031  ConstFrameIt it = d->m_frames.constBegin();
6032  const ConstFrameIt end = d->m_frames.constEnd();
6033  for (; it != end; ++it )
6034  if (!(*it)->m_bPreloaded && (*it)->m_part)
6035  res += (*it)->m_name;
6036 
6037  return res;
6038 }
6039 
6040 QList<KParts::ReadOnlyPart*> KHTMLPart::frames() const
6041 {
6042  QList<KParts::ReadOnlyPart*> res;
6043 
6044  ConstFrameIt it = d->m_frames.constBegin();
6045  const ConstFrameIt end = d->m_frames.constEnd();
6046  for (; it != end; ++it )
6047  if (!(*it)->m_bPreloaded && (*it)->m_part) // ### TODO: make sure that we always create an empty
6048  // KHTMLPart for frames so this never happens.
6049  res.append( (*it)->m_part.data() );
6050 
6051  return res;
6052 }
6053 
6054 bool KHTMLPart::openUrlInFrame( const KUrl &url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments &browserArgs)
6055 {
6056  kDebug( 6031 ) << this << url;
6057  FrameIt it = d->m_frames.find( browserArgs.frameName );
6058 
6059  if ( it == d->m_frames.end() )
6060  return false;
6061 
6062  // Inform someone that we are about to show something else.
6063  if ( !browserArgs.lockHistory() )
6064  emit d->m_extension->openUrlNotify();
6065 
6066  requestObject( *it, url, args, browserArgs );
6067 
6068  return true;
6069 }
6070 
6071 void KHTMLPart::setDNDEnabled( bool b )
6072 {
6073  d->m_bDnd = b;
6074 }
6075 
6076 bool KHTMLPart::dndEnabled() const
6077 {
6078  return d->m_bDnd;
6079 }
6080 
6081 void KHTMLPart::customEvent( QEvent *event )
6082 {
6083  if ( khtml::MousePressEvent::test( event ) )
6084  {
6085  khtmlMousePressEvent( static_cast<khtml::MousePressEvent *>( event ) );
6086  return;
6087  }
6088 
6089  if ( khtml::MouseDoubleClickEvent::test( event ) )
6090  {
6091  khtmlMouseDoubleClickEvent( static_cast<khtml::MouseDoubleClickEvent *>( event ) );
6092  return;
6093  }
6094 
6095  if ( khtml::MouseMoveEvent::test( event ) )
6096  {
6097  khtmlMouseMoveEvent( static_cast<khtml::MouseMoveEvent *>( event ) );
6098  return;
6099  }
6100 
6101  if ( khtml::MouseReleaseEvent::test( event ) )
6102  {
6103  khtmlMouseReleaseEvent( static_cast<khtml::MouseReleaseEvent *>( event ) );
6104  return;
6105  }
6106 
6107  if ( khtml::DrawContentsEvent::test( event ) )
6108  {
6109  khtmlDrawContentsEvent( static_cast<khtml::DrawContentsEvent *>( event ) );
6110  return;
6111  }
6112 
6113  KParts::ReadOnlyPart::customEvent( event );
6114 }
6115 
6116 bool KHTMLPart::isPointInsideSelection(int x, int y)
6117 {
6118  // Treat a collapsed selection like no selection.
6119  if (d->editor_context.m_selection.state() == Selection::CARET)
6120  return false;
6121  if (!xmlDocImpl()->renderer())
6122  return false;
6123 
6124  khtml::RenderObject::NodeInfo nodeInfo(true, true);
6125  xmlDocImpl()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y);
6126  NodeImpl *innerNode = nodeInfo.innerNode();
6127  if (!innerNode || !innerNode->renderer())
6128  return false;
6129 
6130  return innerNode->isPointInsideSelection(x, y, d->editor_context.m_selection);
6131 }
6132 
6138 static bool firstRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset)
6139 {
6140  for (khtml::RenderObject *n = renderNode; n; n = n->nextSibling()) {
6141  if (n->isText()) {
6142  khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
6143  for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
6144  if (box->m_y == y && textRenderer->element()) {
6145  startNode = textRenderer->element();
6146  startOffset = box->m_start;
6147  return true;
6148  }
6149  }
6150  }
6151 
6152  if (firstRunAt(n->firstChild(), y, startNode, startOffset)) {
6153  return true;
6154  }
6155  }
6156 
6157  return false;
6158 }
6159 
6165 static bool lastRunAt(khtml::RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset)
6166 {
6167  khtml::RenderObject *n = renderNode;
6168  if (!n) {
6169  return false;
6170  }
6171  khtml::RenderObject *next;
6172  while ((next = n->nextSibling())) {
6173  n = next;
6174  }
6175 
6176  while (1) {
6177  if (lastRunAt(n->firstChild(), y, endNode, endOffset)) {
6178  return true;
6179  }
6180 
6181  if (n->isText()) {
6182  khtml::RenderText* const textRenderer = static_cast<khtml::RenderText *>(n);
6183  for (khtml::InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
6184  if (box->m_y == y && textRenderer->element()) {
6185  endNode = textRenderer->element();
6186  endOffset = box->m_start + box->m_len;
6187  return true;
6188  }
6189  }
6190  }
6191 
6192  if (n == renderNode) {
6193  return false;
6194  }
6195 
6196  n = n->previousSibling();
6197  }
6198 }
6199 
6200 void KHTMLPart::handleMousePressEventDoubleClick(khtml::MouseDoubleClickEvent *event)
6201 {
6202  QMouseEvent *mouse = event->qmouseEvent();
6203  DOM::Node innerNode = event->innerNode();
6204 
6205  Selection selection;
6206 
6207  if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() &&
6208  innerNode.handle()->renderer()->shouldSelect()) {
6209  Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()).position());
6210  if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
6211  selection.moveTo(pos);
6212  selection.expandUsingGranularity(Selection::WORD);
6213  }
6214  }
6215 
6216  if (selection.state() != Selection::CARET) {
6217  d->editor_context.beginSelectingText(Selection::WORD);
6218  }
6219 
6220  setCaret(selection);
6221  startAutoScroll();
6222 }
6223 
6224 void KHTMLPart::handleMousePressEventTripleClick(khtml::MouseDoubleClickEvent *event)
6225 {
6226  QMouseEvent *mouse = event->qmouseEvent();
6227  DOM::Node innerNode = event->innerNode();
6228 
6229  Selection selection;
6230 
6231  if (mouse->button() == Qt::LeftButton && !innerNode.isNull() && innerNode.handle()->renderer() &&
6232  innerNode.handle()->renderer()->shouldSelect()) {
6233  Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()).position());
6234  if (pos.node() && (pos.node()->nodeType() == Node::TEXT_NODE || pos.node()->nodeType() == Node::CDATA_SECTION_NODE)) {
6235  selection.moveTo(pos);
6236  selection.expandUsingGranularity(Selection::LINE);
6237  }
6238  }
6239 
6240  if (selection.state() != Selection::CARET) {
6241  d->editor_context.beginSelectingText(Selection::LINE);
6242  }
6243 
6244  setCaret(selection);
6245  startAutoScroll();
6246 }
6247 
6248 void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event)
6249 {
6250  QMouseEvent *mouse = event->qmouseEvent();
6251  DOM::Node innerNode = event->innerNode();
6252 
6253  if (mouse->button() == Qt::LeftButton) {
6254  Selection sel;
6255 
6256  if (!innerNode.isNull() && innerNode.handle()->renderer() &&
6257  innerNode.handle()->renderer()->shouldSelect()) {
6258  bool extendSelection = mouse->modifiers() & Qt::ShiftModifier;
6259 
6260  // Don't restart the selection when the mouse is pressed on an
6261  // existing selection so we can allow for text dragging.
6262  if (!extendSelection && isPointInsideSelection(event->x(), event->y())) {
6263  return;
6264  }
6265  Position pos(innerNode.handle()->positionForCoordinates(event->x(), event->y()).position());
6266  if (pos.isEmpty())
6267  pos = Position(innerNode.handle(), innerNode.handle()->caretMinOffset());
6268  kDebug(6050) << event->x() << event->y() << pos << endl;
6269 
6270  sel = caret();
6271  if (extendSelection && sel.notEmpty()) {
6272  sel.clearModifyBias();
6273  sel.setExtent(pos);
6274  if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
6275  sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
6276  }
6277  d->editor_context.m_beganSelectingText = true;
6278  } else {
6279  sel = pos;
6280  d->editor_context.m_selectionGranularity = Selection::CHARACTER;
6281  }
6282  }
6283 
6284  setCaret(sel);
6285  startAutoScroll();
6286  }
6287 }
6288 
6289 void KHTMLPart::khtmlMousePressEvent( khtml::MousePressEvent *event )
6290 {
6291  DOM::DOMString url = event->url();
6292  QMouseEvent *_mouse = event->qmouseEvent();
6293  DOM::Node innerNode = event->innerNode();
6294  d->m_mousePressNode = innerNode;
6295 
6296  d->m_dragStartPos = QPoint(event->x(), event->y());
6297 
6298  if ( !event->url().isNull() ) {
6299  d->m_strSelectedURL = event->url().string();
6300  d->m_strSelectedURLTarget = event->target().string();
6301  }
6302  else {
6303  d->m_strSelectedURL.clear();
6304  d->m_strSelectedURLTarget.clear();
6305  }
6306 
6307  if ( _mouse->button() == Qt::LeftButton ||
6308  _mouse->button() == Qt::MidButton )
6309  {
6310  d->m_bMousePressed = true;
6311 
6312 #ifdef KHTML_NO_SELECTION
6313  d->m_dragLastPos = _mouse->globalPos();
6314 #else
6315  if ( _mouse->button() == Qt::LeftButton )
6316  {
6317  if ( (!d->m_strSelectedURL.isNull() && !isEditable())
6318  || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) )
6319  return;
6320 
6321  d->editor_context.m_beganSelectingText = false;
6322 
6323  handleMousePressEventSingleClick(event);
6324  }
6325 #endif
6326  }
6327 
6328  if ( _mouse->button() == Qt::RightButton )
6329  {
6330  popupMenu( d->m_strSelectedURL );
6331  // might be deleted, don't touch "this"
6332  }
6333 }
6334 
6335 void KHTMLPart::khtmlMouseDoubleClickEvent( khtml::MouseDoubleClickEvent *event )
6336 {
6337  QMouseEvent *_mouse = event->qmouseEvent();
6338  if ( _mouse->button() == Qt::LeftButton )
6339  {
6340  d->m_bMousePressed = true;
6341  d->editor_context.m_beganSelectingText = false;
6342 
6343  if (event->clickCount() == 2) {
6344  handleMousePressEventDoubleClick(event);
6345  return;
6346  }
6347 
6348  if (event->clickCount() >= 3) {
6349  handleMousePressEventTripleClick(event);
6350  return;
6351  }
6352  }
6353 }
6354 
6355 #ifndef KHTML_NO_SELECTION
6356 bool KHTMLPart::isExtendingSelection() const
6357  {
6358  // This is it, the whole detection. khtmlMousePressEvent only sets this
6359  // on LMB or MMB, but never on RMB. As text selection doesn't work for MMB,
6360  // it's sufficient to only rely on this flag to detect selection extension.
6361  return d->editor_context.m_beganSelectingText;
6362 }
6363 
6364 void KHTMLPart::extendSelectionTo(int x, int y, const DOM::Node &innerNode)
6365 {
6366  // handle making selection
6367  Position pos(innerNode.handle()->positionForCoordinates(x, y).position());
6368 
6369  // Don't modify the selection if we're not on a node.
6370  if (pos.isEmpty())
6371  return;
6372 
6373  // Restart the selection if this is the first mouse move. This work is usually
6374  // done in khtmlMousePressEvent, but not if the mouse press was on an existing selection.
6375  Selection sel = caret();
6376  sel.clearModifyBias();
6377  if (!d->editor_context.m_beganSelectingText) {
6378  // We are beginning a selection during press-drag, when the original click
6379  // wasn't appropriate for one. Make sure to set the granularity.
6380  d->editor_context.beginSelectingText(Selection::CHARACTER);
6381  sel.moveTo(pos);
6382  }
6383 
6384  sel.setExtent(pos);
6385  if (d->editor_context.m_selectionGranularity != Selection::CHARACTER) {
6386  sel.expandUsingGranularity(d->editor_context.m_selectionGranularity);
6387  }
6388  setCaret(sel);
6389 
6390 }
6391 #endif // KHTML_NO_SELECTION
6392 
6393 bool KHTMLPart::handleMouseMoveEventDrag(khtml::MouseMoveEvent *event)
6394 {
6395 #ifdef QT_NO_DRAGANDDROP
6396  return false;
6397 #else
6398  if (!dndEnabled())
6399  return false;
6400 
6401  DOM::Node innerNode = event->innerNode();
6402 
6403  if( (d->m_bMousePressed &&
6404  ( (!d->m_strSelectedURL.isEmpty() && !isEditable())
6405  || (!d->m_mousePressNode.isNull() && d->m_mousePressNode.elementId() == ID_IMG) ) )
6406  && ( d->m_dragStartPos - QPoint(event->x(), event->y()) ).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
6407 
6408  DOM::DOMString url = event->url();
6409 
6410  QPixmap pix;
6411  HTMLImageElementImpl *img = 0L;
6412  KUrl u;
6413 
6414  // qDebug("****************** Event URL: %s", url.string().toLatin1().constData());
6415  // qDebug("****************** Event Target: %s", target.string().toLatin1().constData());
6416 
6417  // Normal image...
6418  if ( url.length() == 0 && innerNode.handle() && innerNode.handle()->id() == ID_IMG )
6419  {
6420  img = static_cast<HTMLImageElementImpl *>(innerNode.handle());
6421  u = KUrl( completeURL( khtml::parseURL(img->getAttribute(ATTR_SRC)).string() ) );
6422  pix = KIconLoader::global()->loadIcon("image-x-generic", KIconLoader::Desktop);
6423  }
6424  else
6425  {
6426  // Text or image link...
6427  u = completeURL( d->m_strSelectedURL );
6428  pix = KIO::pixmapForUrl(u, 0, KIconLoader::Desktop, KIconLoader::SizeMedium);
6429  }
6430 
6431  u.setPass(QString());
6432 
6433  QDrag *drag = new QDrag( d->m_view->viewport() );
6434  QMap<QString, QString> metaDataMap;
6435  if ( !d->m_referrer.isEmpty() )
6436  metaDataMap.insert( "referrer", d->m_referrer );
6437  QMimeData* mimeData = new QMimeData();
6438  u.populateMimeData( mimeData, metaDataMap );
6439  drag->setMimeData( mimeData );
6440 
6441  if( img && img->complete() )
6442  drag->mimeData()->setImageData( img->currentImage() );
6443 
6444  if ( !pix.isNull() )
6445  drag->setPixmap( pix );
6446 
6447  stopAutoScroll();
6448  drag->start();
6449 
6450  // when we finish our drag, we need to undo our mouse press
6451  d->m_bMousePressed = false;
6452  d->m_strSelectedURL.clear();
6453  d->m_strSelectedURLTarget.clear();
6454  return true;
6455  }
6456  return false;
6457 #endif // QT_NO_DRAGANDDROP
6458 }
6459 
6460 bool KHTMLPart::handleMouseMoveEventOver(khtml::MouseMoveEvent *event)
6461 {
6462  // Mouse clicked -> do nothing
6463  if ( d->m_bMousePressed ) return false;
6464 
6465  DOM::DOMString url = event->url();
6466 
6467  // The mouse is over something
6468  if ( url.length() )
6469  {
6470  DOM::DOMString target = event->target();
6471  QMouseEvent *_mouse = event->qmouseEvent();
6472  DOM::Node innerNode = event->innerNode();
6473 
6474  bool shiftPressed = ( _mouse->modifiers() & Qt::ShiftModifier );
6475 
6476  // Image map
6477  if ( !innerNode.isNull() && innerNode.elementId() == ID_IMG )
6478  {
6479  HTMLImageElementImpl *i = static_cast<HTMLImageElementImpl *>(innerNode.handle());
6480  if ( i && i->isServerMap() )
6481  {
6482  khtml::RenderObject *r = i->renderer();
6483  if(r)
6484  {
6485  int absx, absy;
6486  r->absolutePosition(absx, absy);
6487  int x(event->x() - absx), y(event->y() - absy);
6488 
6489  d->m_overURL = url.string() + QString("?%1,%2").arg(x).arg(y);
6490  d->m_overURLTarget = target.string();
6491  overURL( d->m_overURL, target.string(), shiftPressed );
6492  return true;
6493  }
6494  }
6495  }
6496 
6497  // normal link
6498  if ( d->m_overURL.isEmpty() || d->m_overURL != url || d->m_overURLTarget != target )
6499  {
6500  d->m_overURL = url.string();
6501  d->m_overURLTarget = target.string();
6502  overURL( d->m_overURL, target.string(), shiftPressed );
6503  }
6504  }
6505  else // Not over a link...
6506  {
6507  if( !d->m_overURL.isEmpty() ) // and we were over a link -> reset to "default statusbar text"
6508  {
6509  // reset to "default statusbar text"
6510  resetHoverText();
6511  }
6512  }
6513  return true;
6514 }
6515 
6516 void KHTMLPart::handleMouseMoveEventSelection(khtml::MouseMoveEvent *event)
6517 {
6518  // Mouse not pressed. Do nothing.
6519  if (!d->m_bMousePressed)
6520  return;
6521 
6522 #ifdef KHTML_NO_SELECTION
6523  if (d->m_doc && d->m_view) {
6524  QPoint diff( mouse->globalPos() - d->m_dragLastPos );
6525 
6526  if (abs(diff.x()) > 64 || abs(diff.y()) > 64) {
6527  d->m_view->scrollBy(-diff.x(), -diff.y());
6528  d->m_dragLastPos = mouse->globalPos();
6529  }
6530  }
6531 #else
6532 
6533  QMouseEvent *mouse = event->qmouseEvent();
6534  DOM::Node innerNode = event->innerNode();
6535 
6536  if ( (mouse->buttons() & Qt::LeftButton) == 0 || !innerNode.handle() || !innerNode.handle()->renderer() ||
6537  !innerNode.handle()->renderer()->shouldSelect())
6538  return;
6539 
6540  // handle making selection
6541  extendSelectionTo(event->x(), event->y(), innerNode);
6542 #endif // KHTML_NO_SELECTION
6543 }
6544 
6545 void KHTMLPart::khtmlMouseMoveEvent( khtml::MouseMoveEvent *event )
6546 {
6547  if (handleMouseMoveEventDrag(event))
6548  return;
6549 
6550  if (handleMouseMoveEventOver(event))
6551  return;
6552 
6553  handleMouseMoveEventSelection(event);
6554 }
6555 
6556 void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
6557 {
6558  DOM::Node innerNode = event->innerNode();
6559  d->m_mousePressNode = DOM::Node();
6560 
6561  if ( d->m_bMousePressed ) {
6562  setStatusBarText(QString(), BarHoverText);
6563  stopAutoScroll();
6564  }
6565 
6566  // Used to prevent mouseMoveEvent from initiating a drag before
6567  // the mouse is pressed again.
6568  d->m_bMousePressed = false;
6569 
6570 #ifndef QT_NO_CLIPBOARD
6571  QMouseEvent *_mouse = event->qmouseEvent();
6572  if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == Qt::MidButton) && (event->url().isNull())) {
6573  kDebug( 6050 ) << "MMB shouldOpen=" << d->m_bOpenMiddleClick;
6574 
6575  if (d->m_bOpenMiddleClick) {
6576  KHTMLPart *p = this;
6577  while (p->parentPart()) p = p->parentPart();
6578  p->d->m_extension->pasteRequest();
6579  }
6580  }
6581 #endif
6582 
6583 #ifndef KHTML_NO_SELECTION
6584  {
6585 
6586  // Clear the selection if the mouse didn't move after the last mouse press.
6587  // We do this so when clicking on the selection, the selection goes away.
6588  // However, if we are editing, place the caret.
6589  if (!d->editor_context.m_beganSelectingText
6590  && d->m_dragStartPos.x() == event->x()
6591  && d->m_dragStartPos.y() == event->y()
6592  && d->editor_context.m_selection.state() == Selection::RANGE) {
6593  Selection selection;
6594 #ifdef APPLE_CHANGES
6595  if (d->editor_context.m_selection.base().node()->isContentEditable())
6596 #endif
6597  selection.moveTo(d->editor_context.m_selection.base().node()->positionForCoordinates(event->x(), event->y()).position());
6598  setCaret(selection);
6599  }
6600  // get selected text and paste to the clipboard
6601 #ifndef QT_NO_CLIPBOARD
6602  QString text = selectedText();
6603  text.replace(QChar(0xa0), ' ');
6604  if (!text.isEmpty()) {
6605  disconnect( qApp->clipboard(), SIGNAL(selectionChanged()), this, SLOT(slotClearSelection()));
6606  qApp->clipboard()->setText(text,QClipboard::Selection);
6607  connect( qApp->clipboard(), SIGNAL(selectionChanged()), SLOT(slotClearSelection()));
6608  }
6609 #endif
6610  //kDebug( 6000 ) << "selectedText = " << text;
6611  emitSelectionChanged();
6612 //kDebug(6000) << "rel2: startBefEnd " << d->m_startBeforeEnd << " extAtEnd " << d->m_extendAtEnd << " (" << d->m_startOffset << ") - (" << d->m_endOffset << "), caretOfs " << d->caretOffset();
6613  }
6614 #endif
6615 }
6616 
6617 void KHTMLPart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * )
6618 {
6619 }
6620 
6621 void KHTMLPart::guiActivateEvent( KParts::GUIActivateEvent *event )
6622 {
6623  if ( event->activated() )
6624  {
6625  emitSelectionChanged();
6626  emit d->m_extension->enableAction( "print", d->m_doc != 0 );
6627 
6628  if ( !d->m_settings->autoLoadImages() && d->m_paLoadImages )
6629  {
6630  QList<QAction*> lst;
6631  lst.append( d->m_paLoadImages );
6632  plugActionList( "loadImages", lst );
6633  }
6634  }
6635 }
6636 
6637 void KHTMLPart::slotPrintFrame()
6638 {
6639  if ( d->m_frames.count() == 0 )
6640  return;
6641 
6642  KParts::ReadOnlyPart *frame = currentFrame();
6643  if (!frame)
6644  return;
6645 
6646  KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject( frame );
6647 
6648  if ( !ext )
6649  return;
6650 
6651 
6652  const QMetaObject *mo = ext->metaObject();
6653 
6654 
6655  if (mo->indexOfSlot( "print()") != -1)
6656  QMetaObject::invokeMethod(ext, "print()", Qt::DirectConnection);
6657 }
6658 
6659 void KHTMLPart::slotSelectAll()
6660 {
6661  KParts::ReadOnlyPart *part = currentFrame();
6662  if (part && part->inherits("KHTMLPart"))
6663  static_cast<KHTMLPart *>(part)->selectAll();
6664 }
6665 
6666 void KHTMLPart::startAutoScroll()
6667 {
6668  connect(&d->m_scrollTimer, SIGNAL(timeout()), this, SLOT(slotAutoScroll()));
6669  d->m_scrollTimer.setSingleShot(false);
6670  d->m_scrollTimer.start(100);
6671 }
6672 
6673 void KHTMLPart::stopAutoScroll()
6674 {
6675  disconnect(&d->m_scrollTimer, SIGNAL(timeout()), this, SLOT(slotAutoScroll()));
6676  if (d->m_scrollTimer.isActive())
6677  d->m_scrollTimer.stop();
6678 }
6679 
6680 
6681 void KHTMLPart::slotAutoScroll()
6682 {
6683  if (d->m_view)
6684  d->m_view->doAutoScroll();
6685  else
6686  stopAutoScroll(); // Safety
6687 }
6688 
6689 void KHTMLPart::runAdFilter()
6690 {
6691  if ( parentPart() )
6692  parentPart()->runAdFilter();
6693 
6694  if ( !d->m_doc )
6695  return;
6696 
6697  QSetIterator<khtml::CachedObject*> it( d->m_doc->docLoader()->m_docObjects );
6698  while (it.hasNext())
6699  {
6700  khtml::CachedObject* obj = it.next();
6701  if ( obj->type() == khtml::CachedObject::Image ) {
6702  khtml::CachedImage *image = static_cast<khtml::CachedImage *>(obj);
6703  bool wasBlocked = image->m_wasBlocked;
6704  image->m_wasBlocked = KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( image->url().string() ) );
6705  if ( image->m_wasBlocked != wasBlocked )
6706  image->do_notify(QRect(QPoint(0,0), image->pixmap_size()));
6707  }
6708  }
6709 
6710  if ( KHTMLGlobal::defaultHTMLSettings()->isHideAdsEnabled() ) {
6711  for ( NodeImpl *nextNode, *node = d->m_doc; node; node = nextNode ) {
6712 
6713  // We might be deleting 'node' shortly.
6714  nextNode = node->traverseNextNode();
6715 
6716  if ( node->id() == ID_IMG ||
6717  node->id() == ID_IFRAME ||
6718  (node->id() == ID_INPUT && static_cast<HTMLInputElementImpl *>(node)->inputType() == HTMLInputElementImpl::IMAGE ))
6719  {
6720  if ( KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( d->m_doc->completeURL( static_cast<ElementImpl *>(node)->getAttribute(ATTR_SRC).string() ) ) )
6721  {
6722  // Since any kids of node will be deleted, too, fastforward nextNode
6723  // until we get outside of node.
6724  while (nextNode && nextNode->isAncestor(node))
6725  nextNode = nextNode->traverseNextNode();
6726 
6727  node->ref();
6728  NodeImpl *parent = node->parent();
6729  if( parent )
6730  {
6731  int exception = 0;
6732  parent->removeChild(node, exception);
6733  }
6734  node->deref();
6735  }
6736  }
6737  }
6738  }
6739 }
6740 
6741 void KHTMLPart::selectAll()
6742 {
6743  if (!d->m_doc) return;
6744 
6745  NodeImpl *first;
6746  if (d->m_doc->isHTMLDocument())
6747  first = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
6748  else
6749  first = d->m_doc;
6750  NodeImpl *next;
6751 
6752  // Look for first text/cdata node that has a renderer,
6753  // or first childless replaced element
6754  while ( first && !(first->renderer()
6755  && ((first->nodeType() == Node::TEXT_NODE || first->nodeType() == Node::CDATA_SECTION_NODE)
6756  || (first->renderer()->isReplaced() && !first->renderer()->firstChild()))))
6757  {
6758  next = first->firstChild();
6759  if ( !next ) next = first->nextSibling();
6760  while( first && !next )
6761  {
6762  first = first->parentNode();
6763  if ( first )
6764  next = first->nextSibling();
6765  }
6766  first = next;
6767  }
6768 
6769  NodeImpl *last;
6770  if (d->m_doc->isHTMLDocument())
6771  last = static_cast<HTMLDocumentImpl*>(d->m_doc)->body();
6772  else
6773  last = d->m_doc;
6774  // Look for last text/cdata node that has a renderer,
6775  // or last childless replaced element
6776  // ### Instead of changing this loop, use findLastSelectableNode
6777  // in render_table.cpp (LS)
6778  while ( last && !(last->renderer()
6779  && ((last->nodeType() == Node::TEXT_NODE || last->nodeType() == Node::CDATA_SECTION_NODE)
6780  || (last->renderer()->isReplaced() && !last->renderer()->lastChild()))))
6781  {
6782  next = last->lastChild();
6783  if ( !next ) next = last->previousSibling();
6784  while ( last && !next )
6785  {
6786  last = last->parentNode();
6787  if ( last )
6788  next = last->previousSibling();
6789  }
6790  last = next;
6791  }
6792 
6793  if ( !first || !last )
6794  return;
6795  Q_ASSERT(first->renderer());
6796  Q_ASSERT(last->renderer());
6797  d->editor_context.m_selection.moveTo(Position(first, 0), Position(last, last->nodeValue().length()));
6798  d->m_doc->updateSelection();
6799 
6800  emitSelectionChanged();
6801 }
6802 
6803 bool KHTMLPart::checkLinkSecurity(const KUrl &linkURL,const KLocalizedString &message, const QString &button)
6804 {
6805  bool linkAllowed = true;
6806 
6807  if ( d->m_doc )
6808  linkAllowed = KAuthorized::authorizeUrlAction("redirect", url(), linkURL);
6809 
6810  if ( !linkAllowed ) {
6811  khtml::Tokenizer *tokenizer = d->m_doc->tokenizer();
6812  if (tokenizer)
6813  tokenizer->setOnHold(true);
6814 
6815  int response = KMessageBox::Cancel;
6816  if (!message.isEmpty())
6817  {
6818  // Dangerous flag makes the Cancel button the default
6819  response = KMessageBox::warningContinueCancel( 0,
6820  message.subs(Qt::escape(linkURL.prettyUrl())).toString(),
6821  i18n( "Security Warning" ),
6822  KGuiItem(button),
6823  KStandardGuiItem::cancel(),
6824  QString(), // no don't ask again info
6825  KMessageBox::Notify | KMessageBox::Dangerous );
6826  }
6827  else
6828  {
6829  KMessageBox::error( 0,
6830  i18n( "<qt>Access by untrusted page to<br /><b>%1</b><br /> denied.</qt>", Qt::escape(linkURL.prettyUrl())),
6831  i18n( "Security Alert" ));
6832  }
6833 
6834  if (tokenizer)
6835  tokenizer->setOnHold(false);
6836  return (response==KMessageBox::Continue);
6837  }
6838  return true;
6839 }
6840 
6841 void KHTMLPart::slotPartRemoved( KParts::Part *part )
6842 {
6843 // kDebug(6050) << part;
6844  if ( part == d->m_activeFrame )
6845  {
6846  d->m_activeFrame = 0L;
6847  if ( !part->inherits( "KHTMLPart" ) )
6848  {
6849  if (factory()) {
6850  factory()->removeClient( part );
6851  }
6852  if (childClients().contains(part)) {
6853  removeChildClient( part );
6854  }
6855  }
6856  }
6857 }
6858 
6859 void KHTMLPart::slotActiveFrameChanged( KParts::Part *part )
6860 {
6861 // kDebug(6050) << this << "part=" << part;
6862  if ( part == this )
6863  {
6864  kError(6050) << "strange error! we activated ourselves";
6865  assert( false );
6866  return;
6867  }
6868 // kDebug(6050) << "d->m_activeFrame=" << d->m_activeFrame;
6869  if ( d->m_activeFrame && d->m_activeFrame->widget() && d->m_activeFrame->widget()->inherits( "QFrame" ) )
6870  {
6871  QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
6872  if (frame->frameStyle() != QFrame::NoFrame)
6873  {
6874  frame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken);
6875  frame->repaint();
6876  }
6877  }
6878 
6879  if( d->m_activeFrame && !d->m_activeFrame->inherits( "KHTMLPart" ) )
6880  {
6881  if (factory()) {
6882  factory()->removeClient( d->m_activeFrame );
6883  }
6884  removeChildClient( d->m_activeFrame );
6885  }
6886  if( part && !part->inherits( "KHTMLPart" ) )
6887  {
6888  if (factory()) {
6889  factory()->addClient( part );
6890  }
6891  insertChildClient( part );
6892  }
6893 
6894 
6895  d->m_activeFrame = part;
6896 
6897  if ( d->m_activeFrame && d->m_activeFrame->widget()->inherits( "QFrame" ) )
6898  {
6899  QFrame *frame = static_cast<QFrame *>( d->m_activeFrame->widget() );
6900  if (frame->frameStyle() != QFrame::NoFrame)
6901  {
6902  frame->setFrameStyle( QFrame::StyledPanel | QFrame::Plain);
6903  frame->repaint();
6904  }
6905  kDebug(6050) << "new active frame " << d->m_activeFrame;
6906  }
6907 
6908  updateActions();
6909 
6910  // (note: childObject returns 0 if the argument is 0)
6911  d->m_extension->setExtensionProxy( KParts::BrowserExtension::childObject( d->m_activeFrame ) );
6912 }
6913 
6914 void KHTMLPart::setActiveNode(const DOM::Node &node)
6915 {
6916  if (!d->m_doc || !d->m_view)
6917  return;
6918 
6919  // Set the document's active node
6920  d->m_doc->setFocusNode(node.handle());
6921 
6922  // Scroll the view if necessary to ensure that the new focus node is visible
6923  QRect rect = node.handle()->getRect();
6924  d->m_view->ensureVisible(rect.right(), rect.bottom());
6925  d->m_view->ensureVisible(rect.left(), rect.top());
6926 }
6927 
6928 DOM::Node KHTMLPart::activeNode() const
6929 {
6930  return DOM::Node(d->m_doc?d->m_doc->focusNode():0);
6931 }
6932 
6933 DOM::EventListener *KHTMLPart::createHTMLEventListener( QString code, QString name, NodeImpl* node, bool svg )
6934 {
6935  KJSProxy *proxy = jScript();
6936 
6937  if (!proxy)
6938  return 0;
6939 
6940  return proxy->createHTMLEventHandler( url().url(), name, code, node, svg );
6941 }
6942 
6943 KHTMLPart *KHTMLPart::opener()
6944 {
6945  return d->m_opener;
6946 }
6947 
6948 void KHTMLPart::setOpener(KHTMLPart *_opener)
6949 {
6950  d->m_opener = _opener;
6951 }
6952 
6953 bool KHTMLPart::openedByJS()
6954 {
6955  return d->m_openedByJS;
6956 }
6957 
6958 void KHTMLPart::setOpenedByJS(bool _openedByJS)
6959 {
6960  d->m_openedByJS = _openedByJS;
6961 }
6962 
6963 void KHTMLPart::preloadStyleSheet(const QString &url, const QString &stylesheet)
6964 {
6965  khtml::Cache::preloadStyleSheet(url, stylesheet);
6966 }
6967 
6968 void KHTMLPart::preloadScript(const QString &url, const QString &script)
6969 {
6970  khtml::Cache::preloadScript(url, script);
6971 }
6972 
6973 long KHTMLPart::cacheId() const
6974 {
6975  return d->m_cacheId;
6976 }
6977 
6978 bool KHTMLPart::restored() const
6979 {
6980  return d->m_restored;
6981 }
6982 
6983 bool KHTMLPart::pluginPageQuestionAsked(const QString& mimetype) const
6984 {
6985  // parentPart() should be const!
6986  KHTMLPart* parent = const_cast<KHTMLPart *>(this)->parentPart();
6987  if ( parent )
6988  return parent->pluginPageQuestionAsked(mimetype);
6989 
6990  return d->m_pluginPageQuestionAsked.contains(mimetype);
6991 }
6992 
6993 void KHTMLPart::setPluginPageQuestionAsked(const QString& mimetype)
6994 {
6995  if ( parentPart() )
6996  parentPart()->setPluginPageQuestionAsked(mimetype);
6997 
6998  d->m_pluginPageQuestionAsked.append(mimetype);
6999 }
7000 
7001 KEncodingDetector *KHTMLPart::createDecoder()
7002 {
7003  KEncodingDetector *dec = new KEncodingDetector();
7004  if( !d->m_encoding.isNull() )
7005  dec->setEncoding( d->m_encoding.toLatin1().constData(),
7006  d->m_haveEncoding ? KEncodingDetector::UserChosenEncoding : KEncodingDetector::EncodingFromHTTPHeader);
7007  else {
7008  // Inherit the default encoding from the parent frame if there is one.
7009  QByteArray defaultEncoding = (parentPart() && parentPart()->d->m_decoder)
7010  ? QByteArray( parentPart()->d->m_decoder->encoding() ) : settings()->encoding().toLatin1();
7011  dec->setEncoding(defaultEncoding.constData(), KEncodingDetector::DefaultEncoding);
7012  }
7013 
7014  if (d->m_doc)
7015  d->m_doc->setDecoder(dec);
7016  dec->setAutoDetectLanguage( d->m_autoDetectLanguage );
7017  return dec;
7018 }
7019 
7020 void KHTMLPart::emitCaretPositionChanged(const DOM::Position &pos) {
7021  // pos must not be already converted to range-compliant coordinates
7022  Position rng_pos = pos.equivalentRangeCompliantPosition();
7023  Node node = rng_pos.node();
7024  emit caretPositionChanged(node, rng_pos.offset());
7025 }
7026 
7027 void KHTMLPart::restoreScrollPosition()
7028 {
7029  const KParts::OpenUrlArguments args( arguments() );
7030 
7031  if ( url().hasRef() && !d->m_restoreScrollPosition && !args.reload()) {
7032  if ( !d->m_doc || !d->m_doc->parsing() )
7033  disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
7034  if ( !gotoAnchor(url().encodedHtmlRef()) )
7035  gotoAnchor(url().htmlRef());
7036  return;
7037  }
7038 
7039  // Check whether the viewport has become large enough to encompass the stored
7040  // offsets. If the document has been fully loaded, force the new coordinates,
7041  // even if the canvas is too short (can happen when user resizes the window
7042  // during loading).
7043  if (d->m_view->contentsHeight() - d->m_view->visibleHeight() >= args.yOffset()
7044  || d->m_bComplete) {
7045  d->m_view->setContentsPos(args.xOffset(), args.yOffset());
7046  disconnect(d->m_view, SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()));
7047  }
7048 }
7049 
7050 
7051 void KHTMLPart::openWallet(DOM::HTMLFormElementImpl *form)
7052 {
7053 #ifndef KHTML_NO_WALLET
7054  KHTMLPart *p;
7055 
7056  for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
7057  }
7058 
7059  if (p) {
7060  p->openWallet(form);
7061  return;
7062  }
7063 
7064  if (onlyLocalReferences()) { // avoid triggering on local apps, thumbnails
7065  return;
7066  }
7067 
7068  if (d->m_wallet) {
7069  if (d->m_bWalletOpened) {
7070  if (d->m_wallet->isOpen()) {
7071  form->walletOpened(d->m_wallet);
7072  return;
7073  }
7074  d->m_wallet->deleteLater();
7075  d->m_wallet = 0L;
7076  d->m_bWalletOpened = false;
7077  }
7078  }
7079 
7080  if (!d->m_wq) {
7081  KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
7082  d->m_wq = new KHTMLWalletQueue(this);
7083  d->m_wq->wallet = wallet;
7084  connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
7085  connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
7086  }
7087  assert(form);
7088  d->m_wq->callers.append(KHTMLWalletQueue::Caller(form, form->document()));
7089 #endif // KHTML_NO_WALLET
7090 }
7091 
7092 
7093 void KHTMLPart::saveToWallet(const QString& key, const QMap<QString,QString>& data)
7094 {
7095 #ifndef KHTML_NO_WALLET
7096  KHTMLPart *p;
7097 
7098  for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
7099  }
7100 
7101  if (p) {
7102  p->saveToWallet(key, data);
7103  return;
7104  }
7105 
7106  if (d->m_wallet) {
7107  if (d->m_bWalletOpened) {
7108  if (d->m_wallet->isOpen()) {
7109  if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder())) {
7110  d->m_wallet->createFolder(KWallet::Wallet::FormDataFolder());
7111  }
7112  d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder());
7113  d->m_wallet->writeMap(key, data);
7114  return;
7115  }
7116  d->m_wallet->deleteLater();
7117  d->m_wallet = 0L;
7118  d->m_bWalletOpened = false;
7119  }
7120  }
7121 
7122  if (!d->m_wq) {
7123  KWallet::Wallet *wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), widget() ? widget()->topLevelWidget()->winId() : 0, KWallet::Wallet::Asynchronous);
7124  d->m_wq = new KHTMLWalletQueue(this);
7125  d->m_wq->wallet = wallet;
7126  connect(wallet, SIGNAL(walletOpened(bool)), d->m_wq, SLOT(walletOpened(bool)));
7127  connect(d->m_wq, SIGNAL(walletOpened(KWallet::Wallet*)), this, SLOT(walletOpened(KWallet::Wallet*)));
7128  }
7129  d->m_wq->savers.append(qMakePair(key, data));
7130 #endif // KHTML_NO_WALLET
7131 }
7132 
7133 
7134 void KHTMLPart::dequeueWallet(DOM::HTMLFormElementImpl *form) {
7135 #ifndef KHTML_NO_WALLET
7136  KHTMLPart *p;
7137 
7138  for (p = parentPart(); p && p->parentPart(); p = p->parentPart()) {
7139  }
7140 
7141  if (p) {
7142  p->dequeueWallet(form);
7143  return;
7144  }
7145 
7146  if (d->m_wq) {
7147  d->m_wq->callers.removeAll(KHTMLWalletQueue::Caller(form, form->document()));
7148  }
7149 #endif // KHTML_NO_WALLET
7150 }
7151 
7152 
7153 void KHTMLPart::walletOpened(KWallet::Wallet *wallet) {
7154 #ifndef KHTML_NO_WALLET
7155  assert(!d->m_wallet);
7156  assert(d->m_wq);
7157 
7158  d->m_wq->deleteLater(); // safe?
7159  d->m_wq = 0L;
7160 
7161  if (!wallet) {
7162  d->m_bWalletOpened = false;
7163  return;
7164  }
7165 
7166  d->m_wallet = wallet;
7167  d->m_bWalletOpened = true;
7168  connect(d->m_wallet, SIGNAL(walletClosed()), SLOT(slotWalletClosed()));
7169  d->m_walletForms.clear();
7170  if (!d->m_statusBarWalletLabel) {
7171  d->m_statusBarWalletLabel = new KUrlLabel(d->m_statusBarExtension->statusBar());
7172  d->m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum));
7173  d->m_statusBarWalletLabel->setUseCursor(false);
7174  d->m_statusBarExtension->addStatusBarItem(d->m_statusBarWalletLabel, 0, false);
7175  d->m_statusBarWalletLabel->setPixmap(SmallIcon("wallet-open"));
7176  connect(d->m_statusBarWalletLabel, SIGNAL(leftClickedUrl()), SLOT(launchWalletManager()));
7177  connect(d->m_statusBarWalletLabel, SIGNAL(rightClickedUrl()), SLOT(walletMenu()));
7178  }
7179  d->m_statusBarWalletLabel->setToolTip(i18n("The wallet '%1' is open and being used for form data and passwords.", KWallet::Wallet::NetworkWallet()));
7180 #endif // KHTML_NO_WALLET
7181 }
7182 
7183 
7184 KWallet::Wallet *KHTMLPart::wallet()
7185 {
7186 #ifndef KHTML_NO_WALLET
7187  KHTMLPart *p;
7188 
7189  for (p = parentPart(); p && p->parentPart(); p = p->parentPart())
7190  ;
7191 
7192  if (p)
7193  return p->wallet();
7194 
7195  return d->m_wallet;
7196 #else
7197  return 0;
7198 #endif // !KHTML_NO_WALLET
7199 }
7200 
7201 
7202 void KHTMLPart::slotWalletClosed()
7203 {
7204 #ifndef KHTML_NO_WALLET
7205  if (d->m_wallet) {
7206  d->m_wallet->deleteLater();
7207  d->m_wallet = 0L;
7208  }
7209  d->m_bWalletOpened = false;
7210  if (d->m_statusBarWalletLabel) {
7211  d->m_statusBarExtension->removeStatusBarItem(d->m_statusBarWalletLabel);
7212  delete d->m_statusBarWalletLabel;
7213  d->m_statusBarWalletLabel = 0L;
7214  }
7215 #endif // KHTML_NO_WALLET
7216 }
7217 
7218 void KHTMLPart::launchWalletManager()
7219 {
7220 #ifndef KHTML_NO_WALLET
7221  QDBusInterface r("org.kde.kwalletmanager", "/kwalletmanager/MainWindow_1",
7222  "org.kde.KMainWindow");
7223  if (!r.isValid()) {
7224  KToolInvocation::startServiceByDesktopName("kwalletmanager_show");
7225  } else {
7226  r.call(QDBus::NoBlock, "show");
7227  r.call(QDBus::NoBlock, "raise");
7228  }
7229 #endif // KHTML_NO_WALLET
7230 }
7231 
7232 void KHTMLPart::walletMenu()
7233 {
7234 #ifndef KHTML_NO_WALLET
7235  KMenu *menu = new KMenu(0L);
7236  QActionGroup *menuActionGroup = new QActionGroup(menu);
7237  connect( menuActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(removeStoredPasswordForm(QAction*)) );
7238 
7239  menu->addAction(i18n("&Close Wallet"), this, SLOT(slotWalletClosed()));
7240 
7241  if (d->m_view && d->m_view->nonPasswordStorableSite(toplevelURL().host())) {
7242  menu->addAction(i18n("&Allow storing passwords for this site"), this, SLOT(delNonPasswordStorableSite()));
7243  }
7244 
7245  // List currently removable form passwords
7246  for ( QStringList::ConstIterator it = d->m_walletForms.constBegin(); it != d->m_walletForms.constEnd(); ++it ) {
7247  QAction* action = menu->addAction( i18n("Remove password for form %1", *it) );
7248  action->setActionGroup(menuActionGroup);
7249  QVariant var(*it);
7250  action->setData(var);
7251  }
7252 
7253  KAcceleratorManager::manage(menu);
7254  menu->popup(QCursor::pos());
7255 #endif // KHTML_NO_WALLET
7256 }
7257 
7258 void KHTMLPart::removeStoredPasswordForm(QAction* action)
7259 {
7260 #ifndef KHTML_NO_WALLET
7261  assert(action);
7262  assert(d->m_wallet);
7263  QVariant var(action->data());
7264 
7265  if(var.isNull() || !var.isValid() || var.type() != QVariant::String)
7266  return;
7267 
7268  QString key = var.toString();
7269  if (KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(),
7270  KWallet::Wallet::FormDataFolder(),
7271  key))
7272  return; // failed
7273 
7274 
7275  if (!d->m_wallet->hasFolder(KWallet::Wallet::FormDataFolder()))
7276  return; // failed
7277 
7278  d->m_wallet->setFolder(KWallet::Wallet::FormDataFolder());
7279  if (d->m_wallet->removeEntry(key))
7280  return; // failed
7281 
7282  d->m_walletForms.removeAll(key);
7283 #endif // KHTML_NO_WALLET
7284 }
7285 
7286 void KHTMLPart::addWalletFormKey(const QString& walletFormKey)
7287 {
7288 #ifndef KHTML_NO_WALLET
7289 
7290  if (parentPart()) {
7291  parentPart()->addWalletFormKey(walletFormKey);
7292  return;
7293  }
7294 
7295  if(!d->m_walletForms.contains(walletFormKey))
7296  d->m_walletForms.append(walletFormKey);
7297 #endif // KHTML_NO_WALLET
7298 }
7299 
7300 void KHTMLPart::delNonPasswordStorableSite()
7301 {
7302 #ifndef KHTML_NO_WALLET
7303  if (d->m_view)
7304  d->m_view->delNonPasswordStorableSite(toplevelURL().host());
7305 #endif // KHTML_NO_WALLET
7306 }
7307 void KHTMLPart::saveLoginInformation(const QString& host, const QString& key, const QMap<QString, QString>& walletMap)
7308 {
7309 #ifndef KHTML_NO_WALLET
7310  d->m_storePass.saveLoginInformation(host, key, walletMap);
7311 #endif // KHTML_NO_WALLET
7312 }
7313 
7314 void KHTMLPart::slotToggleCaretMode()
7315 {
7316  setCaretMode(d->m_paToggleCaretMode->isChecked());
7317 }
7318 
7319 void KHTMLPart::setFormNotification(KHTMLPart::FormNotification fn) {
7320  d->m_formNotification = fn;
7321 }
7322 
7323 KHTMLPart::FormNotification KHTMLPart::formNotification() const {
7324  return d->m_formNotification;
7325 }
7326 
7327 KUrl KHTMLPart::toplevelURL()
7328 {
7329  KHTMLPart* part = this;
7330  while (part->parentPart())
7331  part = part->parentPart();
7332 
7333  if (!part)
7334  return KUrl();
7335 
7336  return part->url();
7337 }
7338 
7339 bool KHTMLPart::isModified() const
7340 {
7341  if ( !d->m_doc )
7342  return false;
7343 
7344  return d->m_doc->unsubmittedFormChanges();
7345 }
7346 
7347 void KHTMLPart::setDebugScript( bool enable )
7348 {
7349  unplugActionList( "debugScriptList" );
7350  if ( enable ) {
7351  if (!d->m_paDebugScript) {
7352  d->m_paDebugScript = new KAction( i18n( "JavaScript &Debugger" ), this );
7353  actionCollection()->addAction( "debugScript", d->m_paDebugScript );
7354  connect( d->m_paDebugScript, SIGNAL(triggered(bool)), this, SLOT(slotDebugScript()) );
7355  }
7356  d->m_paDebugScript->setEnabled( d->m_frame ? d->m_frame->m_jscript : 0L );
7357  QList<QAction*> lst;
7358  lst.append( d->m_paDebugScript );
7359  plugActionList( "debugScriptList", lst );
7360  }
7361  d->m_bJScriptDebugEnabled = enable;
7362 }
7363 
7364 void KHTMLPart::setSuppressedPopupIndicator( bool enable, KHTMLPart *originPart )
7365 {
7366  if ( parentPart() ) {
7367  parentPart()->setSuppressedPopupIndicator( enable, originPart );
7368  return;
7369  }
7370 
7371  if ( enable && originPart ) {
7372  d->m_openableSuppressedPopups++;
7373  if ( d->m_suppressedPopupOriginParts.indexOf( originPart ) == -1 )
7374  d->m_suppressedPopupOriginParts.append( originPart );
7375  }
7376 
7377  if ( enable && !d->m_statusBarPopupLabel ) {
7378  d->m_statusBarPopupLabel = new KUrlLabel( d->m_statusBarExtension->statusBar() );
7379  d->m_statusBarPopupLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ));
7380  d->m_statusBarPopupLabel->setUseCursor( false );
7381  d->m_statusBarExtension->addStatusBarItem( d->m_statusBarPopupLabel, 0, false );
7382  d->m_statusBarPopupLabel->setPixmap( SmallIcon( "window-suppressed") );
7383 
7384  d->m_statusBarPopupLabel->setToolTip(i18n("This page was prevented from opening a new window via JavaScript." ) );
7385 
7386  connect(d->m_statusBarPopupLabel, SIGNAL(leftClickedUrl()), SLOT(suppressedPopupMenu()));
7387  if (d->m_settings->jsPopupBlockerPassivePopup()) {
7388  QPixmap px;
7389  px = MainBarIcon( "window-suppressed" );
7390  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);
7391  }
7392  } else if ( !enable && d->m_statusBarPopupLabel ) {
7393  d->m_statusBarPopupLabel->setToolTip("" );
7394  d->m_statusBarExtension->removeStatusBarItem( d->m_statusBarPopupLabel );
7395  delete d->m_statusBarPopupLabel;
7396  d->m_statusBarPopupLabel = 0L;
7397  }
7398 }
7399 
7400 void KHTMLPart::suppressedPopupMenu() {
7401  KMenu *m = new KMenu(0L);
7402  if ( d->m_openableSuppressedPopups )
7403  m->addAction(i18np("&Show Blocked Popup Window","&Show %1 Blocked Popup Windows", d->m_openableSuppressedPopups), this, SLOT(showSuppressedPopups()));
7404  QAction *a = m->addAction(i18n("Show Blocked Window Passive Popup &Notification"), this, SLOT(togglePopupPassivePopup()));
7405  a->setChecked(d->m_settings->jsPopupBlockerPassivePopup());
7406  m->addAction(i18n("&Configure JavaScript New Window Policies..."), this, SLOT(launchJSConfigDialog()));
7407  m->popup(QCursor::pos());
7408 }
7409 
7410 void KHTMLPart::togglePopupPassivePopup() {
7411  // Same hack as in disableJSErrorExtension()
7412  d->m_settings->setJSPopupBlockerPassivePopup( !d->m_settings->jsPopupBlockerPassivePopup() );
7413  emit configurationChanged();
7414 }
7415 
7416 void KHTMLPart::showSuppressedPopups() {
7417  foreach ( KHTMLPart* part, d->m_suppressedPopupOriginParts ) {
7418  if (part) {
7419  KJS::Window *w = KJS::Window::retrieveWindow( part );
7420  if (w) {
7421  w->showSuppressedWindows();
7422  w->forgetSuppressedWindows();
7423  }
7424  }
7425  }
7426  setSuppressedPopupIndicator( false );
7427  d->m_openableSuppressedPopups = 0;
7428  d->m_suppressedPopupOriginParts.clear();
7429 }
7430 
7431 // Extension to use for "view document source", "save as" etc.
7432 // Using the right extension can help the viewer get into the right mode (#40496)
7433 QString KHTMLPart::defaultExtension() const
7434 {
7435  if ( !d->m_doc )
7436  return ".html";
7437  if ( !d->m_doc->isHTMLDocument() )
7438  return ".xml";
7439  return d->m_doc->htmlMode() == DOM::DocumentImpl::XHtml ? ".xhtml" : ".html";
7440 }
7441 
7442 bool KHTMLPart::inProgress() const
7443 {
7444  if (!d->m_bComplete || d->m_runningScripts || (d->m_doc && d->m_doc->parsing()))
7445  return true;
7446 
7447  // Any frame that hasn't completed yet ?
7448  ConstFrameIt it = d->m_frames.constBegin();
7449  const ConstFrameIt end = d->m_frames.constEnd();
7450  for (; it != end; ++it ) {
7451  if ((*it)->m_run || !(*it)->m_bCompleted)
7452  return true;
7453  }
7454 
7455  return d->m_submitForm || !d->m_redirectURL.isEmpty() || d->m_redirectionTimer.isActive() || d->m_job;
7456 }
7457 
7458 using namespace KParts;
7459 #include "khtml_part.moc"
7460 #include "khtmlpart_p.moc"
7461 #ifndef KHTML_NO_WALLET
7462 #include "khtml_wallet_p.moc"
7463 #endif
7464 
7465 // 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 Tue Jul 16 2013 17:52:46 by doxygen 1.8.1.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.5 API Reference

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