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