7ace67804fa3770f179d9d4eebe6b899b85425fb
[WebKit.git] / WebKit2 / UIProcess / API / qt / qwkpage.cpp
1 /*
2  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this program; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #include "qwkpage.h"
22 #include "qwkpage_p.h"
23
24 #include "ClientImpl.h"
25 #include "LocalizedStrings.h"
26 #include "WebEventFactoryQt.h"
27 #include "WKStringQt.h"
28 #include "WKURLQt.h"
29 #include <QAction>
30 #include <QApplication>
31 #include <QGraphicsSceneMouseEvent>
32 #include <QStyle>
33 #include <QtDebug>
34 #include <WebKit2/WKFrame.h>
35 #include <WebKit2/WKRetainPtr.h>
36
37 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
38 #include <QTouchEvent>
39 #endif
40
41 using namespace WebKit;
42 using namespace WebCore;
43
44 QWKPagePrivate::QWKPagePrivate(QWKPage* qq, WKPageNamespaceRef namespaceRef)
45     : q(qq)
46     , createNewPageFn(0)
47 {
48     memset(actions, 0, sizeof(actions));
49     page = toWK(namespaceRef)->createWebPage();
50     page->setPageClient(this);
51 }
52
53 QWKPagePrivate::~QWKPagePrivate()
54 {
55     page->close();
56 }
57
58 void QWKPagePrivate::init(const QSize& viewportSize, PassOwnPtr<DrawingAreaProxy> proxy)
59 {
60     page->initializeWebPage(IntSize(viewportSize), proxy);
61 }
62
63 void QWKPagePrivate::setCursor(const WebCore::Cursor& cursor)
64 {
65 #ifndef QT_NO_CURSOR
66     emit q->cursorChanged(*cursor.platformCursor());
67 #endif
68 }
69
70 void QWKPagePrivate::toolTipChanged(const String&, const String& newTooltip)
71 {
72     emit q->statusBarMessage(QString(newTooltip));
73 }
74
75 void QWKPagePrivate::registerEditCommand(PassRefPtr<WebEditCommandProxy>, UndoOrRedo)
76 {
77 }
78
79 void QWKPagePrivate::clearAllEditCommands()
80 {
81 }
82
83 void QWKPagePrivate::paint(QPainter* painter, QRect area)
84 {
85     painter->save();
86
87     painter->setBrush(Qt::white);
88     painter->drawRect(area);
89
90     if (page->isValid() && page->drawingArea())
91         page->drawingArea()->paint(IntRect(area), painter);
92
93     painter->restore();
94 }
95
96 void QWKPagePrivate::keyPressEvent(QKeyEvent* ev)
97 {
98     WebKeyboardEvent keyboardEvent = WebEventFactory::createWebKeyboardEvent(ev);
99     page->keyEvent(keyboardEvent);
100 }
101
102 void QWKPagePrivate::keyReleaseEvent(QKeyEvent* ev)
103 {
104     WebKeyboardEvent keyboardEvent = WebEventFactory::createWebKeyboardEvent(ev);
105     page->keyEvent(keyboardEvent);
106 }
107
108 void QWKPagePrivate::mouseMoveEvent(QGraphicsSceneMouseEvent* ev)
109 {
110     // For some reason mouse press results in mouse hover (which is
111     // converted to mouse move for WebKit). We ignore these hover
112     // events by comparing lastPos with newPos.
113     // NOTE: lastPos from the event always comes empty, so we work
114     // around that here.
115     static QPointF lastPos = QPointF();
116     if (lastPos == ev->pos())
117         return;
118     lastPos = ev->pos();
119
120     WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 0);
121     page->mouseEvent(mouseEvent);
122 }
123
124 void QWKPagePrivate::mousePressEvent(QGraphicsSceneMouseEvent* ev)
125 {
126     if (tripleClickTimer.isActive() && (ev->pos() - tripleClick).manhattanLength() < QApplication::startDragDistance()) {
127         WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 3);
128         page->mouseEvent(mouseEvent);
129         return;
130     }
131
132     WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 1);
133     page->mouseEvent(mouseEvent);
134 }
135
136 void QWKPagePrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* ev)
137 {
138     WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 0);
139     page->mouseEvent(mouseEvent);
140 }
141
142 void QWKPagePrivate::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* ev)
143 {
144     WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 2);
145     page->mouseEvent(mouseEvent);
146
147     tripleClickTimer.start(QApplication::doubleClickInterval(), q);
148     tripleClick = ev->pos().toPoint();
149 }
150
151 void QWKPagePrivate::wheelEvent(QGraphicsSceneWheelEvent* ev)
152 {
153     WebWheelEvent wheelEvent = WebEventFactory::createWebWheelEvent(ev);
154     page->wheelEvent(wheelEvent);
155 }
156
157 void QWKPagePrivate::updateAction(QWKPage::WebAction action)
158 {
159 #ifdef QT_NO_ACTION
160     Q_UNUSED(action)
161 #else
162     QAction* a = actions[action];
163     if (!a)
164         return;
165
166     RefPtr<WebKit::WebFrameProxy> mainFrame = page->mainFrame();
167     if (!mainFrame)
168         return;
169
170     bool enabled = a->isEnabled();
171     bool checked = a->isChecked();
172
173     switch (action) {
174     case QWKPage::Back:
175         enabled = page->canGoBack();
176         break;
177     case QWKPage::Forward:
178         enabled = page->canGoForward();
179         break;
180     case QWKPage::Stop:
181         enabled = !(WebFrameProxy::LoadStateFinished == mainFrame->loadState());
182         break;
183     case QWKPage::Reload:
184         enabled = (WebFrameProxy::LoadStateFinished == mainFrame->loadState());
185         break;
186     default:
187         break;
188     }
189
190     a->setEnabled(enabled);
191
192     if (a->isCheckable())
193         a->setChecked(checked);
194 #endif // QT_NO_ACTION
195 }
196
197 void QWKPagePrivate::updateNavigationActions()
198 {
199     updateAction(QWKPage::Back);
200     updateAction(QWKPage::Forward);
201     updateAction(QWKPage::Stop);
202     updateAction(QWKPage::Reload);
203 }
204
205 #ifndef QT_NO_ACTION
206 void QWKPagePrivate::_q_webActionTriggered(bool checked)
207 {
208     QAction* a = qobject_cast<QAction*>(q->sender());
209     if (!a)
210         return;
211     QWKPage::WebAction action = static_cast<QWKPage::WebAction>(a->data().toInt());
212     q->triggerAction(action, checked);
213 }
214 #endif // QT_NO_ACTION
215
216 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
217
218 void QWKPagePrivate::touchEvent(QTouchEvent* event)
219 {
220     WebTouchEvent touchEvent = WebEventFactory::createWebTouchEvent(event);
221     page->touchEvent(touchEvent);
222 }
223
224 #endif
225
226 QWKPage::QWKPage(WKPageNamespaceRef namespaceRef)
227     : d(new QWKPagePrivate(this, namespaceRef))
228 {
229     WKPageLoaderClient loadClient = {
230         0,      /* version */
231         this,   /* clientInfo */
232         qt_wk_didStartProvisionalLoadForFrame,
233         qt_wk_didReceiveServerRedirectForProvisionalLoadForFrame,
234         qt_wk_didFailProvisionalLoadWithErrorForFrame,
235         qt_wk_didCommitLoadForFrame,
236         qt_wk_didFinishDocumentLoadForFrame,
237         qt_wk_didFinishLoadForFrame,
238         qt_wk_didFailLoadWithErrorForFrame,
239         qt_wk_didReceiveTitleForFrame,
240         qt_wk_didFirstLayoutForFrame,
241         qt_wk_didFirstVisuallyNonEmptyLayoutForFrame,
242         qt_wk_didStartProgress,
243         qt_wk_didChangeProgress,
244         qt_wk_didFinishProgress,
245         qt_wk_didBecomeUnresponsive,
246         qt_wk_didBecomeResponsive,
247         0,  /* processDidExit */
248         0   /* didChangeBackForwardList */
249     };
250     WKPageSetPageLoaderClient(pageRef(), &loadClient);
251
252     WKPageUIClient uiClient = {
253         0,      /* version */
254         this,   /* clientInfo */
255         qt_wk_createNewPage,
256         qt_wk_showPage,
257         qt_wk_close,
258         qt_wk_runJavaScriptAlert,
259         0,  /* runJavaScriptConfirm */
260         0,  /* runJavaScriptPrompt */
261         0   /* setStatusText */
262         0   /* contentsSizeChanged */
263     };
264     WKPageSetPageUIClient(pageRef(), &uiClient);
265 }
266
267 QWKPage::~QWKPage()
268 {
269     delete d;
270 }
271
272 void QWKPage::timerEvent(QTimerEvent* ev)
273 {
274     int timerId = ev->timerId();
275     if (timerId == d->tripleClickTimer.timerId())
276         d->tripleClickTimer.stop();
277     else
278         QObject::timerEvent(ev);
279 }
280
281 WKPageRef QWKPage::pageRef() const
282 {
283     return toRef(d->page.get());
284 }
285
286 void QWKPage::setCreateNewPageFunction(CreateNewPageFn function)
287 {
288     d->createNewPageFn = function;
289 }
290
291 void QWKPage::load(const QUrl& url)
292 {
293     WKRetainPtr<WKURLRef> wkurl(WKURLCreateWithQUrl(url));
294     WKPageLoadURL(pageRef(), wkurl.get());
295 }
296
297 void QWKPage::setUrl(const QUrl& url)
298 {
299     load(url);
300 }
301
302 QUrl QWKPage::url() const
303 {
304     WKRetainPtr<WKFrameRef> frame = WKPageGetMainFrame(pageRef());
305     if (!frame)
306         return QUrl();
307     return WKURLCopyQUrl(WKFrameCopyURL(frame.get()));
308 }
309
310 QString QWKPage::title() const
311 {
312     return WKStringCopyQString(WKPageCopyTitle(pageRef()));
313 }
314
315 void QWKPage::setViewportSize(const QSize& size)
316 {
317     if (d->page->drawingArea())
318         d->page->drawingArea()->setSize(IntSize(size));
319 }
320
321 #ifndef QT_NO_ACTION
322 void QWKPage::triggerAction(WebAction action, bool)
323 {
324     switch (action) {
325     case Back:
326         d->page->goBack();
327         break;
328     case Forward:
329         d->page->goForward();
330         break;
331     case Stop:
332         d->page->stopLoading();
333         break;
334     case Reload:
335         d->page->reload(/* reloadFromOrigin */ true);
336         break;
337     default:
338         break;
339     }
340 }
341 #endif // QT_NO_ACTION
342
343 #ifndef QT_NO_ACTION
344 QAction* QWKPage::action(WebAction action) const
345 {
346     if (action == QWKPage::NoWebAction || action >= WebActionCount)
347         return 0;
348
349     if (d->actions[action])
350         return d->actions[action];
351
352     QString text;
353     QIcon icon;
354     QStyle* style = qobject_cast<QApplication*>(QCoreApplication::instance())->style();
355     bool checkable = false;
356
357     switch (action) {
358     case Back:
359         text = contextMenuItemTagGoBack();
360         icon = style->standardIcon(QStyle::SP_ArrowBack);
361         break;
362     case Forward:
363         text = contextMenuItemTagGoForward();
364         icon = style->standardIcon(QStyle::SP_ArrowForward);
365         break;
366     case Stop:
367         text = contextMenuItemTagStop();
368         icon = style->standardIcon(QStyle::SP_BrowserStop);
369         break;
370     case Reload:
371         text = contextMenuItemTagReload();
372         icon = style->standardIcon(QStyle::SP_BrowserReload);
373         break;
374     default:
375         return 0;
376         break;
377     }
378
379     if (text.isEmpty())
380         return 0;
381
382     QAction* a = new QAction(d->q);
383     a->setText(text);
384     a->setData(action);
385     a->setCheckable(checkable);
386     a->setIcon(icon);
387
388     connect(a, SIGNAL(triggered(bool)), this, SLOT(_q_webActionTriggered(bool)));
389
390     d->actions[action] = a;
391     d->updateAction(action);
392     return a;
393 }
394 #endif // QT_NO_ACTION
395
396 #include "moc_qwkpage.cpp"