Reworked the QWebSettings API.
[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->webAction(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->webActionTriggered(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     webActionTriggered(Stop);
354 }
355
356 QWebPageHistory *QWebPage::history() const
357 {
358     return &d->history;
359 }
360
361 void QWebPage::goBack()
362 {
363     webActionTriggered(GoBack);
364 }
365
366 void QWebPage::goForward()
367 {
368     webActionTriggered(GoForward);
369 }
370
371 void QWebPage::goToHistoryItem(const QWebHistoryItem &item)
372 {
373     d->page->goToItem(item.d->item, FrameLoadTypeIndexedBackForward);
374 }
375
376 void QWebPage::javaScriptConsoleMessage(const QString& message, unsigned int lineNumber, const QString& sourceID)
377 {
378 }
379
380 void QWebPage::javaScriptAlert(QWebFrame *frame, const QString& msg)
381 {
382     //FIXME frame pos...
383     QMessageBox::information(this, title(), msg, QMessageBox::Ok);
384 }
385
386 bool QWebPage::javaScriptConfirm(QWebFrame *frame, const QString& msg)
387 {
388     //FIXME frame pos...
389     return 0 == QMessageBox::information(this, title(), msg, QMessageBox::Yes, QMessageBox::No);
390 }
391
392 bool QWebPage::javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result)
393 {
394     //FIXME frame pos...
395     bool ok = false;
396 #ifndef QT_NO_INPUTDIALOG
397     QString x = QInputDialog::getText(this, title(), msg, QLineEdit::Normal, defaultValue, &ok);
398     if (ok && result) {
399         *result = x;
400     }
401 #endif
402     return ok;
403 }
404
405 QWebPage *QWebPage::createWindow()
406 {
407     return 0;
408 }
409
410 QWebPage *QWebPage::createModalDialog()
411 {
412     return 0;
413 }
414
415 QObject *QWebPage::createPlugin(const QString &classid, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
416 {
417     Q_UNUSED(classid)
418     Q_UNUSED(url)
419     Q_UNUSED(paramNames)
420     Q_UNUSED(paramValues)
421     return 0;
422 }
423
424 static WebCore::FrameLoadRequest frameLoadRequest(const QUrl &url, WebCore::Frame *frame)
425 {
426     WebCore::ResourceRequest rr(WebCore::KURL(url.toString()),
427                                 frame->loader()->outgoingReferrer());
428     return WebCore::FrameLoadRequest(rr);
429 }
430
431 static void openNewWindow(const QUrl& url, WebCore::Frame* frame)
432 {
433     if (Page* oldPage = frame->page())
434         if (Page* newPage = oldPage->chrome()->createWindow(frame,
435                 frameLoadRequest(url, frame)))
436             newPage->chrome()->show();
437 }
438
439 void QWebPage::webActionTriggered(WebAction action, bool checked)
440 {
441     WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
442     WebCore::Editor *editor = frame->editor();
443     const char *command = 0;
444
445     switch (action) {
446         case OpenLink:
447             if (QWebFrame *targetFrame = d->currentContext.targetFrame()) {
448                 WTF::RefPtr<WebCore::Frame> wcFrame = targetFrame->d->frame;
449                 targetFrame->d->frame->loader()->load(frameLoadRequest(d->currentContext.linkUrl(), wcFrame.get()),
450                                                       /*lockHistory*/ false,
451                                                       /*userGesture*/ true,
452                                                       /*event*/ 0,
453                                                       /*HTMLFormElement*/ 0,
454                                                       /*formValues*/
455                                                       WTF::HashMap<String, String>());
456                 break;
457             } else {
458             }
459             // fall through
460         case OpenLinkInNewWindow:
461             openNewWindow(d->currentContext.linkUrl(), frame);
462             break;
463         case OpenFrameInNewWindow:
464             break;
465         case DownloadLinkToDisk:
466         case CopyLinkToClipboard:
467             editor->copyURL(WebCore::KURL(d->currentContext.linkUrl().toString()), d->currentContext.text());
468             break;
469         case OpenImageInNewWindow:
470             openNewWindow(d->currentContext.imageUrl(), frame);
471             break;
472         case DownloadImageToDisk:
473         case CopyImageToClipboard:
474             break;
475         case GoBack:
476             d->page->goBack();
477             break;
478         case GoForward:
479             d->page->goForward();
480             break;
481         case Stop:
482             mainFrame()->d->frame->loader()->stopForUserCancel();
483             break;
484         case Reload:
485             mainFrame()->d->frame->loader()->reload();
486             break;
487         case Cut:
488             editor->cut();
489             break;
490         case Copy:
491             editor->copy();
492             break;
493         case Paste:
494             editor->paste();
495             break;
496
497         case Undo:
498             editor->undo();
499             break;
500         case Redo:
501             editor->redo();
502             break;
503
504         case MoveToNextChar:
505             command = "MoveForward";
506             break;
507         case MoveToPreviousChar:
508             command = "MoveBackward";
509             break;
510         case MoveToNextWord:
511             command = "MoveWordForward";
512             break;
513         case MoveToPreviousWord:
514             command = "MoveWordBackward";
515             break;
516         case MoveToNextLine:
517             command = "MoveDown";
518             break;
519         case MoveToPreviousLine:
520             command = "MoveUp";
521             break;
522         case MoveToStartOfLine:
523             command = "MoveToBeginningOfLine";
524             break;
525         case MoveToEndOfLine:
526             command = "MoveToEndOfLine";
527             break;
528         case MoveToStartOfBlock:
529             command = "MoveToBeginningOfParagraph";
530             break;
531         case MoveToEndOfBlock:
532             command = "MoveToEndOfParagraph";
533             break;
534         case MoveToStartOfDocument:
535             command = "MoveToBeginningOfDocument";
536             break;
537         case MoveToEndOfDocument:
538             command = "MoveToEndOfDocument";
539             break;
540         case SelectNextChar:
541             command = "MoveForwardAndModifySelection";
542             break;
543         case SelectPreviousChar:
544             command = "MoveBackwardAndModifySelection";
545             break;
546         case SelectNextWord:
547             command = "MoveWordForwardAndModifySelection";
548             break;
549         case SelectPreviousWord:
550             command = "MoveWordBackwardAndModifySelection";
551             break;
552         case SelectNextLine:
553             command = "MoveDownAndModifySelection";
554             break;
555         case SelectPreviousLine:
556             command = "MoveUpAndModifySelection";
557             break;
558         case SelectStartOfLine:
559             command = "MoveToBeginningOfLineAndModifySelection";
560             break;
561         case SelectEndOfLine:
562             command = "MoveToEndOfLineAndModifySelection";
563             break;
564         case SelectStartOfBlock:
565             command = "MoveToBeginningOfParagraphAndModifySelection";
566             break;
567         case SelectEndOfBlock:
568             command = "MoveToEndOfParagraphAndModifySelection";
569             break;
570         case SelectStartOfDocument:
571             command = "MoveToBeginningOfDocumentAndModifySelection";
572             break;
573         case SelectEndOfDocument:
574             command = "MoveToEndOfDocumentAndModifySelection";
575             break;
576         case DeleteStartOfWord:
577             command = "DeleteWordBackward";
578             break;
579         case DeleteEndOfWord:
580             command = "DeleteWordForward";
581             break;
582
583         default: break;
584     }
585
586     if (command)
587         editor->execCommand(command);
588 }
589
590 QWebPage::NavigationRequestResponse QWebPage::navigationRequested(QWebFrame *frame, const QWebNetworkRequest &request, QWebPage::NavigationType type)
591 {
592     Q_UNUSED(request)
593     return AcceptNavigationRequest;
594 }
595
596 void QWebPage::setWindowGeometry(const QRect& geom)
597 {
598     Q_UNUSED(geom)
599 }
600
601 bool QWebPage::canCut() const
602 {
603     return d->page->focusController()->focusedOrMainFrame()->editor()->canCut();
604 }
605
606 bool QWebPage::canCopy() const
607 {
608     return d->page->focusController()->focusedOrMainFrame()->editor()->canCopy();
609 }
610
611 bool QWebPage::canPaste() const
612 {
613     return d->page->focusController()->focusedOrMainFrame()->editor()->canPaste();
614 }
615
616 void QWebPage::cut()
617 {
618     webActionTriggered(Cut);
619 }
620
621 void QWebPage::copy()
622 {
623     webActionTriggered(Copy);
624 }
625
626 void QWebPage::paste()
627 {
628     webActionTriggered(Paste);
629 }
630
631 QAction *QWebPage::webAction(WebAction action) const
632 {
633     if (action == QWebPage::NoWebAction) return 0;
634     if (d->actions[action])
635         return d->actions[action];
636
637     QString text;
638
639     switch (action) {
640         case OpenLink:
641             text = contextMenuItemTagOpenLink();
642             break;
643         case OpenLinkInNewWindow:
644             text = contextMenuItemTagOpenLinkInNewWindow();
645             break;
646         case OpenFrameInNewWindow:
647             text = contextMenuItemTagOpenFrameInNewWindow();
648             break;
649
650         case DownloadLinkToDisk:
651             text = contextMenuItemTagDownloadLinkToDisk();
652             break;
653         case CopyLinkToClipboard:
654             text = contextMenuItemTagCopyLinkToClipboard();
655             break;
656
657         case OpenImageInNewWindow:
658             text = contextMenuItemTagOpenImageInNewWindow();
659             break;
660         case DownloadImageToDisk:
661             text = contextMenuItemTagDownloadImageToDisk();
662             break;
663         case CopyImageToClipboard:
664             text = contextMenuItemTagCopyImageToClipboard();
665             break;
666
667         case GoBack:
668             text = contextMenuItemTagGoBack();
669             break;
670         case GoForward:
671             text = contextMenuItemTagGoForward();
672             break;
673         case Stop:
674             text = contextMenuItemTagStop();
675             break;
676         case Reload:
677             text = contextMenuItemTagReload();
678             break;
679
680         case Cut:
681             text = contextMenuItemTagCut();
682             break;
683         case Copy:
684             text = contextMenuItemTagCopy();
685             break;
686         case Paste:
687             text = contextMenuItemTagPaste();
688             break;
689
690         case Undo: {
691             QAction *a = undoStack()->createUndoAction(d->q);
692             d->actions[action] = a;
693             return a;
694         }
695         case Redo: {
696             QAction *a = undoStack()->createRedoAction(d->q);
697             d->actions[action] = a;
698             return a;
699         }
700         case MoveToNextChar:
701         case MoveToPreviousChar:
702         case MoveToNextWord:
703         case MoveToPreviousWord:
704         case MoveToNextLine:
705         case MoveToPreviousLine:
706         case MoveToStartOfLine:
707         case MoveToEndOfLine:
708         case MoveToStartOfBlock:
709         case MoveToEndOfBlock:
710         case MoveToStartOfDocument:
711         case MoveToEndOfDocument:
712         case SelectNextChar:
713         case SelectPreviousChar:
714         case SelectNextWord:
715         case SelectPreviousWord:
716         case SelectNextLine:
717         case SelectPreviousLine:
718         case SelectStartOfLine:
719         case SelectEndOfLine:
720         case SelectStartOfBlock:
721         case SelectEndOfBlock:
722         case SelectStartOfDocument:
723         case SelectEndOfDocument:
724         case DeleteStartOfWord:
725         case DeleteEndOfWord:
726             break; // ####
727
728         case NoWebAction:
729             return 0;
730     }
731
732     if (text.isEmpty())
733         return 0;
734
735     QAction *a = new QAction(d->q);
736     a->setText(text);
737     a->setData(action);
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 void QWebPage::resizeEvent(QResizeEvent *e)
789 {
790     QWidget::resizeEvent(e);
791     if (mainFrame()->d->frame && mainFrame()->d->frameView) {
792         mainFrame()->d->frameView->setFrameGeometry(rect());
793         mainFrame()->d->frame->forceLayout();
794         mainFrame()->d->frame->view()->adjustViewSize();
795     }
796 }
797
798 void QWebPage::paintEvent(QPaintEvent *ev)
799 {
800 #ifdef QWEBKIT_TIME_RENDERING
801     QTime time;
802     time.start();
803 #endif
804
805     QPainter p(this);
806
807     QVector<QRect> vector = ev->region().rects();
808     if (!vector.isEmpty()) {
809         for (int i = 0; i < vector.size(); ++i) {
810             mainFrame()->render(&p, vector.at(i));
811         }
812     } else {
813         mainFrame()->render(&p, ev->rect());
814     }
815
816 #ifdef    QWEBKIT_TIME_RENDERING
817     int elapsed = time.elapsed();
818     qDebug()<<"paint event on "<<ev->region()<<", took to render =  "<<elapsed;
819 #endif
820 }
821
822 void QWebPage::mouseMoveEvent(QMouseEvent *ev)
823 {
824     QWebFramePrivate *frame = d->currentFrame(ev->pos())->d;
825     if (!frame->frameView)
826         return;
827
828     frame->eventHandler->handleMouseMoveEvent(PlatformMouseEvent(ev, 0));
829     const int xOffset =
830         frame->horizontalScrollBar() ? frame->horizontalScrollBar()->value() : 0;
831     const int yOffset =
832         frame->verticalScrollBar() ? frame->verticalScrollBar()->value() : 0;
833     IntPoint pt(ev->x() + xOffset, ev->y() + yOffset);
834     WebCore::HitTestResult result = frame->eventHandler->hitTestResultAtPoint(pt, false);
835     WebCore::Element *link = result.URLElement();
836     if (link != frame->lastHoverElement) {
837         frame->lastHoverElement = link;
838         emit hoveringOverLink(result.absoluteLinkURL().prettyURL(), result.title());
839     }
840 }
841
842 void QWebPage::mousePressEvent(QMouseEvent *ev)
843 {
844     d->frameUnderMouse = d->frameAt(ev->pos());
845     QWebFramePrivate *frame = d->frameUnderMouse->d;
846     if (!frame->eventHandler)
847         return;
848
849     frame->eventHandler->handleMousePressEvent(PlatformMouseEvent(ev, 1));
850
851     //FIXME need to keep track of subframe focus for key events!
852     frame->page->setFocus();
853 }
854
855 void QWebPage::mouseDoubleClickEvent(QMouseEvent *ev)
856 {
857     QWebFramePrivate *frame = d->currentFrame(ev->pos())->d;
858     if (!frame->eventHandler)
859         return;
860
861     frame->eventHandler->handleMousePressEvent(PlatformMouseEvent(ev, 2));
862
863     //FIXME need to keep track of subframe focus for key events!
864     frame->page->setFocus();
865 }
866
867 void QWebPage::mouseReleaseEvent(QMouseEvent *ev)
868 {
869     QWebFramePrivate *frame = d->currentFrame(ev->pos())->d;
870     if (frame->frameView) {
871         frame->eventHandler->handleMouseReleaseEvent(PlatformMouseEvent(ev, 0));
872
873         //FIXME need to keep track of subframe focus for key events!
874         frame->page->setFocus();
875     }
876     d->frameUnderMouse = 0;
877 }
878
879 void QWebPage::contextMenuEvent(QContextMenuEvent *ev)
880 {
881     QWebFramePrivate *frame = d->currentFrame(ev->pos())->d;
882     if (!frame->eventHandler)
883         return;
884     d->page->contextMenuController()->clearContextMenu();
885     frame->eventHandler->sendContextMenuEvent(PlatformMouseEvent(ev, 1));
886     ContextMenu *menu = d->page->contextMenuController()->contextMenu();
887
888     QWebPageContext oldContext = d->currentContext;
889     d->currentContext = QWebPageContext(menu->hitTestResult());
890
891     QList<ContextMenuItem> *items = menu->platformDescription();
892     QMenu *qmenu = d->createContextMenu(items);
893     if (qmenu) {
894         qmenu->exec(ev->globalPos());
895         delete qmenu;
896     }
897     d->currentContext = oldContext;
898 }
899
900 void QWebPage::wheelEvent(QWheelEvent *ev)
901 {
902     QWebFramePrivate *frame = d->currentFrame(ev->pos())->d;
903
904     bool accepted = false;
905     if (frame->eventHandler) {
906         WebCore::PlatformWheelEvent pev(ev);
907         accepted = frame->eventHandler->handleWheelEvent(pev);
908     }
909
910     ev->setAccepted(accepted);
911
912     //FIXME need to keep track of subframe focus for key events!
913     frame->page->setFocus();
914
915     if (!ev->isAccepted())
916         QWidget::wheelEvent(ev);
917 }
918
919 void QWebPage::keyPressEvent(QKeyEvent *ev)
920 {
921     if (!mainFrame()->d->eventHandler)
922         return;
923
924     bool handled = false;
925     QWebFrame *frame = mainFrame();
926     WebCore::Editor *editor = frame->d->frame->editor();
927     if (editor->canEdit()) {
928         if (ev == QKeySequence::Cut) {
929             webActionTriggered(Cut);
930             handled = true;
931         } else if (ev == QKeySequence::Copy) {
932             webActionTriggered(Copy);
933             handled = true;
934         } else if (ev == QKeySequence::Paste) {
935             webActionTriggered(Paste);
936             handled = true;
937         } else if (ev == QKeySequence::Undo) {
938             webActionTriggered(Undo);
939             handled = true;
940         } else if (ev == QKeySequence::Redo) {
941             webActionTriggered(Redo);
942             handled = true;
943         } else if(ev == QKeySequence::MoveToNextChar) {
944             webActionTriggered(MoveToNextChar);
945             handled = true;
946         } else if(ev == QKeySequence::MoveToPreviousChar) {
947             webActionTriggered(MoveToPreviousChar);
948             handled = true;
949         } else if(ev == QKeySequence::MoveToNextWord) {
950             webActionTriggered(MoveToNextWord);
951             handled = true;
952         } else if(ev == QKeySequence::MoveToPreviousWord) {
953             webActionTriggered(MoveToPreviousWord);
954             handled = true;
955         } else if(ev == QKeySequence::MoveToNextLine) {
956             webActionTriggered(MoveToNextLine);
957             handled = true;
958         } else if(ev == QKeySequence::MoveToPreviousLine) {
959             webActionTriggered(MoveToPreviousLine);
960             handled = true;
961 //             } else if(ev == QKeySequence::MoveToNextPage) {
962 //             } else if(ev == QKeySequence::MoveToPreviousPage) {
963         } else if(ev == QKeySequence::MoveToStartOfLine) {
964             webActionTriggered(MoveToStartOfLine);
965             handled = true;
966         } else if(ev == QKeySequence::MoveToEndOfLine) {
967             webActionTriggered(MoveToEndOfLine);
968             handled = true;
969         } else if(ev == QKeySequence::MoveToStartOfBlock) {
970             webActionTriggered(MoveToStartOfBlock);
971             handled = true;
972         } else if(ev == QKeySequence::MoveToEndOfBlock) {
973             webActionTriggered(MoveToEndOfBlock);
974             handled = true;
975         } else if(ev == QKeySequence::MoveToStartOfDocument) {
976             webActionTriggered(MoveToStartOfDocument);
977             handled = true;
978         } else if(ev == QKeySequence::MoveToEndOfDocument) {
979             webActionTriggered(MoveToEndOfDocument);
980             handled = true;
981         } else if(ev == QKeySequence::SelectNextChar) {
982             webActionTriggered(SelectNextChar);
983             handled = true;
984         } else if(ev == QKeySequence::SelectPreviousChar) {
985             webActionTriggered(SelectPreviousChar);
986             handled = true;
987         } else if(ev == QKeySequence::SelectNextWord) {
988             webActionTriggered(SelectNextWord);
989             handled = true;
990         } else if(ev == QKeySequence::SelectPreviousWord) {
991             webActionTriggered(SelectPreviousWord);
992             handled = true;
993         } else if(ev == QKeySequence::SelectNextLine) {
994             webActionTriggered(SelectNextLine);
995             handled = true;
996         } else if(ev == QKeySequence::SelectPreviousLine) {
997             webActionTriggered(SelectPreviousLine);
998             handled = true;
999 //             } else if(ev == QKeySequence::SelectNextPage) {
1000 //             } else if(ev == QKeySequence::SelectPreviousPage) {
1001         } else if(ev == QKeySequence::SelectStartOfLine) {
1002             webActionTriggered(SelectStartOfLine);
1003             handled = true;
1004         } else if(ev == QKeySequence::SelectEndOfLine) {
1005             webActionTriggered(SelectEndOfLine);
1006             handled = true;
1007         } else if(ev == QKeySequence::SelectStartOfBlock) {
1008             webActionTriggered(SelectStartOfBlock);
1009             handled = true;
1010         } else if(ev == QKeySequence::SelectEndOfBlock) {
1011             webActionTriggered(SelectEndOfBlock);
1012             handled = true;
1013         } else if(ev == QKeySequence::SelectStartOfDocument) {
1014             webActionTriggered(SelectStartOfDocument);
1015             handled = true;
1016         } else if(ev == QKeySequence::SelectEndOfDocument) {
1017             webActionTriggered(SelectEndOfDocument);
1018             handled = true;
1019         } else if(ev == QKeySequence::DeleteStartOfWord) {
1020             webActionTriggered(DeleteStartOfWord);
1021             handled = true;
1022         } else if(ev == QKeySequence::DeleteEndOfWord) {
1023             webActionTriggered(DeleteEndOfWord);
1024             handled = true;
1025 //             } else if(ev == QKeySequence::DeleteEndOfLine) {
1026         }
1027     }
1028     if (!handled) 
1029         handled = frame->d->eventHandler->keyEvent(ev);
1030     if (!handled) {
1031         handled = true;
1032         PlatformScrollbar *h, *v;
1033         h = mainFrame()->d->horizontalScrollBar();
1034         v = mainFrame()->d->verticalScrollBar();
1035
1036         if (ev == QKeySequence::MoveToNextPage) {
1037             if (v)
1038                 v->setValue(v->value() + height());
1039         } else if (ev == QKeySequence::MoveToPreviousPage) {
1040             if (v)
1041                 v->setValue(v->value() - height());
1042         } else {
1043             switch (ev->key()) {
1044             case Qt::Key_Up:
1045                 if (v)
1046                     v->setValue(v->value() - 10);
1047                 break;
1048             case Qt::Key_Down:
1049                 if (v)
1050                     v->setValue(v->value() + 10);
1051                 break;
1052             case Qt::Key_Left:
1053                 if (h)
1054                     h->setValue(h->value() - 10);
1055                 break;
1056             case Qt::Key_Right:
1057                 if (h)
1058                     h->setValue(h->value() + 10);
1059                 break;
1060             default:
1061                 handled = false;
1062                 break;
1063             }
1064         }
1065     }
1066
1067     ev->setAccepted(handled);
1068 }
1069
1070 void QWebPage::keyReleaseEvent(QKeyEvent *ev)
1071 {
1072     if (ev->isAutoRepeat()) {
1073         ev->setAccepted(true);
1074         return;
1075     }
1076
1077     if (!mainFrame()->d->eventHandler)
1078         return;
1079
1080     bool handled = mainFrame()->d->eventHandler->keyEvent(ev);
1081     ev->setAccepted(handled);
1082 }
1083
1084 void QWebPage::focusInEvent(QFocusEvent *ev)
1085 {
1086     if (ev->reason() != Qt::PopupFocusReason) 
1087         mainFrame()->d->frame->page()->focusController()->setFocusedFrame(mainFrame()->d->frame);
1088     QWidget::focusInEvent(ev);
1089 }
1090
1091 void QWebPage::focusOutEvent(QFocusEvent *ev)
1092 {
1093     QWidget::focusOutEvent(ev);
1094     if (ev->reason() != Qt::PopupFocusReason) {
1095         mainFrame()->d->frame->selectionController()->clear();
1096         mainFrame()->d->frame->setIsActive(false);
1097     }
1098 }
1099
1100 bool QWebPage::focusNextPrevChild(bool next)
1101 {
1102     Q_UNUSED(next)
1103     return false;
1104 }
1105
1106 void QWebPage::dragEnterEvent(QDragEnterEvent *ev)
1107 {
1108 #ifndef QT_NO_DRAGANDDROP
1109     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), 
1110                       dropActionToDragOp(ev->possibleActions()));
1111     Qt::DropAction action = dragOpToDropAction(d->page->dragController()->dragEntered(&dragData));
1112     ev->setDropAction(action);
1113     ev->accept();
1114 #endif
1115 }
1116
1117 void QWebPage::dragLeaveEvent(QDragLeaveEvent *ev)
1118 {
1119 #ifndef QT_NO_DRAGANDDROP
1120     DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
1121     d->page->dragController()->dragExited(&dragData);
1122     ev->accept();
1123 #endif
1124 }
1125
1126 void QWebPage::dragMoveEvent(QDragMoveEvent *ev)
1127 {
1128 #ifndef QT_NO_DRAGANDDROP
1129     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), 
1130                       dropActionToDragOp(ev->possibleActions()));
1131     Qt::DropAction action = dragOpToDropAction(d->page->dragController()->dragUpdated(&dragData));
1132     ev->setDropAction(action);
1133     ev->accept();
1134 #endif
1135 }
1136
1137 void QWebPage::dropEvent(QDropEvent *ev)
1138 {
1139 #ifndef QT_NO_DRAGANDDROP
1140     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), 
1141                       dropActionToDragOp(ev->possibleActions()));
1142     Qt::DropAction action = dragOpToDropAction(d->page->dragController()->performDrag(&dragData));
1143     ev->accept();
1144 #endif
1145 }
1146
1147 void QWebPage::setNetworkInterface(QWebNetworkInterface *interface)
1148 {
1149     d->networkInterface = interface;
1150 }
1151
1152 QWebNetworkInterface *QWebPage::networkInterface() const
1153 {
1154     if (d->networkInterface)
1155         return d->networkInterface;
1156     else
1157         return QWebNetworkInterface::defaultInterface();
1158 }
1159
1160 QPixmap QWebPage::icon() const
1161 {
1162     Image* image = iconDatabase()->iconForPageURL(url().toString(), IntSize(16, 16));
1163     if (!image || image->isNull()) {
1164         image = iconDatabase()->defaultIcon(IntSize(16, 16));
1165     }
1166
1167     if (!image) {
1168         return QPixmap();
1169     }
1170
1171     QPixmap *icon = image->getPixmap();
1172     if (!icon) {
1173         return QPixmap();
1174     }
1175     return *icon;
1176 }
1177
1178 QWebSettings *QWebPage::settings()
1179 {
1180     return d->settings;
1181 }
1182
1183 QString QWebPage::chooseFile(QWebFrame *parentFrame, const QString& oldFile)
1184 {
1185     //FIXME frame pos...
1186 #ifndef QT_NO_FILEDIALOG
1187     return QFileDialog::getOpenFileName(this, QString::null, oldFile);
1188 #else
1189     return QString::null;
1190 #endif
1191 }
1192
1193 #ifndef QT_NO_NETWORKPROXY
1194 void QWebPage::setNetworkProxy(const QNetworkProxy& proxy)
1195 {
1196     d->networkProxy = proxy;
1197 }
1198
1199 QNetworkProxy QWebPage::networkProxy() const
1200 {
1201     return d->networkProxy;
1202 }
1203 #endif
1204
1205 QString QWebPage::userAgentStringForUrl(const QUrl& forUrl) const {
1206     Q_UNUSED(forUrl)
1207     return QLatin1String("Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3 Qt");
1208 }
1209
1210
1211 void QWebPagePrivate::_q_onLoadProgressChanged(int) {
1212     m_totalBytes = page->progress()->totalPageAndResourceBytesToLoad();
1213     m_bytesReceived = page->progress()->totalBytesReceived();
1214 }
1215
1216
1217 quint64 QWebPage::totalBytes() const {
1218     return d->m_bytesReceived;
1219 }
1220
1221
1222 quint64 QWebPage::bytesReceived() const {
1223     return d->m_totalBytes;
1224 }
1225
1226 QWebPageContext::QWebPageContext(const WebCore::HitTestResult &hitTest)
1227     : d(new QWebPageContextPrivate)
1228 {
1229     d->pos = hitTest.point();
1230     d->text = hitTest.textContent();
1231     d->linkUrl = hitTest.absoluteLinkURL().url();
1232     d->imageUrl = hitTest.absoluteImageURL().url();
1233     WebCore::Image *img = hitTest.image();
1234     if (img) {
1235         QPixmap *pix = img->getPixmap();
1236         if (pix)
1237             d->image = *pix;
1238     }
1239     WebCore::Frame *frame = hitTest.targetFrame();
1240     if (frame)
1241         d->targetFrame = frame->view()->qwebframe();
1242 }
1243
1244 QWebPageContext::QWebPageContext()
1245     : d(0)
1246 {
1247 }
1248
1249 QWebPageContext::QWebPageContext(const QWebPageContext &other)
1250     : d(0)
1251 {
1252     if (other.d)
1253         d = new QWebPageContextPrivate(*other.d);
1254 }
1255
1256 QWebPageContext &QWebPageContext::operator=(const QWebPageContext &other)
1257 {
1258     if (this != &other) {
1259         if (other.d) {
1260             if (!d)
1261                 d = new QWebPageContextPrivate;
1262             *d = *other.d;
1263         } else {
1264             delete d;
1265             d = 0;
1266         }
1267     }
1268     return *this;
1269 }
1270
1271 QWebPageContext::~QWebPageContext()
1272 {
1273     delete d;
1274 }
1275
1276 QPoint QWebPageContext::pos() const
1277 {
1278     if (!d)
1279         return QPoint();
1280     return d->pos;
1281 }
1282
1283 QString QWebPageContext::text() const
1284 {
1285     if (!d)
1286         return QString();
1287     return d->text;
1288 }
1289
1290 QUrl QWebPageContext::linkUrl() const
1291 {
1292     if (!d)
1293         return QUrl();
1294     return d->linkUrl;
1295 }
1296
1297 QUrl QWebPageContext::imageUrl() const
1298 {
1299     if (!d)
1300         return QUrl();
1301     return d->linkUrl;
1302 }
1303
1304 QPixmap QWebPageContext::image() const
1305 {
1306     if (!d)
1307         return QPixmap();
1308     return d->image;
1309 }
1310
1311 QWebFrame *QWebPageContext::targetFrame() const
1312 {
1313     if (!d)
1314         return 0;
1315     return d->targetFrame;
1316 }
1317
1318 #include "moc_qwebpage.cpp"