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