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