32cf3871d2dfe8a2ce2c0869872905fc76db1c1b
[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         d->mouseMoveEvent(static_cast<QMouseEvent*>(ev));
794         break;
795     case QEvent::MouseButtonPress:
796         d->mousePressEvent(static_cast<QMouseEvent*>(ev));
797         break;
798     case QEvent::MouseButtonDblClick:
799         d->mouseDoubleClickEvent(static_cast<QMouseEvent*>(ev));
800         break;
801     case QEvent::MouseButtonRelease:
802         d->mouseReleaseEvent(static_cast<QMouseEvent*>(ev));
803         break;
804     case QEvent::ContextMenu:
805         d->contextMenuEvent(static_cast<QContextMenuEvent*>(ev));
806         break;
807     case QEvent::Wheel:
808         d->wheelEvent(static_cast<QWheelEvent*>(ev));
809         break;
810     case QEvent::KeyPress:
811         d->keyPressEvent(static_cast<QKeyEvent*>(ev));
812         break;
813     case QEvent::KeyRelease:
814         d->keyReleaseEvent(static_cast<QKeyEvent*>(ev));
815         break;
816     case QEvent::FocusIn:
817         d->focusInEvent(static_cast<QFocusEvent*>(ev));
818         break;
819     case QEvent::FocusOut:
820         d->focusOutEvent(static_cast<QFocusEvent*>(ev));
821         break;
822     case QEvent::DragEnter:
823         d->dragEnterEvent(static_cast<QDragEnterEvent*>(ev));
824         break;
825     case QEvent::DragLeave:
826         d->dragLeaveEvent(static_cast<QDragLeaveEvent*>(ev));
827         break;
828     case QEvent::DragMove:
829         d->dragMoveEvent(static_cast<QDragMoveEvent*>(ev));
830         break;
831     case QEvent::Drop:
832         d->dropEvent(static_cast<QDropEvent*>(ev));
833         break;
834     default:
835         return QObject::event(ev);
836     }
837
838     return true;
839 }
840
841 void QWebPagePrivate::mouseMoveEvent(QMouseEvent *ev)
842 {
843     QWebFrame *f = 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 q->hoveringOverLink(result.absoluteLinkURL().prettyURL(), result.title(), result.textContent());
862     }
863 }
864
865 void QWebPagePrivate::mousePressEvent(QMouseEvent *ev)
866 {
867     frameUnderMouse = frameAt(ev->pos());
868     if (!frameUnderMouse)
869         return;
870
871     QWebFramePrivate *frame = frameUnderMouse->d;
872     if (!frame->eventHandler)
873         return;
874
875     frame->eventHandler->handleMousePressEvent(PlatformMouseEvent(ev, 1));
876 }
877
878 void QWebPagePrivate::mouseDoubleClickEvent(QMouseEvent *ev)
879 {
880     QWebFrame *f = 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 QWebPagePrivate::mouseReleaseEvent(QMouseEvent *ev)
892 {
893     QWebFrame *f = 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     frameUnderMouse = 0;
904 }
905
906 void QWebPagePrivate::contextMenuEvent(QContextMenuEvent *ev)
907 {
908     QWebFrame *f = currentFrame(ev->pos());
909     if (!f)
910         return;
911
912     QWebFramePrivate *frame = f->d;
913     if (!frame->eventHandler)
914         return;
915
916     page->contextMenuController()->clearContextMenu();
917     frame->eventHandler->sendContextMenuEvent(PlatformMouseEvent(ev, 1));
918     ContextMenu *menu = page->contextMenuController()->contextMenu();
919
920     QWebPageContext oldContext = currentContext;
921     currentContext = QWebPageContext(menu->hitTestResult());
922
923     const QList<ContextMenuItem> *items = menu->platformDescription();
924     QMenu *qmenu = createContextMenu(menu, items);
925     if (qmenu) {
926         qmenu->exec(ev->globalPos());
927         delete qmenu;
928     }
929     currentContext = oldContext;
930 }
931
932 void QWebPagePrivate::wheelEvent(QWheelEvent *ev)
933 {
934     QWebFramePrivate *frame = 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
945 void QWebPagePrivate::keyPressEvent(QKeyEvent *ev)
946 {
947     if (!mainFrame->d->eventHandler)
948         return;
949
950     bool handled = false;
951     QWebFrame *frame = mainFrame;
952     WebCore::Editor *editor = frame->d->frame->editor();
953     if (editor->canEdit()) {
954         if (ev == QKeySequence::Cut) {
955             q->triggerAction(QWebPage::Cut);
956             handled = true;
957         } else if (ev == QKeySequence::Copy) {
958             q->triggerAction(QWebPage::Copy);
959             handled = true;
960         } else if (ev == QKeySequence::Paste) {
961             q->triggerAction(QWebPage::Paste);
962             handled = true;
963         } else if (ev == QKeySequence::Undo) {
964             q->triggerAction(QWebPage::Undo);
965             handled = true;
966         } else if (ev == QKeySequence::Redo) {
967             q->triggerAction(QWebPage::Redo);
968             handled = true;
969         } else if(ev == QKeySequence::MoveToNextChar) {
970             q->triggerAction(QWebPage::MoveToNextChar);
971             handled = true;
972         } else if(ev == QKeySequence::MoveToPreviousChar) {
973             q->triggerAction(QWebPage::MoveToPreviousChar);
974             handled = true;
975         } else if(ev == QKeySequence::MoveToNextWord) {
976             q->triggerAction(QWebPage::MoveToNextWord);
977             handled = true;
978         } else if(ev == QKeySequence::MoveToPreviousWord) {
979             q->triggerAction(QWebPage::MoveToPreviousWord);
980             handled = true;
981         } else if(ev == QKeySequence::MoveToNextLine) {
982             q->triggerAction(QWebPage::MoveToNextLine);
983             handled = true;
984         } else if(ev == QKeySequence::MoveToPreviousLine) {
985             q->triggerAction(QWebPage::MoveToPreviousLine);
986             handled = true;
987 //             } else if(ev == QKeySequence::MoveToNextPage) {
988 //             } else if(ev == QKeySequence::MoveToPreviousPage) {
989         } else if(ev == QKeySequence::MoveToStartOfLine) {
990             q->triggerAction(QWebPage::MoveToStartOfLine);
991             handled = true;
992         } else if(ev == QKeySequence::MoveToEndOfLine) {
993             q->triggerAction(QWebPage::MoveToEndOfLine);
994             handled = true;
995         } else if(ev == QKeySequence::MoveToStartOfBlock) {
996             q->triggerAction(QWebPage::MoveToStartOfBlock);
997             handled = true;
998         } else if(ev == QKeySequence::MoveToEndOfBlock) {
999             q->triggerAction(QWebPage::MoveToEndOfBlock);
1000             handled = true;
1001         } else if(ev == QKeySequence::MoveToStartOfDocument) {
1002             q->triggerAction(QWebPage::MoveToStartOfDocument);
1003             handled = true;
1004         } else if(ev == QKeySequence::MoveToEndOfDocument) {
1005             q->triggerAction(QWebPage::MoveToEndOfDocument);
1006             handled = true;
1007         } else if(ev == QKeySequence::SelectNextChar) {
1008             q->triggerAction(QWebPage::SelectNextChar);
1009             handled = true;
1010         } else if(ev == QKeySequence::SelectPreviousChar) {
1011             q->triggerAction(QWebPage::SelectPreviousChar);
1012             handled = true;
1013         } else if(ev == QKeySequence::SelectNextWord) {
1014             q->triggerAction(QWebPage::SelectNextWord);
1015             handled = true;
1016         } else if(ev == QKeySequence::SelectPreviousWord) {
1017             q->triggerAction(QWebPage::SelectPreviousWord);
1018             handled = true;
1019         } else if(ev == QKeySequence::SelectNextLine) {
1020             q->triggerAction(QWebPage::SelectNextLine);
1021             handled = true;
1022         } else if(ev == QKeySequence::SelectPreviousLine) {
1023             q->triggerAction(QWebPage::SelectPreviousLine);
1024             handled = true;
1025 //             } else if(ev == QKeySequence::SelectNextPage) {
1026 //             } else if(ev == QKeySequence::SelectPreviousPage) {
1027         } else if(ev == QKeySequence::SelectStartOfLine) {
1028             q->triggerAction(QWebPage::SelectStartOfLine);
1029             handled = true;
1030         } else if(ev == QKeySequence::SelectEndOfLine) {
1031             q->triggerAction(QWebPage::SelectEndOfLine);
1032             handled = true;
1033         } else if(ev == QKeySequence::SelectStartOfBlock) {
1034             q->triggerAction(QWebPage::SelectStartOfBlock);
1035             handled = true;
1036         } else if(ev == QKeySequence::SelectEndOfBlock) {
1037             q->triggerAction(QWebPage::SelectEndOfBlock);
1038             handled = true;
1039         } else if(ev == QKeySequence::SelectStartOfDocument) {
1040             q->triggerAction(QWebPage::SelectStartOfDocument);
1041             handled = true;
1042         } else if(ev == QKeySequence::SelectEndOfDocument) {
1043             q->triggerAction(QWebPage::SelectEndOfDocument);
1044             handled = true;
1045         } else if(ev == QKeySequence::DeleteStartOfWord) {
1046             q->triggerAction(QWebPage::DeleteStartOfWord);
1047             handled = true;
1048         } else if(ev == QKeySequence::DeleteEndOfWord) {
1049             q->triggerAction(QWebPage::DeleteEndOfWord);
1050             handled = true;
1051 //             } else if(ev == QKeySequence::DeleteEndOfLine) {
1052         }
1053     }
1054     if (!handled) 
1055         handled = frame->d->eventHandler->keyEvent(ev);
1056     if (!handled) {
1057         handled = true;
1058         PlatformScrollbar *h, *v;
1059         h = mainFrame->d->horizontalScrollBar();
1060         v = mainFrame->d->verticalScrollBar();
1061
1062         if (ev == QKeySequence::MoveToNextPage) {
1063             if (v)
1064                 v->setValue(v->value() + q->viewportSize().height());
1065         } else if (ev == QKeySequence::MoveToPreviousPage) {
1066             if (v)
1067                 v->setValue(v->value() - q->viewportSize().height());
1068         } else {
1069             switch (ev->key()) {
1070             case Qt::Key_Up:
1071                 if (v)
1072                     v->setValue(v->value() - 10);
1073                 break;
1074             case Qt::Key_Down:
1075                 if (v)
1076                     v->setValue(v->value() + 10);
1077                 break;
1078             case Qt::Key_Left:
1079                 if (h)
1080                     h->setValue(h->value() - 10);
1081                 break;
1082             case Qt::Key_Right:
1083                 if (h)
1084                     h->setValue(h->value() + 10);
1085                 break;
1086             default:
1087                 handled = false;
1088                 break;
1089             }
1090         }
1091     }
1092
1093     ev->setAccepted(handled);
1094 }
1095
1096 void QWebPagePrivate::keyReleaseEvent(QKeyEvent *ev)
1097 {
1098     if (ev->isAutoRepeat()) {
1099         ev->setAccepted(true);
1100         return;
1101     }
1102
1103     if (!mainFrame->d->eventHandler)
1104         return;
1105
1106     bool handled = mainFrame->d->eventHandler->keyEvent(ev);
1107     ev->setAccepted(handled);
1108 }
1109
1110 void QWebPagePrivate::focusInEvent(QFocusEvent *ev)
1111 {
1112     if (ev->reason() != Qt::PopupFocusReason) 
1113         mainFrame->d->frame->page()->focusController()->setFocusedFrame(mainFrame->d->frame);
1114 }
1115
1116 void QWebPagePrivate::focusOutEvent(QFocusEvent *ev)
1117 {
1118     if (ev->reason() != Qt::PopupFocusReason) {
1119         mainFrame->d->frame->selectionController()->clear();
1120         mainFrame->d->frame->setIsActive(false);
1121     }
1122 }
1123
1124 bool QWebPage::focusNextPrevChild(bool next)
1125 {
1126     Q_UNUSED(next)
1127     return false;
1128 }
1129
1130 void QWebPagePrivate::dragEnterEvent(QDragEnterEvent *ev)
1131 {
1132 #ifndef QT_NO_DRAGANDDROP
1133     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), 
1134                       dropActionToDragOp(ev->possibleActions()));
1135     Qt::DropAction action = dragOpToDropAction(page->dragController()->dragEntered(&dragData));
1136     ev->setDropAction(action);
1137     ev->accept();
1138 #endif
1139 }
1140
1141 void QWebPagePrivate::dragLeaveEvent(QDragLeaveEvent *ev)
1142 {
1143 #ifndef QT_NO_DRAGANDDROP
1144     DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
1145     page->dragController()->dragExited(&dragData);
1146     ev->accept();
1147 #endif
1148 }
1149
1150 void QWebPagePrivate::dragMoveEvent(QDragMoveEvent *ev)
1151 {
1152 #ifndef QT_NO_DRAGANDDROP
1153     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), 
1154                       dropActionToDragOp(ev->possibleActions()));
1155     Qt::DropAction action = dragOpToDropAction(page->dragController()->dragUpdated(&dragData));
1156     ev->setDropAction(action);
1157     ev->accept();
1158 #endif
1159 }
1160
1161 void QWebPagePrivate::dropEvent(QDropEvent *ev)
1162 {
1163 #ifndef QT_NO_DRAGANDDROP
1164     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), 
1165                       dropActionToDragOp(ev->possibleActions()));
1166     Qt::DropAction action = dragOpToDropAction(page->dragController()->performDrag(&dragData));
1167     ev->accept();
1168 #endif
1169 }
1170
1171 void QWebPage::setNetworkInterface(QWebNetworkInterface *interface)
1172 {
1173     d->networkInterface = interface;
1174 }
1175
1176 QWebNetworkInterface *QWebPage::networkInterface() const
1177 {
1178     if (d->networkInterface)
1179         return d->networkInterface;
1180     else
1181         return QWebNetworkInterface::defaultInterface();
1182 }
1183
1184 QWebSettings *QWebPage::settings()
1185 {
1186     return d->settings;
1187 }
1188
1189 QString QWebPage::chooseFile(QWebFrame *parentFrame, const QString& oldFile)
1190 {
1191     //FIXME frame pos...
1192 #ifndef QT_NO_FILEDIALOG
1193     return QFileDialog::getOpenFileName(d->view, QString::null, oldFile);
1194 #else
1195     return QString::null;
1196 #endif
1197 }
1198
1199 #ifndef QT_NO_NETWORKPROXY
1200 void QWebPage::setNetworkProxy(const QNetworkProxy& proxy)
1201 {
1202     d->networkProxy = proxy;
1203 }
1204
1205 QNetworkProxy QWebPage::networkProxy() const
1206 {
1207     return d->networkProxy;
1208 }
1209 #endif
1210
1211 QString QWebPage::userAgentFor(const QUrl& url) const {
1212     Q_UNUSED(url)
1213     return QLatin1String("Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3 Qt");
1214 }
1215
1216
1217 void QWebPagePrivate::_q_onLoadProgressChanged(int) {
1218     m_totalBytes = page->progress()->totalPageAndResourceBytesToLoad();
1219     m_bytesReceived = page->progress()->totalBytesReceived();
1220 }
1221
1222
1223 quint64 QWebPage::totalBytes() const {
1224     return d->m_bytesReceived;
1225 }
1226
1227
1228 quint64 QWebPage::bytesReceived() const {
1229     return d->m_totalBytes;
1230 }
1231
1232 QWebPageContext::QWebPageContext(const WebCore::HitTestResult &hitTest)
1233     : d(new QWebPageContextPrivate)
1234 {
1235     d->pos = hitTest.point();
1236     d->text = hitTest.textContent();
1237     d->linkUrl = hitTest.absoluteLinkURL().string();
1238     d->imageUrl = hitTest.absoluteImageURL().string();
1239     d->innerNonSharedNode = hitTest.innerNonSharedNode();
1240     WebCore::Image *img = hitTest.image();
1241     if (img) {
1242         QPixmap *pix = img->getPixmap();
1243         if (pix)
1244             d->image = *pix;
1245     }
1246     WebCore::Frame *frame = hitTest.targetFrame();
1247     if (frame)
1248         d->targetFrame = frame->view()->qwebframe();
1249 }
1250
1251 QWebPageContext::QWebPageContext()
1252     : d(0)
1253 {
1254 }
1255
1256 QWebPageContext::QWebPageContext(const QWebPageContext &other)
1257     : d(0)
1258 {
1259     if (other.d)
1260         d = new QWebPageContextPrivate(*other.d);
1261 }
1262
1263 QWebPageContext &QWebPageContext::operator=(const QWebPageContext &other)
1264 {
1265     if (this != &other) {
1266         if (other.d) {
1267             if (!d)
1268                 d = new QWebPageContextPrivate;
1269             *d = *other.d;
1270         } else {
1271             delete d;
1272             d = 0;
1273         }
1274     }
1275     return *this;
1276 }
1277
1278 QWebPageContext::~QWebPageContext()
1279 {
1280     delete d;
1281 }
1282
1283 QPoint QWebPageContext::pos() const
1284 {
1285     if (!d)
1286         return QPoint();
1287     return d->pos;
1288 }
1289
1290 QString QWebPageContext::text() const
1291 {
1292     if (!d)
1293         return QString();
1294     return d->text;
1295 }
1296
1297 QUrl QWebPageContext::linkUrl() const
1298 {
1299     if (!d)
1300         return QUrl();
1301     return d->linkUrl;
1302 }
1303
1304 QUrl QWebPageContext::imageUrl() const
1305 {
1306     if (!d)
1307         return QUrl();
1308     return d->linkUrl;
1309 }
1310
1311 QPixmap QWebPageContext::image() const
1312 {
1313     if (!d)
1314         return QPixmap();
1315     return d->image;
1316 }
1317
1318 QWebFrame *QWebPageContext::targetFrame() const
1319 {
1320     if (!d)
1321         return 0;
1322     return d->targetFrame;
1323 }
1324
1325 #include "moc_qwebpage.cpp"