2009-12-07 Benjamin Poulain <benjamin.poulain@nokia.com>
[WebKit-https.git] / WebKit / qt / QGVLauncher / main.cpp
1 /*
2  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3  * Copyright (C) 2006 George Staikos <staikos@kde.org>
4  * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
5  * Copyright (C) 2006 Zack Rusin <zack@kde.org>
6  * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
7  * Copyright (C) 2009 Kenneth Christiansen <kenneth@webkit.org>
8  * Copyright (C) 2009 Antonio Gomes <antonio.gomes@openbossa.org>
9  * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
10  *
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
23  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
26  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
30  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <QDebug>
36 #include <QFile>
37 #include <QGraphicsScene>
38 #include <QGraphicsView>
39 #include <QGraphicsWidget>
40 #include <QNetworkRequest>
41 #include <QTextStream>
42 #include <QVector>
43 #include <QtGui>
44 #include <QtNetwork/QNetworkProxy>
45 #include <cstdio>
46 #include <qwebelement.h>
47 #include <qwebframe.h>
48 #include <qgraphicswebview.h>
49 #include <qwebpage.h>
50 #include <qwebsettings.h>
51 #include <qwebview.h>
52
53 static QUrl urlFromUserInput(const QString& string)
54 {
55     QString input(string);
56     QFileInfo fi(input);
57     if (fi.exists() && fi.isRelative())
58         input = fi.absoluteFilePath();
59
60 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
61     return QUrl::fromUserInput(input);
62 #else
63     return QUrl(input);
64 #endif
65 }
66
67 class WebView : public QGraphicsWebView {
68     Q_OBJECT
69     Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation)
70
71 public:
72     WebView(QGraphicsItem* parent = 0)
73         : QGraphicsWebView(parent)
74     {
75     }
76     void setYRotation(qreal angle)
77     {
78 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
79         QRectF r = boundingRect();
80         setTransform(QTransform()
81             .translate(r.width() / 2, r.height() / 2)
82             .rotate(angle, Qt::YAxis)
83             .translate(-r.width() / 2, -r.height() / 2));
84 #endif
85         m_yRotation = angle;
86     }
87     qreal yRotation() const
88     {
89         return m_yRotation;
90     }
91
92 private:
93     qreal m_yRotation;
94 };
95
96 class WebPage : public QWebPage {
97     Q_OBJECT
98
99 public:
100     WebPage(QObject* parent = 0)
101         : QWebPage(parent)
102     {
103         applyProxy();
104     }
105     virtual QWebPage* createWindow(QWebPage::WebWindowType);
106
107 private:
108     void applyProxy()
109     {
110         QUrl proxyUrl = urlFromUserInput(qgetenv("http_proxy"));
111
112         if (proxyUrl.isValid() && !proxyUrl.host().isEmpty()) {
113             int proxyPort = (proxyUrl.port() > 0) ? proxyUrl.port() : 8080;
114             networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, proxyUrl.host(), proxyPort));
115         }
116     }
117 };
118
119 class MainView : public QGraphicsView {
120     Q_OBJECT
121
122 public:
123     MainView(QWidget* parent)
124         : QGraphicsView(parent)
125         , m_mainWidget(0)
126     {
127         setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
128         setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
129
130         setFrameShape(QFrame::NoFrame);
131         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
132     }
133
134     void setMainWidget(QGraphicsWidget* widget)
135     {
136         QRectF rect(QRect(QPoint(0, 0), size()));
137         widget->setGeometry(rect);
138         m_mainWidget = widget;
139     }
140
141     void resizeEvent(QResizeEvent* event)
142     {
143         QGraphicsView::resizeEvent(event);
144         if (!m_mainWidget)
145             return;
146         QRectF rect(QPoint(0, 0), event->size());
147         m_mainWidget->setGeometry(rect);
148     }
149
150     void setWaitCursor()
151     {
152         m_mainWidget->setCursor(Qt::WaitCursor);
153     }
154
155     void resetCursor()
156     {
157         m_mainWidget->unsetCursor();
158     }
159
160 public slots:
161     void flip()
162     {
163 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
164         QSizeF center = m_mainWidget->boundingRect().size() / 2;
165         QPointF centerPoint = QPointF(center.width(), center.height());
166         m_mainWidget->setTransformOriginPoint(centerPoint);
167
168         m_mainWidget->setRotation(m_mainWidget->rotation() ? 0 : 180);
169 #endif
170     }
171
172     void animatedFlip()
173     {
174 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
175         QSizeF center = m_mainWidget->boundingRect().size() / 2;
176         QPointF centerPoint = QPointF(center.width(), center.height());
177         m_mainWidget->setTransformOriginPoint(centerPoint);
178
179         QPropertyAnimation* animation = new QPropertyAnimation(m_mainWidget, "rotation", this);
180         animation->setDuration(1000);
181
182         int rotation = int(m_mainWidget->rotation());
183
184         animation->setStartValue(rotation);
185         animation->setEndValue(rotation + 180 - (rotation % 180));
186
187         animation->start(QAbstractAnimation::DeleteWhenStopped);
188 #endif
189     }
190
191     void animatedYFlip()
192     {
193         emit flipRequest();
194     }
195
196 signals:
197     void flipRequest();
198
199 private:
200     QGraphicsWidget* m_mainWidget;
201 };
202
203 class SharedScene : public QSharedData {
204 public:
205     SharedScene()
206     {
207         m_scene = new QGraphicsScene;
208         m_item = new WebView;
209         m_item->setPage((m_page = new WebPage));
210
211         m_scene->addItem(m_item);
212         m_scene->setActiveWindow(m_item);
213     }
214
215     ~SharedScene()
216     {
217         delete m_item;
218         delete m_scene;
219         delete m_page;
220     }
221
222     QGraphicsScene* scene() const { return m_scene; }
223     WebView* webView() const { return m_item; }
224
225 private:
226     QGraphicsScene* m_scene;
227     WebView* m_item;
228     WebPage* m_page;
229 };
230
231 class MainWindow : public QMainWindow {
232     Q_OBJECT
233
234 public:
235     MainWindow(QExplicitlySharedDataPointer<SharedScene> other)
236         : QMainWindow()
237         , view(new MainView(this))
238         , scene(other)
239     {
240         init();
241     }
242
243     MainWindow()
244         : QMainWindow()
245         , view(new MainView(this))
246         , scene(new SharedScene())
247     {
248         init();
249     }
250
251     void init()
252     {
253         setAttribute(Qt::WA_DeleteOnClose);
254
255         view->setScene(scene->scene());
256
257         setCentralWidget(view);
258
259         view->setMainWidget(scene->webView());
260
261         connect(scene->webView(), SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
262         connect(scene->webView(), SIGNAL(titleChanged(const QString&)), this, SLOT(setWindowTitle(const QString&)));
263         connect(scene->webView()->page(), SIGNAL(windowCloseRequested()), this, SLOT(close()));
264
265 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
266         QStateMachine *machine = new QStateMachine(this);
267         QState *s0 = new QState(machine);
268         s0->assignProperty(scene->webView(), "yRotation", 0);
269
270         QState *s1 = new QState(machine);
271         s1->assignProperty(scene->webView(), "yRotation", 90);
272
273         QAbstractTransition *t1 = s0->addTransition(view, SIGNAL(flipRequest()), s1);
274         QPropertyAnimation *yRotationAnim = new QPropertyAnimation(scene->webView(), "yRotation", this);
275         yRotationAnim->setDuration(1000);
276         t1->addAnimation(yRotationAnim);
277
278         QState *s2 = new QState(machine);
279         s2->assignProperty(scene->webView(), "yRotation", -90);
280         s1->addTransition(s1, SIGNAL(polished()), s2);
281
282         QAbstractTransition *t2 = s2->addTransition(s0);
283         t2->addAnimation(yRotationAnim);
284
285         machine->setInitialState(s0);
286         machine->start();
287 #endif
288
289         resize(640, 480);
290         buildUI();
291     }
292
293     void load(const QString& url)
294     {
295         QUrl deducedUrl = urlFromUserInput(url);
296         if (!deducedUrl.isValid())
297             deducedUrl = QUrl("http://" + url + "/");
298
299         urlEdit->setText(deducedUrl.toEncoded());
300         scene->webView()->load(deducedUrl);
301         scene->webView()->setFocus(Qt::OtherFocusReason);
302     }
303
304     QWebPage* page() const
305     {
306         return scene->webView()->page();
307     }
308
309 protected slots:
310     void changeLocation()
311     {
312         load(urlEdit->text());
313     }
314
315     void loadFinished(bool)
316     {
317         QUrl url = scene->webView()->url();
318         urlEdit->setText(url.toString());
319
320         QUrl::FormattingOptions opts;
321         opts |= QUrl::RemoveScheme;
322         opts |= QUrl::RemoveUserInfo;
323         opts |= QUrl::StripTrailingSlash;
324         QString s = url.toString(opts);
325         s = s.mid(2);
326         if (s.isEmpty())
327             return;
328         //FIXME: something missing here
329     }
330
331 public slots:
332     void newWindow(const QString &url = QString())
333     {
334         MainWindow* mw = new MainWindow();
335         mw->load(url);
336         mw->show();
337     }
338
339     void clone()
340     {
341         MainWindow* mw = new MainWindow(scene);
342         mw->show();
343     }
344
345     void setWaitCursor()
346     {
347         view->setWaitCursor();
348     }
349
350     void resetCursor()
351     {
352         view->resetCursor();
353     }
354
355     void flip()
356     {
357         view->flip();
358     }
359
360     void animatedFlip()
361     {
362         view->animatedFlip();
363     }
364
365     void animatedYFlip()
366     {
367         view->animatedYFlip();
368     }
369
370 private:
371     void buildUI()
372     {
373         QWebPage* page = scene->webView()->page();
374         urlEdit = new QLineEdit(this);
375         urlEdit->setSizePolicy(QSizePolicy::Expanding, urlEdit->sizePolicy().verticalPolicy());
376         connect(urlEdit, SIGNAL(returnPressed()), SLOT(changeLocation()));
377
378         QToolBar* bar = addToolBar("Navigation");
379         bar->addAction(page->action(QWebPage::Back));
380         bar->addAction(page->action(QWebPage::Forward));
381         bar->addAction(page->action(QWebPage::Reload));
382         bar->addAction(page->action(QWebPage::Stop));
383         bar->addWidget(urlEdit);
384
385         QMenu* fileMenu = menuBar()->addMenu("&File");
386         fileMenu->addAction("New Window", this, SLOT(newWindow()));
387         fileMenu->addAction("Clone view", this, SLOT(clone()));
388         fileMenu->addAction("Close", this, SLOT(close()));
389
390         QMenu* viewMenu = menuBar()->addMenu("&View");
391         viewMenu->addAction(page->action(QWebPage::Stop));
392         viewMenu->addAction(page->action(QWebPage::Reload));
393
394         QMenu* testMenu = menuBar()->addMenu("&Tests");
395         testMenu->addAction("Set Wait Cursor", this, SLOT(setWaitCursor()), QKeySequence("Ctrl+W"));
396         testMenu->addAction("Reset Cursor", this, SLOT(resetCursor()), QKeySequence("Ctrl+Shift+W"));
397
398         QMenu* fxMenu = menuBar()->addMenu("&Effects");
399         fxMenu->addAction("Flip", this, SLOT(flip()));
400         fxMenu->addAction("Animated Flip", this, SLOT(animatedFlip()), QKeySequence("Ctrl+R"));
401         fxMenu->addAction("Animated Y-Flip", this, SLOT(animatedYFlip()), QKeySequence("Ctrl+Y"));
402     }
403
404 private:
405     MainView* view;
406     QExplicitlySharedDataPointer<SharedScene> scene;
407
408     QLineEdit* urlEdit;
409 };
410
411 QWebPage* WebPage::createWindow(QWebPage::WebWindowType)
412 {
413     MainWindow* mw = new MainWindow;
414     mw->show();
415     return mw->page();
416 }
417
418 int main(int argc, char** argv)
419 {
420     QApplication app(argc, argv);
421     QString url = QString("file://%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
422
423     app.setApplicationName("GQVLauncher");
424
425     QWebSettings::setObjectCacheCapacities((16 * 1024 * 1024) / 8, (16 * 1024 * 1024) / 8, 16 * 1024 * 1024);
426     QWebSettings::setMaximumPagesInCache(4);
427     QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
428     QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
429     QWebSettings::globalSettings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
430
431     const QStringList args = app.arguments();
432     if (args.count() > 1)
433         url = args.at(1);
434
435     MainWindow* window = new MainWindow;
436     window->load(url);
437
438     for (int i = 2; i < args.count(); i++)
439         window->newWindow(args.at(i));
440
441     window->show();
442     return app.exec();
443 }
444
445 #include "main.moc"