2041861104fe71e65dbc7b07eb58f1d5df5889a7
[WebKit-https.git] / WebKit / qt / Api / qwebpage.cpp
1 /*
2     Copyright (C) 2007 Trolltech ASA
3     Copyright (C) 2007 Staikos Computing Services Inc.
4     Copyright (C) 2007 Apple Inc.
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library 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     Library General Public License for more details.
15
16     You should have received a copy of the GNU Library General Public License
17     along with this library; see the file COPYING.LIB.  If not, write to
18     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19     Boston, MA 02110-1301, USA.
20
21     This class provides all functionality needed for loading images, style sheets and html
22     pages from the web. It has a memory cache for these objects.
23 */
24 #include "config.h"
25 #include "qwebpage.h"
26 #include "qwebframe.h"
27 #include "qwebpage_p.h"
28 #include "qwebframe_p.h"
29 #include "qwebnetworkinterface.h"
30 #include "qwebpagehistory.h"
31 #include "qwebpagehistory_p.h"
32 #include "qwebsettings.h"
33
34 #include "Frame.h"
35 #include "FrameLoaderClientQt.h"
36 #include "ChromeClientQt.h"
37 #include "ContextMenu.h"
38 #include "ContextMenuClientQt.h"
39 #include "DragClientQt.h"
40 #include "DragController.h"
41 #include "DragData.h"
42 #include "EditorClientQt.h"
43 #include "Settings.h"
44 #include "Page.h"
45 #include "FrameLoader.h"
46 #include "FrameLoadRequest.h"
47 #include "KURL.h"
48 #include "Image.h"
49 #include "InspectorClientQt.h"
50 #include "InspectorController.h"
51 #include "FocusController.h"
52 #include "Editor.h"
53 #include "PlatformScrollBar.h"
54 #include "PlatformKeyboardEvent.h"
55 #include "PlatformWheelEvent.h"
56 #include "ProgressTracker.h"
57 #include "RefPtr.h"
58 #include "HashMap.h"
59 #include "HitTestResult.h"
60 #include "WindowFeatures.h"
61 #include "LocalizedStrings.h"
62
63 #include <QDebug>
64 #include <QDragEnterEvent>
65 #include <QDragLeaveEvent>
66 #include <QDragMoveEvent>
67 #include <QDropEvent>
68 #include <QFileDialog>
69 #include <QHttpRequestHeader>
70 #include <QInputDialog>
71 #include <QMessageBox>
72 #include <QNetworkProxy>
73 #include <QUndoStack>
74 #include <QUrl>
75 #include <QPainter>
76
77 using namespace WebCore;
78
79 QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
80     : q(qq)
81     , view(0)
82     , modified(false)
83 {
84     chromeClient = new ChromeClientQt(q);
85     contextMenuClient = new ContextMenuClientQt();
86     editorClient = new EditorClientQt(q);
87     page = new Page(chromeClient, contextMenuClient, editorClient,
88                     new DragClientQt(q), new InspectorClientQt(q));
89
90     // ### should be configurable
91     page->settings()->setDefaultTextEncodingName("iso-8859-1");
92
93     settings = new QWebSettings(page->settings());
94
95     undoStack = 0;
96     mainFrame = 0;
97     networkInterface = 0;
98     insideOpenCall = false;
99
100     history.d = new QWebPageHistoryPrivate(page->backForwardList());
101     memset(actions, 0, sizeof(actions));
102 }
103
104 QWebPagePrivate::~QWebPagePrivate()
105 {
106     delete undoStack;
107     delete settings;
108     delete page;
109 }
110
111 QWebPage::NavigationRequestResponse QWebPagePrivate::navigationRequested(QWebFrame *frame, const QWebNetworkRequest &request, QWebPage::NavigationType type)
112 {
113     if (insideOpenCall
114         && frame == mainFrame)
115         return QWebPage::AcceptNavigationRequest;
116     return q->navigationRequested(frame, request, type);
117 }
118
119 void QWebPagePrivate::createMainFrame()
120 {
121     if (!mainFrame) {
122         QWebFrameData frameData;
123         frameData.ownerElement = 0;
124         frameData.allowsScrolling = true;
125         frameData.marginWidth = 0;
126         frameData.marginHeight = 0;
127         mainFrame = new QWebFrame(q, &frameData);
128         mainFrame->d->frameView->setFrameGeometry(IntRect(IntPoint(0,0), q->viewportSize()));
129
130         emit q->frameCreated(mainFrame);
131     }
132 }
133
134 static QWebPage::WebAction webActionForContextMenuAction(WebCore::ContextMenuAction action)
135 {
136     switch (action) {
137         case WebCore::ContextMenuItemTagOpenLink: return QWebPage::OpenLink;
138         case WebCore::ContextMenuItemTagOpenLinkInNewWindow: return QWebPage::OpenLinkInNewWindow;
139         case WebCore::ContextMenuItemTagDownloadLinkToDisk: return QWebPage::DownloadLinkToDisk;
140         case WebCore::ContextMenuItemTagCopyLinkToClipboard: return QWebPage::CopyLinkToClipboard;
141         case WebCore::ContextMenuItemTagOpenImageInNewWindow: return QWebPage::OpenImageInNewWindow;
142         case WebCore::ContextMenuItemTagDownloadImageToDisk: return QWebPage::DownloadImageToDisk;
143         case WebCore::ContextMenuItemTagCopyImageToClipboard: return QWebPage::CopyImageToClipboard;
144         case WebCore::ContextMenuItemTagOpenFrameInNewWindow: return QWebPage::OpenFrameInNewWindow;
145         case WebCore::ContextMenuItemTagCopy: return QWebPage::Copy;
146         case WebCore::ContextMenuItemTagGoBack: return QWebPage::GoBack;
147         case WebCore::ContextMenuItemTagGoForward: return QWebPage::GoForward;
148         case WebCore::ContextMenuItemTagStop: return QWebPage::Stop;
149         case WebCore::ContextMenuItemTagReload: return QWebPage::Reload;
150         case WebCore::ContextMenuItemTagCut: return QWebPage::Cut;
151         case WebCore::ContextMenuItemTagPaste: return QWebPage::Paste;
152         case WebCore::ContextMenuItemTagDefaultDirection: return QWebPage::SetTextDirectionDefault;
153         case WebCore::ContextMenuItemTagLeftToRight: return QWebPage::SetTextDirectionLeftToRight;
154         case WebCore::ContextMenuItemTagRightToLeft: return QWebPage::SetTextDirectionRightToLeft;
155         case WebCore::ContextMenuItemTagBold: return QWebPage::ToggleBold;
156         case WebCore::ContextMenuItemTagItalic: return QWebPage::ToggleItalic;
157         case WebCore::ContextMenuItemTagUnderline: return QWebPage::ToggleUnderline;
158         case WebCore::ContextMenuItemTagInspectElement: return QWebPage::InspectElement;
159         default: break;
160     }
161     return QWebPage::NoWebAction;
162 }
163
164 QMenu *QWebPagePrivate::createContextMenu(const WebCore::ContextMenu *webcoreMenu, const QList<WebCore::ContextMenuItem> *items)
165 {
166     QMenu *menu = new QMenu;
167     for (int i = 0; i < items->count(); ++i) {
168         const ContextMenuItem &item = items->at(i);
169         switch (item.type()) {
170             case WebCore::ActionType: {
171                 QWebPage::WebAction action = webActionForContextMenuAction(item.action());
172                 QAction *a = q->action(action);
173                 if (a) {
174                     ContextMenuItem it(item);
175                     webcoreMenu->checkOrEnableIfNeeded(it);
176                     PlatformMenuItemDescription desc = it.releasePlatformDescription();
177                     a->setEnabled(desc.enabled);
178                     a->setChecked(desc.checked);
179
180                     menu->addAction(a);
181                 }
182                 break;
183             }
184             case WebCore::SeparatorType:
185                 menu->addSeparator();
186                 break;
187             case WebCore::SubmenuType: {
188                 QMenu *subMenu = createContextMenu(webcoreMenu, item.platformSubMenu());
189                 if (!subMenu->actions().isEmpty()) {
190                     subMenu->setTitle(item.title());
191                     menu->addAction(subMenu->menuAction());
192                 } else {
193                     delete subMenu;
194                 }
195                 break;
196             }
197         }
198     }
199     return menu;
200 }
201
202 QWebFrame *QWebPagePrivate::frameAt(const QPoint &pos) const
203 {
204     QWebFrame *frame = mainFrame;
205
206 redo:
207     QList<QWebFrame*> children = frame->childFrames();
208     for (int i = 0; i < children.size(); ++i) {
209         if (children.at(i)->geometry().contains(pos)) {
210             frame = children.at(i);
211             goto redo;
212         }
213     }
214     if (frame->geometry().contains(pos))
215         return frame;
216     return 0;
217 }
218
219 void QWebPagePrivate::_q_webActionTriggered(bool checked)
220 {
221     QAction *a = qobject_cast<QAction *>(q->sender());
222     if (!a)
223         return;
224     QWebPage::WebAction action = static_cast<QWebPage::WebAction>(a->data().toInt());
225     q->triggerAction(action, checked);
226 }
227
228 void QWebPagePrivate::updateAction(QWebPage::WebAction action)
229 {
230     QAction *a = actions[action];
231     if (!a || !mainFrame)
232         return;
233
234     WebCore::FrameLoader *loader = mainFrame->d->frame->loader();
235     WebCore::Editor *editor = page->focusController()->focusedOrMainFrame()->editor();
236
237     bool enabled = a->isEnabled();
238
239     switch (action) {
240         case QWebPage::GoBack:
241             enabled = loader->canGoBackOrForward(-1);
242             break;
243         case QWebPage::GoForward:
244             enabled = loader->canGoBackOrForward(1);
245             break;
246         case QWebPage::Stop:
247             enabled = loader->isLoading();
248             break;
249         case QWebPage::Reload:
250             enabled = !loader->isLoading();
251             break;
252         case QWebPage::Cut:
253             enabled = editor->canCut();
254             break;
255         case QWebPage::Copy:
256             enabled = editor->canCopy();
257             break;
258         case QWebPage::Paste:
259             enabled = editor->canPaste();
260             break;
261         case QWebPage::Undo:
262         case QWebPage::Redo:
263             // those two are handled by QUndoStack
264             break;
265         default: break;
266     }
267
268     a->setEnabled(enabled);
269 }
270
271 void QWebPagePrivate::updateNavigationActions()
272 {
273     updateAction(QWebPage::GoBack);
274     updateAction(QWebPage::GoForward);
275     updateAction(QWebPage::Stop);
276     updateAction(QWebPage::Reload);
277 }
278
279 void QWebPagePrivate::updateEditorActions()
280 {
281     updateAction(QWebPage::Cut);
282     updateAction(QWebPage::Copy);
283     updateAction(QWebPage::Paste);
284 }
285
286 QWebPage::QWebPage(QObject *parent)
287     : QObject(parent)
288     , d(new QWebPagePrivate(this))
289 {
290     setView(qobject_cast<QWidget *>(parent));
291
292     connect(this, SIGNAL(loadProgressChanged(int)), this, SLOT(_q_onLoadProgressChanged(int)));
293 }
294
295 QWebPage::~QWebPage()
296 {
297     FrameLoader *loader = d->mainFrame->d->frame->loader();
298     if (loader)
299         loader->detachFromParent();
300     delete d;
301 }
302
303 QWebFrame *QWebPage::mainFrame() const
304 {
305     d->createMainFrame();
306     return d->mainFrame;
307 }
308
309 QWebFrame *QWebPage::currentFrame() const
310 {
311     return static_cast<WebCore::FrameLoaderClientQt *>(d->page->focusController()->focusedOrMainFrame()->loader()->client())->webFrame();
312 }
313
314 QWebPageHistory *QWebPage::history() const
315 {
316     return &d->history;
317 }
318
319 void QWebPage::setView(QWidget *view)
320 {
321     d->view = view;
322     setViewportSize(view ? view->size() : QSize(0, 0));
323 }
324
325 QWidget *QWebPage::view() const
326 {
327     return d->view;
328 }
329
330
331 void QWebPage::javaScriptConsoleMessage(const QString& message, unsigned int lineNumber, const QString& sourceID)
332 {
333 }
334
335 void QWebPage::javaScriptAlert(QWebFrame *frame, const QString& msg)
336 {
337     //FIXME frame pos...
338     QMessageBox::information(d->view, mainFrame()->title(), msg, QMessageBox::Ok);
339 }
340
341 bool QWebPage::javaScriptConfirm(QWebFrame *frame, const QString& msg)
342 {
343     //FIXME frame pos...
344     return 0 == QMessageBox::information(d->view, mainFrame()->title(), msg, QMessageBox::Yes, QMessageBox::No);
345 }
346
347 bool QWebPage::javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result)
348 {
349     //FIXME frame pos...
350     bool ok = false;
351 #ifndef QT_NO_INPUTDIALOG
352     QString x = QInputDialog::getText(d->view, mainFrame()->title(), msg, QLineEdit::Normal, defaultValue, &ok);
353     if (ok && result) {
354         *result = x;
355     }
356 #endif
357     return ok;
358 }
359
360 QWebPage *QWebPage::createWindow()
361 {
362     return 0;
363 }
364
365 QWebPage *QWebPage::createModalDialog()
366 {
367     return 0;
368 }
369
370 QObject *QWebPage::createPlugin(const QString &classid, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
371 {
372     Q_UNUSED(classid)
373     Q_UNUSED(url)
374     Q_UNUSED(paramNames)
375     Q_UNUSED(paramValues)
376     return 0;
377 }
378
379 static WebCore::FrameLoadRequest frameLoadRequest(const QUrl &url, WebCore::Frame *frame)
380 {
381     WebCore::ResourceRequest rr(WebCore::KURL(url.toString()),
382                                 frame->loader()->outgoingReferrer());
383     return WebCore::FrameLoadRequest(rr);
384 }
385
386 static void openNewWindow(const QUrl& url, WebCore::Frame* frame)
387 {
388     if (Page* oldPage = frame->page()) {
389         WindowFeatures features;
390         if (Page* newPage = oldPage->chrome()->createWindow(frame,
391                 frameLoadRequest(url, frame), features))
392             newPage->chrome()->show();
393     }
394 }
395
396 void QWebPage::triggerAction(WebAction action, bool checked)
397 {
398     WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
399     WebCore::Editor *editor = frame->editor();
400     const char *command = 0;
401
402     switch (action) {
403         case OpenLink:
404             if (QWebFrame *targetFrame = d->currentContext.targetFrame()) {
405                 WTF::RefPtr<WebCore::Frame> wcFrame = targetFrame->d->frame;
406                 targetFrame->d->frame->loader()->load(frameLoadRequest(d->currentContext.linkUrl(), wcFrame.get()),
407                                                       /*lockHistory*/ false,
408                                                       /*userGesture*/ true,
409                                                       /*event*/ 0,
410                                                       /*HTMLFormElement*/ 0,
411                                                       /*formValues*/
412                                                       WTF::HashMap<String, String>());
413                 break;
414             } else {
415             }
416             // fall through
417         case OpenLinkInNewWindow:
418             openNewWindow(d->currentContext.linkUrl(), frame);
419             break;
420         case OpenFrameInNewWindow:
421             break;
422         case DownloadLinkToDisk:
423         case CopyLinkToClipboard:
424             editor->copyURL(WebCore::KURL(d->currentContext.linkUrl().toString()), d->currentContext.text());
425             break;
426         case OpenImageInNewWindow:
427             openNewWindow(d->currentContext.imageUrl(), frame);
428             break;
429         case DownloadImageToDisk:
430         case CopyImageToClipboard:
431             break;
432         case GoBack:
433             d->page->goBack();
434             break;
435         case GoForward:
436             d->page->goForward();
437             break;
438         case Stop:
439             mainFrame()->d->frame->loader()->stopForUserCancel();
440             break;
441         case Reload:
442             mainFrame()->d->frame->loader()->reload();
443             break;
444         case Cut:
445             command = "Cut";
446             break;
447         case Copy:
448             command = "Copy";
449             break;
450         case Paste:
451             command = "Paste";
452             break;
453
454         case Undo:
455             command = "Undo";
456             break;
457         case Redo:
458             command = "Redo";
459             break;
460
461         case MoveToNextChar:
462             command = "MoveForward";
463             break;
464         case MoveToPreviousChar:
465             command = "MoveBackward";
466             break;
467         case MoveToNextWord:
468             command = "MoveWordForward";
469             break;
470         case MoveToPreviousWord:
471             command = "MoveWordBackward";
472             break;
473         case MoveToNextLine:
474             command = "MoveDown";
475             break;
476         case MoveToPreviousLine:
477             command = "MoveUp";
478             break;
479         case MoveToStartOfLine:
480             command = "MoveToBeginningOfLine";
481             break;
482         case MoveToEndOfLine:
483             command = "MoveToEndOfLine";
484             break;
485         case MoveToStartOfBlock:
486             command = "MoveToBeginningOfParagraph";
487             break;
488         case MoveToEndOfBlock:
489             command = "MoveToEndOfParagraph";
490             break;
491         case MoveToStartOfDocument:
492             command = "MoveToBeginningOfDocument";
493             break;
494         case MoveToEndOfDocument:
495             command = "MoveToEndOfDocument";
496             break;
497         case SelectNextChar:
498             command = "MoveForwardAndModifySelection";
499             break;
500         case SelectPreviousChar:
501             command = "MoveBackwardAndModifySelection";
502             break;
503         case SelectNextWord:
504             command = "MoveWordForwardAndModifySelection";
505             break;
506         case SelectPreviousWord:
507             command = "MoveWordBackwardAndModifySelection";
508             break;
509         case SelectNextLine:
510             command = "MoveDownAndModifySelection";
511             break;
512         case SelectPreviousLine:
513             command = "MoveUpAndModifySelection";
514             break;
515         case SelectStartOfLine:
516             command = "MoveToBeginningOfLineAndModifySelection";
517             break;
518         case SelectEndOfLine:
519             command = "MoveToEndOfLineAndModifySelection";
520             break;
521         case SelectStartOfBlock:
522             command = "MoveToBeginningOfParagraphAndModifySelection";
523             break;
524         case SelectEndOfBlock:
525             command = "MoveToEndOfParagraphAndModifySelection";
526             break;
527         case SelectStartOfDocument:
528             command = "MoveToBeginningOfDocumentAndModifySelection";
529             break;
530         case SelectEndOfDocument:
531             command = "MoveToEndOfDocumentAndModifySelection";
532             break;
533         case DeleteStartOfWord:
534             command = "DeleteWordBackward";
535             break;
536         case DeleteEndOfWord:
537             command = "DeleteWordForward";
538             break;
539
540         case SetTextDirectionDefault:
541             editor->setBaseWritingDirection("inherit");
542             break;
543         case SetTextDirectionLeftToRight:
544             editor->setBaseWritingDirection("ltr");
545             break;
546         case SetTextDirectionRightToLeft:
547             editor->setBaseWritingDirection("rtl");
548             break;
549
550         case ToggleBold:
551             command = "ToggleBold";
552             break;
553         case ToggleItalic:
554             command = "ToggleItalic";
555             break;
556         case ToggleUnderline:
557             editor->toggleUnderline();
558
559         case InspectElement:
560             d->page->inspectorController()->inspect(d->currentContext.d->innerNonSharedNode.get());
561             break;
562
563         default: break;
564     }
565
566     if (command)
567         editor->command(command).execute();
568 }
569
570 QSize QWebPage::viewportSize() const
571 {
572     QWebFrame *frame = mainFrame();
573     if (frame->d->frame && frame->d->frameView)
574         return frame->d->frameView->frameGeometry().size();
575     return QSize(0, 0);
576 }
577
578 void QWebPage::setViewportSize(const QSize &size) const
579 {
580     QWebFrame *frame = mainFrame();
581     if (frame->d->frame && frame->d->frameView) {
582         frame->d->frameView->setFrameGeometry(QRect(QPoint(0, 0), size));
583         frame->d->frame->forceLayout();
584         frame->d->frame->view()->adjustViewSize();
585     }
586 }
587
588
589 QWebPage::NavigationRequestResponse QWebPage::navigationRequested(QWebFrame *frame, const QWebNetworkRequest &request, QWebPage::NavigationType type)
590 {
591     Q_UNUSED(request)
592     return AcceptNavigationRequest;
593 }
594
595 QString QWebPage::selectedText() const
596 {
597     return d->page->focusController()->focusedOrMainFrame()->selectedText();
598 }
599
600 QAction *QWebPage::action(WebAction action) const
601 {
602     if (action == QWebPage::NoWebAction) return 0;
603     if (d->actions[action])
604         return d->actions[action];
605
606     QString text;
607     bool checkable = false;
608
609     switch (action) {
610         case OpenLink:
611             text = contextMenuItemTagOpenLink();
612             break;
613         case OpenLinkInNewWindow:
614             text = contextMenuItemTagOpenLinkInNewWindow();
615             break;
616         case OpenFrameInNewWindow:
617             text = contextMenuItemTagOpenFrameInNewWindow();
618             break;
619
620         case DownloadLinkToDisk:
621             text = contextMenuItemTagDownloadLinkToDisk();
622             break;
623         case CopyLinkToClipboard:
624             text = contextMenuItemTagCopyLinkToClipboard();
625             break;
626
627         case OpenImageInNewWindow:
628             text = contextMenuItemTagOpenImageInNewWindow();
629             break;
630         case DownloadImageToDisk:
631             text = contextMenuItemTagDownloadImageToDisk();
632             break;
633         case CopyImageToClipboard:
634             text = contextMenuItemTagCopyImageToClipboard();
635             break;
636
637         case GoBack:
638             text = contextMenuItemTagGoBack();
639             break;
640         case GoForward:
641             text = contextMenuItemTagGoForward();
642             break;
643         case Stop:
644             text = contextMenuItemTagStop();
645             break;
646         case Reload:
647             text = contextMenuItemTagReload();
648             break;
649
650         case Cut:
651             text = contextMenuItemTagCut();
652             break;
653         case Copy:
654             text = contextMenuItemTagCopy();
655             break;
656         case Paste:
657             text = contextMenuItemTagPaste();
658             break;
659
660         case Undo: {
661             QAction *a = undoStack()->createUndoAction(d->q);
662             d->actions[action] = a;
663             return a;
664         }
665         case Redo: {
666             QAction *a = undoStack()->createRedoAction(d->q);
667             d->actions[action] = a;
668             return a;
669         }
670         case MoveToNextChar:
671         case MoveToPreviousChar:
672         case MoveToNextWord:
673         case MoveToPreviousWord:
674         case MoveToNextLine:
675         case MoveToPreviousLine:
676         case MoveToStartOfLine:
677         case MoveToEndOfLine:
678         case MoveToStartOfBlock:
679         case MoveToEndOfBlock:
680         case MoveToStartOfDocument:
681         case MoveToEndOfDocument:
682         case SelectNextChar:
683         case SelectPreviousChar:
684         case SelectNextWord:
685         case SelectPreviousWord:
686         case SelectNextLine:
687         case SelectPreviousLine:
688         case SelectStartOfLine:
689         case SelectEndOfLine:
690         case SelectStartOfBlock:
691         case SelectEndOfBlock:
692         case SelectStartOfDocument:
693         case SelectEndOfDocument:
694         case DeleteStartOfWord:
695         case DeleteEndOfWord:
696             break; // ####
697
698         case SetTextDirectionDefault:
699             text = contextMenuItemTagDefaultDirection();
700             break;
701         case SetTextDirectionLeftToRight:
702             text = contextMenuItemTagLeftToRight();
703             checkable = true;
704             break;
705         case SetTextDirectionRightToLeft:
706             text = contextMenuItemTagRightToLeft();
707             checkable = true;
708             break;
709
710         case ToggleBold:
711             text = contextMenuItemTagBold();
712             checkable = true;
713             break;
714         case ToggleItalic:
715             text = contextMenuItemTagItalic();
716             checkable = true;
717             break;
718         case ToggleUnderline:
719             text = contextMenuItemTagUnderline();
720             checkable = true;
721             break;
722
723         case InspectElement:
724             text = contextMenuItemTagInspectElement();
725             break;
726
727         case NoWebAction:
728             return 0;
729     }
730
731     if (text.isEmpty())
732         return 0;
733
734     QAction *a = new QAction(d->q);
735     a->setText(text);
736     a->setData(action);
737     a->setCheckable(checkable);
738
739     connect(a, SIGNAL(triggered(bool)),
740             this, SLOT(_q_webActionTriggered(bool)));
741
742     d->actions[action] = a;
743     d->updateAction(action);
744     return a;
745 }
746
747 /*!
748   Returns true if the page contains unsubmitted form data.
749 */
750 bool QWebPage::isModified() const
751 {
752     return d->modified;
753 }
754
755
756 QUndoStack *QWebPage::undoStack() const
757 {
758     if (!d->undoStack)
759         d->undoStack = new QUndoStack(const_cast<QWebPage *>(this));
760
761     return d->undoStack;
762 }
763
764 static inline DragOperation dropActionToDragOp(Qt::DropActions actions)
765 {
766     unsigned result = 0;
767     if (actions & Qt::CopyAction)
768         result |= DragOperationCopy;
769     if (actions & Qt::MoveAction)
770         result |= DragOperationMove;
771     if (actions & Qt::LinkAction)
772         result |= DragOperationLink;
773     return (DragOperation)result;    
774 }
775
776 static inline Qt::DropAction dragOpToDropAction(unsigned actions)
777 {
778     Qt::DropAction result = Qt::IgnoreAction;
779     if (actions & DragOperationCopy)
780         result = Qt::CopyAction;
781     else if (actions & DragOperationMove)
782         result = Qt::MoveAction;
783     else if (actions & DragOperationLink)
784         result = Qt::LinkAction;
785     return result;    
786 }
787
788
789 bool QWebPage::event(QEvent *ev)
790 {
791     switch (ev->type()) {
792     case QEvent::MouseMove:
793         mouseMoveEvent(static_cast<QMouseEvent*>(ev));
794         break;
795     case QEvent::MouseButtonPress:
796         mousePressEvent(static_cast<QMouseEvent*>(ev));
797         break;
798     case QEvent::MouseButtonDblClick:
799         mouseDoubleClickEvent(static_cast<QMouseEvent*>(ev));
800         break;
801     case QEvent::MouseButtonRelease:
802         mouseReleaseEvent(static_cast<QMouseEvent*>(ev));
803         break;
804     case QEvent::ContextMenu:
805         contextMenuEvent(static_cast<QContextMenuEvent*>(ev));
806         break;
807     case QEvent::Wheel:
808         wheelEvent(static_cast<QWheelEvent*>(ev));
809         break;
810     case QEvent::KeyPress:
811         keyPressEvent(static_cast<QKeyEvent*>(ev));
812         break;
813     case QEvent::KeyRelease:
814         keyReleaseEvent(static_cast<QKeyEvent*>(ev));
815         break;
816     case QEvent::FocusIn:
817         focusInEvent(static_cast<QFocusEvent*>(ev));
818         break;
819     case QEvent::FocusOut:
820         focusOutEvent(static_cast<QFocusEvent*>(ev));
821         break;
822     case QEvent::DragEnter:
823         dragEnterEvent(static_cast<QDragEnterEvent*>(ev));
824         break;
825     case QEvent::DragLeave:
826         dragLeaveEvent(static_cast<QDragLeaveEvent*>(ev));
827         break;
828     case QEvent::DragMove:
829         dragMoveEvent(static_cast<QDragMoveEvent*>(ev));
830         break;
831     case QEvent::Drop:
832         dropEvent(static_cast<QDropEvent*>(ev));
833         break;
834     default:
835         return QObject::event(ev);
836     }
837
838     return true;
839 }
840
841 void QWebPage::mouseMoveEvent(QMouseEvent *ev)
842 {
843     QWebFrame *f = d->currentFrame(ev->pos());
844     if (!f)
845         return;
846
847     QWebFramePrivate *frame = f->d;
848     if (!frame->frameView)
849         return;
850
851     frame->eventHandler->handleMouseMoveEvent(PlatformMouseEvent(ev, 0));
852     const int xOffset =
853         frame->horizontalScrollBar() ? frame->horizontalScrollBar()->value() : 0;
854     const int yOffset =
855         frame->verticalScrollBar() ? frame->verticalScrollBar()->value() : 0;
856     IntPoint pt(ev->x() + xOffset, ev->y() + yOffset);
857     WebCore::HitTestResult result = frame->eventHandler->hitTestResultAtPoint(pt, false);
858     WebCore::Element *link = result.URLElement();
859     if (link != frame->lastHoverElement) {
860         frame->lastHoverElement = link;
861         emit hoveringOverLink(result.absoluteLinkURL().prettyURL(), result.title(), result.textContent());
862     }
863 }
864
865 void QWebPage::mousePressEvent(QMouseEvent *ev)
866 {
867     d->frameUnderMouse = d->frameAt(ev->pos());
868     if (!d->frameUnderMouse)
869         return;
870
871     QWebFramePrivate *frame = d->frameUnderMouse->d;
872     if (!frame->eventHandler)
873         return;
874
875     frame->eventHandler->handleMousePressEvent(PlatformMouseEvent(ev, 1));
876 }
877
878 void QWebPage::mouseDoubleClickEvent(QMouseEvent *ev)
879 {
880     QWebFrame *f = d->currentFrame(ev->pos());
881     if (!f)
882         return;
883
884     QWebFramePrivate *frame = f->d;
885     if (!frame->eventHandler)
886         return;
887
888     frame->eventHandler->handleMousePressEvent(PlatformMouseEvent(ev, 2));
889 }
890
891 void QWebPage::mouseReleaseEvent(QMouseEvent *ev)
892 {
893     QWebFrame *f = d->currentFrame(ev->pos());
894     if (!f)
895         return;
896
897     QWebFramePrivate *frame = f->d;
898     if (!frame->frameView)
899         return;
900
901     frame->eventHandler->handleMouseReleaseEvent(PlatformMouseEvent(ev, 0));
902
903     d->frameUnderMouse = 0;
904 }
905
906 void QWebPage::contextMenuEvent(QContextMenuEvent *ev)
907 {
908     QWebFrame *f = d->currentFrame(ev->pos());
909     if (!f)
910         return;
911
912     QWebFramePrivate *frame = f->d;
913     if (!frame->eventHandler)
914         return;
915
916     d->page->contextMenuController()->clearContextMenu();
917     frame->eventHandler->sendContextMenuEvent(PlatformMouseEvent(ev, 1));
918     ContextMenu *menu = d->page->contextMenuController()->contextMenu();
919
920     QWebPageContext oldContext = d->currentContext;
921     d->currentContext = QWebPageContext(menu->hitTestResult());
922
923     const QList<ContextMenuItem> *items = menu->platformDescription();
924     QMenu *qmenu = d->createContextMenu(menu, items);
925     if (qmenu) {
926         qmenu->exec(ev->globalPos());
927         delete qmenu;
928     }
929     d->currentContext = oldContext;
930 }
931
932 void QWebPage::wheelEvent(QWheelEvent *ev)
933 {
934     QWebFramePrivate *frame = d->currentFrame(ev->pos())->d;
935
936     bool accepted = false;
937     if (frame->eventHandler) {
938         WebCore::PlatformWheelEvent pev(ev);
939         accepted = frame->eventHandler->handleWheelEvent(pev);
940     }
941
942     ev->setAccepted(accepted);
943
944     // ### QWebPage
945 //     if (!ev->isAccepted())
946 //         QWidget::wheelEvent(ev);
947 }
948
949 void QWebPage::keyPressEvent(QKeyEvent *ev)
950 {
951     if (!mainFrame()->d->eventHandler)
952         return;
953
954     bool handled = false;
955     QWebFrame *frame = mainFrame();
956     WebCore::Editor *editor = frame->d->frame->editor();
957     if (editor->canEdit()) {
958         if (ev == QKeySequence::Cut) {
959             triggerAction(Cut);
960             handled = true;
961         } else if (ev == QKeySequence::Copy) {
962             triggerAction(Copy);
963             handled = true;
964         } else if (ev == QKeySequence::Paste) {
965             triggerAction(Paste);
966             handled = true;
967         } else if (ev == QKeySequence::Undo) {
968             triggerAction(Undo);
969             handled = true;
970         } else if (ev == QKeySequence::Redo) {
971             triggerAction(Redo);
972             handled = true;
973         } else if(ev == QKeySequence::MoveToNextChar) {
974             triggerAction(MoveToNextChar);
975             handled = true;
976         } else if(ev == QKeySequence::MoveToPreviousChar) {
977             triggerAction(MoveToPreviousChar);
978             handled = true;
979         } else if(ev == QKeySequence::MoveToNextWord) {
980             triggerAction(MoveToNextWord);
981             handled = true;
982         } else if(ev == QKeySequence::MoveToPreviousWord) {
983             triggerAction(MoveToPreviousWord);
984             handled = true;
985         } else if(ev == QKeySequence::MoveToNextLine) {
986             triggerAction(MoveToNextLine);
987             handled = true;
988         } else if(ev == QKeySequence::MoveToPreviousLine) {
989             triggerAction(MoveToPreviousLine);
990             handled = true;
991 //             } else if(ev == QKeySequence::MoveToNextPage) {
992 //             } else if(ev == QKeySequence::MoveToPreviousPage) {
993         } else if(ev == QKeySequence::MoveToStartOfLine) {
994             triggerAction(MoveToStartOfLine);
995             handled = true;
996         } else if(ev == QKeySequence::MoveToEndOfLine) {
997             triggerAction(MoveToEndOfLine);
998             handled = true;
999         } else if(ev == QKeySequence::MoveToStartOfBlock) {
1000             triggerAction(MoveToStartOfBlock);
1001             handled = true;
1002         } else if(ev == QKeySequence::MoveToEndOfBlock) {
1003             triggerAction(MoveToEndOfBlock);
1004             handled = true;
1005         } else if(ev == QKeySequence::MoveToStartOfDocument) {
1006             triggerAction(MoveToStartOfDocument);
1007             handled = true;
1008         } else if(ev == QKeySequence::MoveToEndOfDocument) {
1009             triggerAction(MoveToEndOfDocument);
1010             handled = true;
1011         } else if(ev == QKeySequence::SelectNextChar) {
1012             triggerAction(SelectNextChar);
1013             handled = true;
1014         } else if(ev == QKeySequence::SelectPreviousChar) {
1015             triggerAction(SelectPreviousChar);
1016             handled = true;
1017         } else if(ev == QKeySequence::SelectNextWord) {
1018             triggerAction(SelectNextWord);
1019             handled = true;
1020         } else if(ev == QKeySequence::SelectPreviousWord) {
1021             triggerAction(SelectPreviousWord);
1022             handled = true;
1023         } else if(ev == QKeySequence::SelectNextLine) {
1024             triggerAction(SelectNextLine);
1025             handled = true;
1026         } else if(ev == QKeySequence::SelectPreviousLine) {
1027             triggerAction(SelectPreviousLine);
1028             handled = true;
1029 //             } else if(ev == QKeySequence::SelectNextPage) {
1030 //             } else if(ev == QKeySequence::SelectPreviousPage) {
1031         } else if(ev == QKeySequence::SelectStartOfLine) {
1032             triggerAction(SelectStartOfLine);
1033             handled = true;
1034         } else if(ev == QKeySequence::SelectEndOfLine) {
1035             triggerAction(SelectEndOfLine);
1036             handled = true;
1037         } else if(ev == QKeySequence::SelectStartOfBlock) {
1038             triggerAction(SelectStartOfBlock);
1039             handled = true;
1040         } else if(ev == QKeySequence::SelectEndOfBlock) {
1041             triggerAction(SelectEndOfBlock);
1042             handled = true;
1043         } else if(ev == QKeySequence::SelectStartOfDocument) {
1044             triggerAction(SelectStartOfDocument);
1045             handled = true;
1046         } else if(ev == QKeySequence::SelectEndOfDocument) {
1047             triggerAction(SelectEndOfDocument);
1048             handled = true;
1049         } else if(ev == QKeySequence::DeleteStartOfWord) {
1050             triggerAction(DeleteStartOfWord);
1051             handled = true;
1052         } else if(ev == QKeySequence::DeleteEndOfWord) {
1053             triggerAction(DeleteEndOfWord);
1054             handled = true;
1055 //             } else if(ev == QKeySequence::DeleteEndOfLine) {
1056         }
1057     }
1058     if (!handled) 
1059         handled = frame->d->eventHandler->keyEvent(ev);
1060     if (!handled) {
1061         handled = true;
1062         PlatformScrollbar *h, *v;
1063         h = mainFrame()->d->horizontalScrollBar();
1064         v = mainFrame()->d->verticalScrollBar();
1065
1066         if (ev == QKeySequence::MoveToNextPage) {
1067             if (v)
1068                 v->setValue(v->value() + viewportSize().height());
1069         } else if (ev == QKeySequence::MoveToPreviousPage) {
1070             if (v)
1071                 v->setValue(v->value() - viewportSize().height());
1072         } else {
1073             switch (ev->key()) {
1074             case Qt::Key_Up:
1075                 if (v)
1076                     v->setValue(v->value() - 10);
1077                 break;
1078             case Qt::Key_Down:
1079                 if (v)
1080                     v->setValue(v->value() + 10);
1081                 break;
1082             case Qt::Key_Left:
1083                 if (h)
1084                     h->setValue(h->value() - 10);
1085                 break;
1086             case Qt::Key_Right:
1087                 if (h)
1088                     h->setValue(h->value() + 10);
1089                 break;
1090             default:
1091                 handled = false;
1092                 break;
1093             }
1094         }
1095     }
1096
1097     ev->setAccepted(handled);
1098 }
1099
1100 void QWebPage::keyReleaseEvent(QKeyEvent *ev)
1101 {
1102     if (ev->isAutoRepeat()) {
1103         ev->setAccepted(true);
1104         return;
1105     }
1106
1107     if (!mainFrame()->d->eventHandler)
1108         return;
1109
1110     bool handled = mainFrame()->d->eventHandler->keyEvent(ev);
1111     ev->setAccepted(handled);
1112 }
1113
1114 void QWebPage::focusInEvent(QFocusEvent *ev)
1115 {
1116     if (ev->reason() != Qt::PopupFocusReason) 
1117         mainFrame()->d->frame->page()->focusController()->setFocusedFrame(mainFrame()->d->frame);
1118     // ### QWebPage
1119     //QWidget::focusInEvent(ev);
1120 }
1121
1122 void QWebPage::focusOutEvent(QFocusEvent *ev)
1123 {
1124     // ### QWebPage
1125     //QWidget::focusOutEvent(ev);
1126     if (ev->reason() != Qt::PopupFocusReason) {
1127         mainFrame()->d->frame->selectionController()->clear();
1128         mainFrame()->d->frame->setIsActive(false);
1129     }
1130 }
1131
1132 bool QWebPage::focusNextPrevChild(bool next)
1133 {
1134     Q_UNUSED(next)
1135     return false;
1136 }
1137
1138 void QWebPage::dragEnterEvent(QDragEnterEvent *ev)
1139 {
1140 #ifndef QT_NO_DRAGANDDROP
1141     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), 
1142                       dropActionToDragOp(ev->possibleActions()));
1143     Qt::DropAction action = dragOpToDropAction(d->page->dragController()->dragEntered(&dragData));
1144     ev->setDropAction(action);
1145     ev->accept();
1146 #endif
1147 }
1148
1149 void QWebPage::dragLeaveEvent(QDragLeaveEvent *ev)
1150 {
1151 #ifndef QT_NO_DRAGANDDROP
1152     DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
1153     d->page->dragController()->dragExited(&dragData);
1154     ev->accept();
1155 #endif
1156 }
1157
1158 void QWebPage::dragMoveEvent(QDragMoveEvent *ev)
1159 {
1160 #ifndef QT_NO_DRAGANDDROP
1161     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), 
1162                       dropActionToDragOp(ev->possibleActions()));
1163     Qt::DropAction action = dragOpToDropAction(d->page->dragController()->dragUpdated(&dragData));
1164     ev->setDropAction(action);
1165     ev->accept();
1166 #endif
1167 }
1168
1169 void QWebPage::dropEvent(QDropEvent *ev)
1170 {
1171 #ifndef QT_NO_DRAGANDDROP
1172     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), 
1173                       dropActionToDragOp(ev->possibleActions()));
1174     Qt::DropAction action = dragOpToDropAction(d->page->dragController()->performDrag(&dragData));
1175     ev->accept();
1176 #endif
1177 }
1178
1179 void QWebPage::setNetworkInterface(QWebNetworkInterface *interface)
1180 {
1181     d->networkInterface = interface;
1182 }
1183
1184 QWebNetworkInterface *QWebPage::networkInterface() const
1185 {
1186     if (d->networkInterface)
1187         return d->networkInterface;
1188     else
1189         return QWebNetworkInterface::defaultInterface();
1190 }
1191
1192 QWebSettings *QWebPage::settings()
1193 {
1194     return d->settings;
1195 }
1196
1197 QString QWebPage::chooseFile(QWebFrame *parentFrame, const QString& oldFile)
1198 {
1199     //FIXME frame pos...
1200 #ifndef QT_NO_FILEDIALOG
1201     return QFileDialog::getOpenFileName(d->view, QString::null, oldFile);
1202 #else
1203     return QString::null;
1204 #endif
1205 }
1206
1207 #ifndef QT_NO_NETWORKPROXY
1208 void QWebPage::setNetworkProxy(const QNetworkProxy& proxy)
1209 {
1210     d->networkProxy = proxy;
1211 }
1212
1213 QNetworkProxy QWebPage::networkProxy() const
1214 {
1215     return d->networkProxy;
1216 }
1217 #endif
1218
1219 QString QWebPage::userAgentFor(const QUrl& url) const {
1220     Q_UNUSED(url)
1221     return QLatin1String("Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3 Qt");
1222 }
1223
1224
1225 void QWebPagePrivate::_q_onLoadProgressChanged(int) {
1226     m_totalBytes = page->progress()->totalPageAndResourceBytesToLoad();
1227     m_bytesReceived = page->progress()->totalBytesReceived();
1228 }
1229
1230
1231 quint64 QWebPage::totalBytes() const {
1232     return d->m_bytesReceived;
1233 }
1234
1235
1236 quint64 QWebPage::bytesReceived() const {
1237     return d->m_totalBytes;
1238 }
1239
1240 QWebPageContext::QWebPageContext(const WebCore::HitTestResult &hitTest)
1241     : d(new QWebPageContextPrivate)
1242 {
1243     d->pos = hitTest.point();
1244     d->text = hitTest.textContent();
1245     d->linkUrl = hitTest.absoluteLinkURL().string();
1246     d->imageUrl = hitTest.absoluteImageURL().string();
1247     d->innerNonSharedNode = hitTest.innerNonSharedNode();
1248     WebCore::Image *img = hitTest.image();
1249     if (img) {
1250         QPixmap *pix = img->getPixmap();
1251         if (pix)
1252             d->image = *pix;
1253     }
1254     WebCore::Frame *frame = hitTest.targetFrame();
1255     if (frame)
1256         d->targetFrame = frame->view()->qwebframe();
1257 }
1258
1259 QWebPageContext::QWebPageContext()
1260     : d(0)
1261 {
1262 }
1263
1264 QWebPageContext::QWebPageContext(const QWebPageContext &other)
1265     : d(0)
1266 {
1267     if (other.d)
1268         d = new QWebPageContextPrivate(*other.d);
1269 }
1270
1271 QWebPageContext &QWebPageContext::operator=(const QWebPageContext &other)
1272 {
1273     if (this != &other) {
1274         if (other.d) {
1275             if (!d)
1276                 d = new QWebPageContextPrivate;
1277             *d = *other.d;
1278         } else {
1279             delete d;
1280             d = 0;
1281         }
1282     }
1283     return *this;
1284 }
1285
1286 QWebPageContext::~QWebPageContext()
1287 {
1288     delete d;
1289 }
1290
1291 QPoint QWebPageContext::pos() const
1292 {
1293     if (!d)
1294         return QPoint();
1295     return d->pos;
1296 }
1297
1298 QString QWebPageContext::text() const
1299 {
1300     if (!d)
1301         return QString();
1302     return d->text;
1303 }
1304
1305 QUrl QWebPageContext::linkUrl() const
1306 {
1307     if (!d)
1308         return QUrl();
1309     return d->linkUrl;
1310 }
1311
1312 QUrl QWebPageContext::imageUrl() const
1313 {
1314     if (!d)
1315         return QUrl();
1316     return d->linkUrl;
1317 }
1318
1319 QPixmap QWebPageContext::image() const
1320 {
1321     if (!d)
1322         return QPixmap();
1323     return d->image;
1324 }
1325
1326 QWebFrame *QWebPageContext::targetFrame() const
1327 {
1328     if (!d)
1329         return 0;
1330     return d->targetFrame;
1331 }
1332
1333 #include "moc_qwebpage.cpp"