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

KHTML

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

KDE's Doxygen guidelines are available online.

KHTML

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

kdelibs-4.10.2 API Reference

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