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