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