7c1c4ed895e548d584acfbf94ba90ca06ac904b8
[WebKit-https.git] / WebKit / gtk / WebCoreSupport / FrameLoaderClientGtk.cpp
1 /*
2  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
3  * Copyright (C) 2007 Holger Hans Peter Freyther
4  * Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "config.h"
22 #include "FrameLoaderClientGtk.h"
23
24 #include "DocumentLoader.h"
25 #include "FrameLoader.h"
26 #include "FrameView.h"
27 #include "FrameTree.h"
28 #include "HTMLFormElement.h"
29 #include "HTMLFrameElement.h"
30 #include "HTMLFrameOwnerElement.h"
31 #include "HTMLNames.h"
32 #include "Language.h"
33 #include "MIMETypeRegistry.h"
34 #include "NotImplemented.h"
35 #include "PlatformString.h"
36 #include "ResourceRequest.h"
37 #include "CString.h"
38 #include "ProgressTracker.h"
39 #include "kjs_binding.h"
40 #include "kjs_proxy.h"
41 #include "kjs_window.h"
42 #include "webkitwebview.h"
43 #include "webkitwebframe.h"
44 #include "webkitprivate.h"
45
46 #include <JavaScriptCore/APICast.h>
47 #include <stdio.h>
48 #if PLATFORM(UNIX)
49 #include <sys/utsname.h>
50 #endif
51
52 using namespace WebCore;
53
54 namespace WebKit {
55
56 FrameLoaderClient::FrameLoaderClient(WebKitWebFrame* frame)
57     : m_frame(frame)
58     , m_userAgent("")
59 {
60     ASSERT(m_frame);
61 }
62
63 static String agentPlatform()
64 {
65 #ifdef GDK_WINDOWING_X11
66     return "X11";
67 #elif defined(GDK_WINDOWING_WIN32)
68     return "Windows";
69 #elif defined(GDK_WINDOWING_QUARTZ)
70     return "Macintosh";
71 #elif defined(GDK_WINDOWING_DIRECTFB)
72     return "DirectFB";
73 #else
74     notImplemented();
75     return "Unknown";
76 #endif
77 }
78
79 static String agentOS()
80 {
81 #if PLATFORM(DARWIN)
82 #if PLATFORM(X86)
83     return "Intel Mac OS X";
84 #else
85     return "PPC Mac OS X";
86 #endif
87 #elif PLATFORM(UNIX)
88     struct utsname name;
89     if (uname(&name) != -1)
90         return String::format("%s %s", name.sysname, name.machine);
91     else
92         return "Unknown";
93 #elif PLATFORM(WIN_OS)
94     // FIXME: Compute the Windows version
95     return "Windows";
96 #else
97     notImplemented();
98     return "Unknown";
99 #endif
100 }
101
102 static String composeUserAgent()
103 {
104     // This is a liberal interpretation of http://www.mozilla.org/build/revised-user-agent-strings.html
105     // See also http://developer.apple.com/internet/safari/faq.html#anchor2
106
107     String ua;
108
109     // Product
110     ua += "Mozilla/5.0";
111
112     // Comment
113     ua += " (";
114     ua += agentPlatform(); // Platform
115     ua += "; U; "; // Security
116     ua += agentOS(); // OS-or-CPU
117     ua += "; ";
118     ua += defaultLanguage(); // Localization information
119     ua += ") ";
120
121     // WebKit Product
122     // FIXME: The WebKit version is hardcoded
123     static const String webKitVersion = "525.1+";
124     ua += "AppleWebKit/" + webKitVersion;
125     ua += " (KHTML, like Gecko, ";
126     // We mention Safari since many broken sites check for it (OmniWeb does this too)
127     // We re-use the WebKit version, though it doesn't seem to matter much in practice
128     ua += "Safari/" + webKitVersion;
129     ua += ") ";
130
131     // Vendor Product
132     ua += g_get_prgname();
133
134     return ua;
135 }
136
137 String FrameLoaderClient::userAgent(const KURL&)
138 {
139     if (m_userAgent.isEmpty())
140         m_userAgent = composeUserAgent();
141
142     return m_userAgent;
143 }
144
145 WTF::PassRefPtr<WebCore::DocumentLoader> FrameLoaderClient::createDocumentLoader(const WebCore::ResourceRequest& request, const SubstituteData& substituteData)
146 {
147     RefPtr<DocumentLoader> loader = new DocumentLoader(request, substituteData);
148     return loader.release();
149 }
150
151 void FrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction policyFunction,  PassRefPtr<FormState>)
152 {
153     // FIXME: This is surely too simple
154     ASSERT(policyFunction);
155     if (!policyFunction)
156         return;
157     (core(m_frame)->loader()->*policyFunction)(PolicyUse);
158 }
159
160
161 void FrameLoaderClient::committedLoad(DocumentLoader* loader, const char* data, int length)
162 {
163     FrameLoader *fl = loader->frameLoader();
164     fl->setEncoding(m_response.textEncodingName(), false);
165     fl->addData(data, length);
166 }
167
168 void FrameLoaderClient::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long  identifier, const AuthenticationChallenge&)
169 {
170     notImplemented();
171 }
172
173 void FrameLoaderClient::dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long  identifier, const AuthenticationChallenge&)
174 {
175     notImplemented();
176 }
177
178 void FrameLoaderClient::dispatchWillSendRequest(DocumentLoader*, unsigned long, ResourceRequest&, const ResourceResponse&)
179 {
180     notImplemented();
181 }
182
183 void FrameLoaderClient::assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&)
184 {
185     notImplemented();
186 }
187
188 void FrameLoaderClient::postProgressStartedNotification()
189 {
190     WebKitWebView* page = getViewFromFrame(m_frame);
191     g_signal_emit_by_name(page, "load-started", m_frame);
192 }
193
194 void FrameLoaderClient::postProgressEstimateChangedNotification()
195 {
196     WebKitWebView* kitPage = getViewFromFrame(m_frame);
197     Page* corePage = core(kitPage);
198
199     g_signal_emit_by_name(kitPage, "load-progress-changed", lround(corePage->progress()->estimatedProgress()*100));
200 }
201
202 void FrameLoaderClient::postProgressFinishedNotification()
203 {
204     WebKitWebView* page = getViewFromFrame(m_frame);
205
206     g_signal_emit_by_name(page, "load-finished", m_frame);
207 }
208
209 void FrameLoaderClient::frameLoaderDestroyed()
210 {
211     m_frame = 0;
212     delete this;
213 }
214
215 void FrameLoaderClient::dispatchDidReceiveResponse(DocumentLoader*, unsigned long, const ResourceResponse& response)
216 {
217     m_response = response;
218 }
219
220 void FrameLoaderClient::dispatchDecidePolicyForMIMEType(FramePolicyFunction policyFunction, const String&, const ResourceRequest&)
221 {
222     // FIXME: we need to call directly here (comment copied from Qt version)
223     ASSERT(policyFunction);
224     if (!policyFunction)
225         return;
226     (core(m_frame)->loader()->*policyFunction)(PolicyUse);
227 }
228
229 void FrameLoaderClient::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction policyFunction, const NavigationAction&, const ResourceRequest&, const String&)
230 {
231     ASSERT(policyFunction);
232     if (!policyFunction)
233         return;
234     // FIXME: I think Qt version marshals this to another thread so when we
235     // have multi-threaded download, we might need to do the same
236     (core(m_frame)->loader()->*policyFunction)(PolicyIgnore);
237 }
238
239 void FrameLoaderClient::dispatchDecidePolicyForNavigationAction(FramePolicyFunction policyFunction, const NavigationAction& action, const ResourceRequest& resourceRequest)
240 {
241     ASSERT(policyFunction);
242     if (!policyFunction)
243         return;
244
245     WebKitWebView* page = getViewFromFrame(m_frame);
246     WebKitNetworkRequest* request = webkit_network_request_new(resourceRequest.url().string().utf8().data());
247     WebKitNavigationResponse response;
248
249     g_signal_emit_by_name(page, "navigation-requested", m_frame, request, &response);
250
251     g_object_unref(request);
252
253     if (response == WEBKIT_NAVIGATION_RESPONSE_IGNORE) {
254         (core(m_frame)->loader()->*policyFunction)(PolicyIgnore);
255         return;
256     }
257
258     (core(m_frame)->loader()->*policyFunction)(PolicyUse);
259 }
260
261 Widget* FrameLoaderClient::createPlugin(const IntSize&, Element*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool)
262 {
263     notImplemented();
264     return 0;
265 }
266
267 PassRefPtr<Frame> FrameLoaderClient::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
268                                                  const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
269 {
270     Frame* coreFrame = core(webFrame());
271
272     ASSERT(core(getViewFromFrame(webFrame())) == coreFrame->page());
273     WebKitWebFrame* gtkFrame = WEBKIT_WEB_FRAME(webkit_web_frame_init_with_web_view(getViewFromFrame(webFrame()), ownerElement));
274     RefPtr<Frame> childFrame(adoptRef(core(gtkFrame)));
275
276     coreFrame->tree()->appendChild(childFrame);
277
278     childFrame->tree()->setName(name);
279     childFrame->init();
280     childFrame->loader()->load(url, referrer, FrameLoadTypeRedirectWithLockedHistory, String(), 0, 0);
281
282     // The frame's onload handler may have removed it from the document.
283     if (!childFrame->tree()->parent())
284         return 0;
285
286     // Propagate the marginwidth/height and scrolling modes to the view.
287     if (ownerElement->hasTagName(HTMLNames::frameTag) || ownerElement->hasTagName(HTMLNames::iframeTag)) {
288         HTMLFrameElement* frameElt = static_cast<HTMLFrameElement*>(ownerElement);
289         if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
290             childFrame->view()->setScrollbarsMode(ScrollbarAlwaysOff);
291         int marginWidth = frameElt->getMarginWidth();
292         int marginHeight = frameElt->getMarginHeight();
293         if (marginWidth != -1)
294             childFrame->view()->setMarginWidth(marginWidth);
295         if (marginHeight != -1)
296             childFrame->view()->setMarginHeight(marginHeight);
297     }
298
299     return childFrame.release();
300 }
301
302 void FrameLoaderClient::redirectDataToPlugin(Widget* pluginWidget)
303 {
304     notImplemented();
305     return;
306 }
307
308 Widget* FrameLoaderClient::createJavaAppletWidget(const IntSize&, Element*, const KURL& baseURL,
309                                                   const Vector<String>& paramNames, const Vector<String>& paramValues)
310 {
311     notImplemented();
312     return 0;
313 }
314
315 ObjectContentType FrameLoaderClient::objectContentType(const KURL& url, const String& mimeType)
316 {
317     String type = mimeType;
318     if (type.isEmpty())
319         type = MIMETypeRegistry::getMIMETypeForExtension(url.path().mid(url.path().findRev('.') + 1));
320
321     if (type.isEmpty())
322         return WebCore::ObjectContentFrame;
323
324     if (MIMETypeRegistry::isSupportedImageMIMEType(type))
325         return WebCore::ObjectContentImage;
326
327     if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
328         return WebCore::ObjectContentFrame;
329
330     return WebCore::ObjectContentNone;
331 }
332
333 String FrameLoaderClient::overrideMediaType() const
334 {
335     notImplemented();
336     return String();
337 }
338
339 void FrameLoaderClient::windowObjectCleared()
340 {
341     // Is this obsolete now?
342     g_signal_emit_by_name(m_frame, "cleared");
343
344     Frame* coreFrame = core(webFrame());
345     ASSERT(coreFrame);
346
347     Settings* settings = coreFrame->settings();
348     if (!settings || !settings->isJavaScriptEnabled())
349         return;
350
351     // TODO: Consider using g_signal_has_handler_pending() to avoid the overhead
352     // when there are no handlers.
353     JSGlobalContextRef context = toGlobalRef(coreFrame->scriptProxy()->globalObject()->globalExec());
354     JSObjectRef windowObject = toRef(KJS::Window::retrieve(coreFrame)->getObject());
355     ASSERT(windowObject);
356
357     WebKitWebView* page = getViewFromFrame(m_frame);
358     g_signal_emit_by_name(page, "window-object-cleared", m_frame, context, windowObject);
359
360     // TODO: Re-attach debug clients if present.
361     // The Win port has an example of how we might do this.
362 }
363
364 void FrameLoaderClient::didPerformFirstNavigation() const
365 {
366 }
367
368 void FrameLoaderClient::registerForIconNotification(bool)
369 {
370     notImplemented();
371 }
372
373 void FrameLoaderClient::setMainFrameDocumentReady(bool)
374 {
375     // this is only interesting once we provide an external API for the DOM
376 }
377
378 bool FrameLoaderClient::hasWebView() const
379 {
380     notImplemented();
381     return true;
382 }
383
384 bool FrameLoaderClient::hasFrameView() const
385 {
386     notImplemented();
387     return true;
388 }
389
390 void FrameLoaderClient::dispatchDidFinishLoad()
391 {
392     g_signal_emit_by_name(m_frame, "load-done", true);
393 }
394
395 void FrameLoaderClient::frameLoadCompleted()
396 {
397     notImplemented();
398 }
399
400 void FrameLoaderClient::saveViewStateToItem(HistoryItem*)
401 {
402     notImplemented();
403 }
404
405 void FrameLoaderClient::restoreViewState()
406 {
407     notImplemented();
408 }
409
410 bool FrameLoaderClient::shouldGoToHistoryItem(HistoryItem* item) const
411 {
412     // FIXME: This is a very simple implementation. More sophisticated
413     // implementation would delegate the decision to a PolicyDelegate.
414     // See mac implementation for example.
415     return item != 0;
416 }
417
418 void FrameLoaderClient::makeRepresentation(DocumentLoader*)
419 {
420     notImplemented();
421 }
422
423 void FrameLoaderClient::forceLayout()
424 {
425     notImplemented();
426 }
427
428 void FrameLoaderClient::forceLayoutForNonHTML()
429 {
430     notImplemented();
431 }
432
433 void FrameLoaderClient::setCopiesOnScroll()
434 {
435     notImplemented();
436 }
437
438 void FrameLoaderClient::detachedFromParent1()
439 {
440     notImplemented();
441 }
442
443 void FrameLoaderClient::detachedFromParent2()
444 {
445     notImplemented();
446 }
447
448 void FrameLoaderClient::detachedFromParent3()
449 {
450     notImplemented();
451 }
452
453 void FrameLoaderClient::detachedFromParent4()
454 {
455     notImplemented();
456 }
457
458 void FrameLoaderClient::loadedFromCachedPage()
459 {
460     notImplemented();
461 }
462
463 void FrameLoaderClient::dispatchDidHandleOnloadEvents()
464 {
465     notImplemented();
466 }
467
468 void FrameLoaderClient::dispatchDidReceiveServerRedirectForProvisionalLoad()
469 {
470     notImplemented();
471 }
472
473 void FrameLoaderClient::dispatchDidCancelClientRedirect()
474 {
475     notImplemented();
476 }
477
478 void FrameLoaderClient::dispatchWillPerformClientRedirect(const KURL&, double, double)
479 {
480     notImplemented();
481 }
482
483 void FrameLoaderClient::dispatchDidChangeLocationWithinPage()
484 {
485     notImplemented();
486 }
487
488 void FrameLoaderClient::dispatchWillClose()
489 {
490     notImplemented();
491 }
492
493 void FrameLoaderClient::dispatchDidReceiveIcon()
494 {
495     WebKitWebView* page = getViewFromFrame(m_frame);
496
497     g_signal_emit_by_name(page, "icon-loaded", m_frame);
498 }
499
500 void FrameLoaderClient::dispatchDidStartProvisionalLoad()
501 {
502 }
503
504 void FrameLoaderClient::dispatchDidReceiveTitle(const String& title)
505 {
506     notImplemented();
507 }
508
509
510 void FrameLoaderClient::dispatchDidCommitLoad()
511 {
512     notImplemented();
513 }
514
515 void FrameLoaderClient::dispatchDidFinishDocumentLoad()
516 {
517     notImplemented();
518 }
519
520 void FrameLoaderClient::dispatchDidFirstLayout()
521 {
522     notImplemented();
523 }
524
525 void FrameLoaderClient::dispatchShow()
526 {
527     notImplemented();
528 }
529
530 void FrameLoaderClient::cancelPolicyCheck()
531 {
532     notImplemented();
533 }
534
535 void FrameLoaderClient::dispatchDidLoadMainResource(DocumentLoader*)
536 {
537     notImplemented();
538 }
539
540 void FrameLoaderClient::revertToProvisionalState(DocumentLoader*)
541 {
542     notImplemented();
543 }
544
545 void FrameLoaderClient::clearUnarchivingState(DocumentLoader*)
546 {
547     notImplemented();
548 }
549
550 void FrameLoaderClient::willChangeTitle(DocumentLoader*)
551 {
552     notImplemented();
553 }
554
555 void FrameLoaderClient::didChangeTitle(DocumentLoader *l)
556 {
557     setTitle(l->title(), l->url());
558 }
559
560 void FrameLoaderClient::finalSetupForReplace(DocumentLoader*)
561 {
562     notImplemented();
563 }
564
565 void FrameLoaderClient::setDefersLoading(bool)
566 {
567     notImplemented();
568 }
569
570 bool FrameLoaderClient::isArchiveLoadPending(ResourceLoader*) const
571 {
572     notImplemented();
573     return false;
574 }
575
576 void FrameLoaderClient::cancelPendingArchiveLoad(ResourceLoader*)
577 {
578     notImplemented();
579 }
580
581 void FrameLoaderClient::clearArchivedResources()
582 {
583     notImplemented();
584 }
585
586 bool FrameLoaderClient::canHandleRequest(const ResourceRequest&) const
587 {
588     notImplemented();
589     return true;
590 }
591
592 bool FrameLoaderClient::canShowMIMEType(const String&) const
593 {
594     notImplemented();
595     return true;
596 }
597
598 bool FrameLoaderClient::representationExistsForURLScheme(const String&) const
599 {
600     notImplemented();
601     return false;
602 }
603
604 String FrameLoaderClient::generatedMIMETypeForURLScheme(const String&) const
605 {
606     notImplemented();
607     return String();
608 }
609
610 void FrameLoaderClient::finishedLoading(DocumentLoader* documentLoader)
611 {
612     ASSERT(documentLoader->frame());
613     // Setting the encoding on the frame loader is our way to get work done that is normally done
614     // when the first bit of data is received, even for the case of a document with no data (like about:blank).
615     String encoding = documentLoader->overrideEncoding();
616     bool userChosen = !encoding.isNull();
617     if (encoding.isNull())
618         encoding = documentLoader->response().textEncodingName();
619     documentLoader->frameLoader()->setEncoding(encoding, userChosen);
620 }
621
622
623 void FrameLoaderClient::provisionalLoadStarted()
624 {
625     notImplemented();
626 }
627
628 void FrameLoaderClient::didFinishLoad() {
629     notImplemented();
630 }
631
632 void FrameLoaderClient::prepareForDataSourceReplacement() { notImplemented(); }
633
634 void FrameLoaderClient::setTitle(const String& title, const KURL& url)
635 {
636     WebKitWebView* page = getViewFromFrame(m_frame);
637
638     CString titleString = title.utf8();
639     DeprecatedCString urlString = url.prettyURL().utf8();
640     g_signal_emit_by_name(m_frame, "title-changed", titleString.data(), urlString.data());
641
642     if (m_frame == webkit_web_view_get_main_frame(page))
643         g_signal_emit_by_name(page, "title-changed", titleString.data(), urlString.data());
644 }
645
646 void FrameLoaderClient::dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived)
647 {
648     notImplemented();
649 }
650
651 void FrameLoaderClient::dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier)
652 {
653     notImplemented();
654 }
655
656 void FrameLoaderClient::dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&)
657 {
658     notImplemented();
659 }
660
661 bool FrameLoaderClient::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length)
662 {
663     notImplemented();
664     return false;
665 }
666
667 void FrameLoaderClient::dispatchDidFailProvisionalLoad(const ResourceError&)
668 {
669     g_signal_emit_by_name(m_frame, "load-done", false);
670 }
671
672 void FrameLoaderClient::dispatchDidFailLoad(const ResourceError&)
673 {
674     g_signal_emit_by_name(m_frame, "load-done", false);
675 }
676
677 void FrameLoaderClient::download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&)
678 {
679     notImplemented();
680 }
681
682 ResourceError FrameLoaderClient::cancelledError(const ResourceRequest&)
683 {
684     notImplemented();
685     return ResourceError();
686 }
687
688 ResourceError FrameLoaderClient::blockedError(const ResourceRequest&)
689 {
690     notImplemented();
691     return ResourceError();
692 }
693
694 ResourceError FrameLoaderClient::cannotShowURLError(const ResourceRequest&)
695 {
696     notImplemented();
697     return ResourceError();
698 }
699
700 ResourceError FrameLoaderClient::interruptForPolicyChangeError(const ResourceRequest&)
701 {
702     notImplemented();
703     return ResourceError();
704 }
705
706 ResourceError FrameLoaderClient::cannotShowMIMETypeError(const ResourceResponse&)
707 {
708     notImplemented();
709     return ResourceError();
710 }
711
712 ResourceError FrameLoaderClient::fileDoesNotExistError(const ResourceResponse&)
713 {
714     notImplemented();
715     return ResourceError();
716 }
717
718 bool FrameLoaderClient::shouldFallBack(const ResourceError&)
719 {
720     notImplemented();
721     return false;
722 }
723
724 bool FrameLoaderClient::willUseArchive(ResourceLoader*, const ResourceRequest&, const KURL& originalURL) const
725 {
726     notImplemented();
727     return false;
728 }
729
730 bool FrameLoaderClient::canCachePage() const
731 {
732     notImplemented();
733     return false;
734 }
735
736 Frame* FrameLoaderClient::dispatchCreatePage()
737 {
738     notImplemented();
739     return 0;
740 }
741
742 void FrameLoaderClient::dispatchUnableToImplementPolicy(const ResourceError&)
743 {
744     notImplemented();
745 }
746
747 void FrameLoaderClient::setMainDocumentError(DocumentLoader*, const ResourceError&)
748 {
749     notImplemented();
750 }
751
752 void FrameLoaderClient::startDownload(const ResourceRequest&)
753 {
754     notImplemented();
755 }
756
757 void FrameLoaderClient::updateGlobalHistoryForStandardLoad(const KURL&)
758 {
759     notImplemented();
760 }
761
762 void FrameLoaderClient::updateGlobalHistoryForReload(const KURL&)
763 {
764     notImplemented();
765 }
766
767 void FrameLoaderClient::savePlatformDataToCachedPage(CachedPage*)
768 {
769     notImplemented();
770 }
771
772 void FrameLoaderClient::transitionToCommittedFromCachedPage(CachedPage*)
773 {
774     notImplemented();
775 }
776
777 void FrameLoaderClient::transitionToCommittedForNewPage()
778 {
779     notImplemented();
780 }
781
782 }