fb3beee820b015d1160bd62db196ff15517909bb
[WebKit-https.git] / WebCore / kwq / KWQKHTMLPartImpl.mm
1 /*
2  * Copyright (C) 2001, 2002 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import <KWQKHTMLPartImpl.h>
27
28 #import <html/htmltokenizer.h>
29
30 #import <html/html_documentimpl.h>
31
32 #import <rendering/render_frames.h>
33
34 #import <khtmlview.h>
35
36 #import <khtmlpart_p.h>
37
38 #import <WCPluginWidget.h>
39 #import <WCWebDataSource.h>
40 #import <external.h>
41
42 #import <kwqdebug.h>
43
44 #undef _KWQ_TIMING
45
46 static WCIFWebDataSourceMakeFunc WCIFWebDataSourceMake;
47
48 void WCSetIFWebDataSourceMakeFunc(WCIFWebDataSourceMakeFunc func)
49 {
50     WCIFWebDataSourceMake = func;
51 }
52
53 static void recursive(const DOM::Node &pNode, const DOM::Node &node)
54 {
55     DOM::Node cur_child = node.lastChild();
56
57     KWQDEBUG("cur_child: %s = %s", cur_child.nodeName().string().latin1(), cur_child.nodeValue().string().latin1());
58
59     while(!cur_child.isNull())
60     {
61         recursive(node, cur_child);
62         cur_child = cur_child.previousSibling();
63     }
64 }
65
66 KWQKHTMLPartImpl::KWQKHTMLPartImpl(KHTMLPart *p)
67     : part(p)
68     , d(part->d)
69     , m_redirectionTimer(0)
70     , m_decodingStarted(false)
71     , m_dataSource(0)
72 {
73 }
74
75 KWQKHTMLPartImpl::~KWQKHTMLPartImpl()
76 {
77     killTimer(m_redirectionTimer);
78 }
79
80 bool KWQKHTMLPartImpl::openURLInFrame( const KURL &url, const KParts::URLArgs &urlArgs )
81 {
82   IFWebDataSource *oldDataSource, *newDataSource;
83   IFWebFrame *frame;
84
85
86   if (!urlArgs.frameName.isEmpty()) {
87     frame = [[getDataSource() controller] frameNamed: QSTRING_TO_NSSTRING(urlArgs.frameName)];
88     oldDataSource = [frame dataSource];
89   } else {
90       oldDataSource = getDataSource();
91       frame = [oldDataSource webFrame];
92   }
93
94   if (frame == nil) {
95     frame = [[getDataSource() controller] mainFrame];
96   }
97
98   newDataSource = WCIFWebDataSourceMake(url.getNSURL(), nil, 0);
99   [newDataSource _setParent: [oldDataSource parent]];
100
101   [frame setProvisionalDataSource: newDataSource];
102   [frame startLoading];
103
104   return true;
105 }
106
107 void KWQKHTMLPartImpl::openURL(const KURL &url)
108 {
109     d->m_workingURL = url;
110     part->m_url = url;
111
112     m_documentSource = "";
113     m_decodingStarted = false;
114 }
115
116 void KWQKHTMLPartImpl::slotData(NSString *encoding, const char *bytes, int length, bool complete)
117 {
118 // NOTE: This code emulates the interface used by the original khtml part  
119     QString enc;
120
121     // This flag is used to tell when a load has completed so we can be sure
122     // to process the data even if we have not yet determined the proper
123     // encoding.
124     if (complete) {
125         d->m_bComplete = true;    
126     }
127
128     if (!d->m_workingURL.isEmpty()) {
129         //begin(d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset);
130         part->begin(d->m_workingURL, 0, 0);
131
132         //d->m_doc->docLoader()->setReloading(d->m_bReloading);
133         d->m_workingURL = KURL();
134     }
135
136     if (encoding != NULL) {
137         enc = QString::fromCFString((CFStringRef) encoding);
138         part->setEncoding(enc, true);
139     }
140     
141     // FIXME [rjw]:  Remove this log eventually.  Should never happen.  For debugging
142     // purposes only.
143     if (d->m_doc == 0){
144         fprintf (stderr, "ERROR:  KHTMLPart::slotData m_doc == 0 IGNORING DATA, url = %s\n", part->m_url.url().latin1());
145         return;
146     }
147
148     part->write(bytes, length);
149 }
150
151 // FIXME: Need to remerge this with code in khtml_part.cpp?
152 void KWQKHTMLPartImpl::begin( const KURL &url, int xOffset, int yOffset )
153 {
154   KParts::URLArgs args;
155   args.xOffset = xOffset;
156   args.yOffset = yOffset;
157   d->m_extension->setURLArgs( args );
158
159   // d->m_referrer = url.url();
160   part->m_url = url;
161   KURL baseurl;
162
163   // ### not sure if XHTML documents served as text/xml should use DocumentImpl or HTMLDocumentImpl
164   if (args.serviceType == "text/xml")
165     d->m_doc = DOM::DOMImplementationImpl::instance()->createDocument( d->m_view );
166   else
167     d->m_doc = DOM::DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
168
169     //DomShared::instanceToCheck = (void *)((DomShared *)d->m_doc);
170     d->m_doc->ref();
171
172     if (m_baseURL.isEmpty()) {
173         m_baseURL = KURL();
174     }
175     else {
176         // If we get here, this means the part has received a redirect before
177         // m_doc was created. Update the document with the base URL.
178         d->m_doc->setBaseURL(m_baseURL.url());
179     }
180     d->m_workingURL = url;
181
182     /* FIXME: this is a pretty gross way to make sure the decoder gets reinitialized for each page. */
183     if (d->m_decoder != NULL) {
184         delete d->m_decoder;
185         d->m_decoder = NULL;
186     }
187
188     //FIXME: do we need this? 
189     if (!d->m_doc->attached())
190         d->m_doc->attach();
191     d->m_doc->setURL( url.url() );
192     
193     // do not set base URL if it has already been set
194     if (!d->m_workingURL.isEmpty() && m_baseURL.isEmpty())
195     {
196         // We're not planning to support the KDE chained URL feature, AFAIK
197 #if KDE_CHAINED_URIS
198         KURL::List lst = KURL::split( d->m_workingURL );
199         KURL baseurl;
200         if ( !lst.isEmpty() )
201             baseurl = *lst.begin();
202         // Use this for relative links.
203         // We prefer m_baseURL over m_url because m_url changes when we are
204         // about to load a new page.
205         setBaseURL(baseurl);
206 #else
207         setBaseURL(d->m_workingURL);
208 #endif
209     }
210
211     /* FIXME: we'll need to make this work....
212     QString userStyleSheet = KHTMLFactory::defaultHTMLSettings()->userStyleSheet();
213     if ( !userStyleSheet.isEmpty() ) {
214         setUserStyleSheet( KURL( userStyleSheet ) );
215     }
216     */
217     
218     d->m_doc->open();    
219
220     d->m_doc->setParsing(true);
221
222 #ifdef _KWQ_TIMING        
223     d->totalWriteTime = 0;
224 #endif
225 }
226
227 // FIXME: Need to remerge this with code in khtml_part.cpp?
228 void KWQKHTMLPartImpl::write( const char *str, int len )
229 {
230     /* FIXME: hook this code back when we have decoders completely working */
231 #if 0
232   if(d->m_bFirstData) {
233       // determine the parse mode
234       d->m_doc->determineParseMode( decoded );
235       d->m_bFirstData = false;
236     
237   //kdDebug(6050) << "KHTMLPart::write haveEnc = " << d->m_haveEncoding << endl;
238       // ### this is still quite hacky, but should work a lot better than the old solution
239       if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
240
241       if (!d->m_haveCharset)
242         {
243             const QTextCodec *c = d->m_decoder->codec();
244             //kdDebug(6005) << "setting up charset to " << (int) KGlobal::charsets()->charsetForEncoding(c->name()) << endl;
245             d->m_charset = KGlobal::charsets()->charsetForEncoding(c->name());
246             d->m_settings->setCharset( d->m_charset );
247             d->m_settings->setScript( KGlobal::charsets()->charsetForEncoding(c->name(), true ));
248             //kdDebug(6005) << "charset is " << (int)d->m_settings->charset() << endl;
249         }
250         d->m_doc->applyChanges(true, true);
251     }
252 #endif
253
254     // begin lines added in lieu of big fixme    
255     if ( !d->m_decoder ) {
256         d->m_decoder = new khtml::Decoder();
257         if(!d->m_encoding.isNull())
258             d->m_decoder->setEncoding(d->m_encoding.latin1(), d->m_haveEncoding);
259         else {
260             //FIXME: d->m_decoder->setEncoding(settings()->encoding().latin1(), d->m_haveEncoding);
261         }
262     }
263     if ( len == 0 )
264         return;
265     
266     if ( len == -1 )
267         len = strlen( str );
268     
269 #ifdef _KWQ_TIMING        
270     double start = CFAbsoluteTimeGetCurrent();
271 #endif
272     
273     // FIX ME:  This is very expensive.  We should using the IFMutableData
274     // that represents the document, and only constructing the complete
275     // string when requested.
276     m_documentSource += QString(str, len);
277
278     QString decoded;
279     if (m_decodingStarted)
280         decoded = d->m_decoder->decode( str, len );
281     else    
282         decoded = d->m_decoder->decode( m_documentSource, m_documentSource.length() );
283
284     if(decoded.isEmpty()){
285         // Check flag to tell whether the load has completed.
286         // If we get here, it means that no text encoding was available.
287         // Try to process what we have with the default encoding.
288         if (d->m_bComplete) {
289             decoded = m_documentSource;
290         }
291         else {
292             fprintf (stderr, "WARNING:  DECODER unable to decode string, length = %d, total length = %d\n", len, m_documentSource.length());
293             return;
294         }
295     }
296
297     m_decodingStarted = true;
298         
299     // Transition from provisional to committed data source at this point.
300     
301 #if FIGURE_OUT_WHAT_APPLY_CHANGES_DOES
302     d->m_doc->applyChanges();
303 #endif    
304
305     // end lines added in lieu of big fixme
306     
307     if (part->jScript())
308         part->jScript()->appendSourceFile(part->m_url.url(),decoded);
309     Tokenizer* t = d->m_doc->tokenizer();
310     if(t)
311         t->write( decoded, true );
312
313 #ifdef _KWQ_TIMING        
314     double thisTime = CFAbsoluteTimeGetCurrent() - start;
315     d->totalWriteTime += thisTime;
316     KWQDEBUGLEVEL (0x200, "%s bytes = %d, seconds = %f, total = %f\n", part->m_url.url().latin1(), len, thisTime, d->totalWriteTime);
317 #endif
318 }
319
320 // FIXME: Need to remerge this with code in khtml_part.cpp?
321 void KWQKHTMLPartImpl::end()
322 {
323     // FIXME [rjw]:  Remove this log eventually.  Should never happen.  For debugging
324     // purposes only.
325     if (d->m_doc == 0){
326         fprintf (stderr, "ERROR:  KHTMLPart::end  m_doc == 0\n");
327         return;
328     }
329
330     d->m_doc->setParsing(false);
331
332     d->m_doc->close();
333     KURL::clearCaches();
334     
335     d->m_view->complete();
336 }
337  
338 bool KWQKHTMLPartImpl::gotoBaseAnchor()
339 {
340     if ( !part->m_url.ref().isEmpty() )
341         return part->gotoAnchor( part->m_url.ref() );
342     return false;
343 }
344
345 // FIXME: Need to remerge this with code in khtml_part.cpp?
346 void KWQKHTMLPartImpl::scheduleRedirection(int delay, const QString &url)
347 {
348     if( d->m_redirectURL.isEmpty() || delay < d->m_delayRedirect )
349     {
350         if (delay < 1) {
351             delay = 1;
352         }
353         d->m_delayRedirect = delay;
354         d->m_redirectURL = url;
355         killTimer(m_redirectionTimer);
356         m_redirectionTimer = startTimer(1000 * d->m_delayRedirect);
357     }
358 }
359
360 void KWQKHTMLPartImpl::timerEvent(QTimerEvent *e)
361 {
362     if (e->timerId()==m_redirectionTimer)
363     {
364         redirectURL();
365         return;
366     }
367 }
368
369 void KWQKHTMLPartImpl::redirectURL()
370 {
371   QString u = d->m_redirectURL;
372   d->m_delayRedirect = 0;
373   d->m_redirectURL = QString::null;
374   if ( u.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
375   {
376     QString script = KURL::decode_string( u.right( u.length() - 11 ) );
377     //kdDebug( 6050 ) << "KHTMLPart::slotRedirect script=" << script << endl;
378     QVariant res = part->executeScript( script );
379     if ( res.type() == QVariant::String ) {
380       part->begin( part->url() );
381       part->write( res.asString() );
382       part->end();
383     }
384     return;
385   }
386
387   KParts::URLArgs args;
388 #if 0
389   if ( urlcmp( u, m_url.url(), true, true ) )
390     args.reload = true;
391
392   args.setLockHistory( true );
393 #endif
394   part->urlSelected( u, 0, 0, QString::null, args );
395 }
396
397
398
399 void KWQKHTMLPartImpl::urlSelected( const QString &url, int button, int state, const QString &_target, KParts::URLArgs )
400 {
401     IFWebDataSource *oldDataSource, *newDataSource;
402     KURL clickedURL(part->completeURL( url));
403     IFWebFrame *frame, *currentFrame;
404     KURL refLess(clickedURL);
405         
406     if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
407     {
408         part->executeScript( url.right( url.length() - 11) );
409         return;
410     }
411
412     // Open new window on command-click
413     if (state & MetaButton) {
414         [[getDataSource() controller] openNewWindowWithURL:clickedURL.getNSURL()];
415         return;
416     }
417
418     part->m_url.setRef ("");
419     refLess.setRef ("");
420     if (refLess.url() == part->m_url.url()){
421         part->m_url = clickedURL;
422         part->gotoAnchor (clickedURL.ref());
423         return;
424     }
425     
426     oldDataSource = getDataSource();
427     currentFrame = [oldDataSource webFrame];
428     if (_target.isEmpty()){
429         // If we're the only frame in a frameset then pop
430         // the frame.
431         if ([[[oldDataSource parent] children] count] == 1){
432             frame = [[oldDataSource parent] webFrame];
433         }
434         else
435             frame = currentFrame;
436     }
437     else {
438         frame = [currentFrame frameNamed: QSTRING_TO_NSSTRING(_target)];
439         if (frame == nil){
440             // FIXME:  What is the correct behavior here?
441             NSLog (@"ERROR:  unable to find frame named %@\n",
442                         QSTRING_TO_NSSTRING(_target));
443             return;
444         }
445         oldDataSource = [frame dataSource];
446     }
447     
448     newDataSource = WCIFWebDataSourceMake(clickedURL.getNSURL(), nil, 0);
449     [newDataSource _setParent: [oldDataSource parent]];
450     
451     [frame setProvisionalDataSource: newDataSource];
452     [frame startLoading];
453 }
454
455 bool KWQKHTMLPartImpl::requestFrame( khtml::RenderPart *frame, const QString &url, const QString &frameName,
456                                      const QStringList &params, bool isIFrame )
457 {
458     NSString *nsframeName = QSTRING_TO_NSSTRING(frameName);
459     IFWebFrame *aFrame;
460     IFWebDataSource *dataSource;
461     
462     dataSource = getDataSource();
463
464     KWQDEBUGLEVEL (KWQ_LOG_FRAMES, "name %s\n", [nsframeName cString]);
465     aFrame =[dataSource frameNamed: nsframeName];
466     if (aFrame){
467         KWQDEBUGLEVEL (KWQ_LOG_FRAMES, "found %s\n", [nsframeName cString]);
468         QWidget *khtmlview = [[[aFrame webView] documentView] _provisionalWidget];
469         if (khtmlview)
470             frame->setWidget (khtmlview);
471         else
472             frame->setWidget ([[[aFrame webView] documentView] _widget]);
473     }
474     else {        
475         KWQDEBUGLEVEL (KWQ_LOG_FRAMES, "creating %s\n", [nsframeName cString]);
476         IFWebDataSource *oldDataSource, *newDataSource;
477         NSURL *childURL;
478         IFWebFrame *newFrame;
479         IFWebController *controller;
480         HTMLIFrameElementImpl *o = static_cast<HTMLIFrameElementImpl *>(frame->element());
481                 
482         childURL = part->completeURL(url).getNSURL();
483         if (childURL == nil || [childURL path] == nil) {
484             NSLog (@"ERROR (probably need to fix CFURL): unable to create URL with path");
485             return false;
486         }
487         
488         oldDataSource = getDataSource();
489         controller = [oldDataSource controller];
490         newFrame = [controller createFrameNamed: nsframeName for: nil inParent: oldDataSource inScrollView: o->scrollingMode() != QScrollView::AlwaysOff];
491         if (newFrame == nil) {
492             // Controller return NO to location change, now what?
493             return false;
494         }
495         [newFrame _setRenderFramePart: frame];
496         
497         newDataSource = WCIFWebDataSourceMake(childURL, nil, 0);
498         [newDataSource _setParent: oldDataSource];
499         [newFrame setProvisionalDataSource: newDataSource];
500     
501         
502         [[newFrame webView] _setMarginWidth: o->getMarginWidth()];
503         [[newFrame webView] _setMarginHeight: o->getMarginHeight()];
504
505         [newFrame startLoading];
506     }
507
508 #ifdef _SUPPORT_JAVASCRIPT_URL_    
509     if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 && !isIFrame )
510     {
511         // static cast is safe as of isIFrame being false.
512         // but: shouldn't we support this javascript hack for iframes aswell?
513         khtml::RenderFrame* rf = static_cast<khtml::RenderFrame*>(frame);
514         assert(rf);
515         QVariant res = executeScript( DOM::Node(rf->frameImpl()), url.right( url.length() - 11) );
516         if ( res.type() == QVariant::String ) {
517             KURL myurl;
518             myurl.setProtocol("javascript");
519             myurl.setPath(res.asString());
520             return processObjectRequest(&(*it), myurl, QString("text/html") );
521         }
522         return false;
523     }
524 #endif
525
526
527     return true;
528 }
529
530 bool KWQKHTMLPartImpl::requestObject( khtml::RenderPart *frame, const QString &url, const QString &serviceType,
531                                       const QStringList &args )
532 {
533   if (url.isEmpty()) {
534     return false;
535   }
536   if (!frame->widget()) {
537     frame->setWidget(IFPluginWidgetCreate(part->completeURL(url).url(), serviceType, args, m_baseURL.url()));
538   }
539   return true;
540 }
541
542 void KWQKHTMLPartImpl::submitForm( const char *action, const QString &url, const QByteArray &formData, const QString &_target, const QString& contentType, const QString& boundary )
543 {
544   QString target = _target;
545   
546   //if ( target.isEmpty() )
547   //  target = d->m_baseTarget;
548
549   KURL u = part->completeURL( url );
550
551   if ( u.isMalformed() )
552   {
553     // ### ERROR HANDLING!
554     return;
555   }
556
557   QString urlstring = u.url();
558
559   if ( urlstring.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
560     urlstring = KURL::decode_string(urlstring);
561     part->executeScript( urlstring.right( urlstring.length() - 11) );
562     return;
563   }
564
565 #ifdef NEED_THIS
566   if (!checkLinkSecurity(u,
567                          i18n( "<qt>The form will be submitted to <BR><B>%1</B><BR>on your local filesystem.<BR>Do you want to submit the form?" ),
568                          i18n( "Submit" )))
569     return;
570 #endif
571
572   NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
573   unsigned loadFlags = 0;
574
575 #ifdef NEED_THIS
576   KParts::URLArgs args;
577
578   if (!d->m_referrer.isEmpty())
579      args.metaData()["referrer"] = d->m_referrer;
580
581   args.metaData().insert("main_frame_request",
582                          parentPart() == 0 ? "TRUE":"FALSE");
583   args.metaData().insert("ssl_was_in_use", d->m_ssl_in_use ? "TRUE":"FALSE");
584   args.metaData().insert("ssl_activate_warnings", "TRUE");
585   args.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
586 #endif
587
588   if ( strcmp( action, "get" ) == 0 )
589   {
590     u.setQuery( QString( formData.data(), formData.size() ) );
591     [attributes setObject:@"GET" forKey:IFHTTPURLHandleRequestMethod];
592
593 #ifdef NEED_THIS
594     args.frameName = target;
595     args.setDoPost( false );
596 #endif
597   }
598   else
599   {
600 #ifdef NEED_THIS
601     args.postData = formData;
602     args.frameName = target;
603     args.setDoPost( true );
604
605     // construct some user headers if necessary
606     if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
607       args.setContentType( "Content-Type: application/x-www-form-urlencoded" );
608     else // contentType must be "multipart/form-data"
609       args.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
610 #endif
611       NSData *postData = [NSData dataWithBytes:formData.data() length:formData.size()];
612       [attributes setObject:postData forKey:IFHTTPURLHandleRequestData];
613       [attributes setObject:@"POST" forKey:IFHTTPURLHandleRequestMethod];
614       // When posting, use the IFURLHandleFlagLoadFromOrigin load flag. 
615       // This prevents a potential bug which may cause a page
616       // with a form that uses itself as an action to be returned 
617       // from the cache without submitting.
618       loadFlags = IFURLHandleFlagLoadFromOrigin;
619   }
620
621 #ifdef NEED_THIS
622   if ( d->m_bParsing || d->m_runningScripts > 0 ) {
623     if( d->m_submitForm ) {
624         return;
625     }
626     d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
627     d->m_submitForm->submitAction = action;
628     d->m_submitForm->submitUrl = url;
629     d->m_submitForm->submitFormData = formData;
630     d->m_submitForm->target = _target;
631     d->m_submitForm->submitContentType = contentType;
632     d->m_submitForm->submitBoundary = boundary;
633     connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
634   }
635   else
636     emit d->m_extension->openURLRequest( u, args );
637 #endif
638     IFWebDataSource *oldDataSource, *newDataSource;
639     IFWebFrame *frame;
640     
641     oldDataSource = getDataSource();
642     frame = [oldDataSource webFrame];
643
644     newDataSource = WCIFWebDataSourceMake(u.getNSURL(), attributes, loadFlags);
645     [newDataSource _setParent: [oldDataSource parent]];
646     
647     [frame setProvisionalDataSource: newDataSource];
648     [frame startLoading];
649 }
650
651 bool KWQKHTMLPartImpl::frameExists( const QString &frameName )
652 {
653     return [getDataSource() frameExists: (NSString *)frameName.getCFMutableString()];
654 }
655
656 QPtrList<KParts::ReadOnlyPart> KWQKHTMLPartImpl::frames() const
657 {
658     QPtrList<KParts::ReadOnlyPart> res;
659     IFWebDataSource *thisDataSource = ((KWQKHTMLPartImpl *)this)->getDataSource();
660     NSArray *children = [thisDataSource children];
661     IFWebFrame *aFrame;
662     unsigned int i;
663     
664     for (i = 0; i < [children count]; i++){
665         aFrame = [children objectAtIndex: i];
666         res.append( [[[aFrame dataSource] representation] part] );
667     }
668     return res;
669 }
670
671 QString KWQKHTMLPartImpl::documentSource() const
672 {
673     return m_documentSource;
674 }
675
676 void KWQKHTMLPartImpl::setBaseURL(const KURL &url)
677 {
678     m_baseURL = url;
679     if (m_baseURL.protocol().startsWith( "http" ) && !m_baseURL.host().isEmpty() && m_baseURL.path().isEmpty()) {
680         m_baseURL.setPath( "/" );
681         // communicate the change in base URL to the document so that links and subloads work
682         if (d->m_doc) {
683             d->m_doc->setBaseURL(url.url());
684         }
685     }
686 }
687
688 void KWQKHTMLPartImpl::setView(KHTMLView *view)
689 {
690     d->m_view = view;
691 }
692
693 void KWQKHTMLPartImpl::setTitle(const DOMString &title)
694 {
695     [getDataSource() _setTitle:title.string().getNSString()];
696 }
697
698 void KWQKHTMLPartImpl::setDataSource(IFWebDataSource *dataSource)
699 {
700     m_dataSource = dataSource; // not retained
701 }
702
703 IFWebDataSource *KWQKHTMLPartImpl::getDataSource()
704 {
705     return m_dataSource;
706 }
707
708
709 KHTMLPart *KWQKHTMLPartImpl::parentPart()
710 {
711     IFWebDataSource *parent, *dataSource = getDataSource();
712     
713     parent = [dataSource parent];
714     return [[parent representation] part];
715 }