• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3  * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
4  * Copyright (C) 2006 George Staikos <staikos@kde.org>
5  * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
6  * Copyright (C) 2006 Zack Rusin <zack@kde.org>
7  * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <QtGui>
34 #include <QtNetwork/QNetworkRequest>
35 #if !defined(QT_NO_PRINTER)
36 #include <QPrintPreviewDialog>
37 #endif
38 
39 #ifndef QT_NO_UITOOLS
40 #include <QtUiTools/QUiLoader>
41 #endif
42 
43 #include <QDebug>
44 
45 #include <cstdio>
46 #include "mainwindow.h"
47 #include <qevent.h>
48 #include <qwebelement.h>
49 #include <qwebframe.h>
50 #include <qwebinspector.h>
51 #include <qwebsettings.h>
52 
53 #ifdef Q_WS_MAEMO_5
54 #include <qx11info_x11.h>
55 #endif
56 
57 #include "urlloader.h"
58 #include "utils.h"
59 #include "webinspector.h"
60 #include "webpage.h"
61 #include "webview.h"
62 
63 #ifdef Q_WS_MAEMO_5
64 #include <X11/Xatom.h>
65 #include <X11/Xlib.h>
66 #undef KeyPress
67 #endif
68 
69 #ifndef NDEBUG
70 void QWEBKIT_EXPORT qt_drt_garbageCollector_collect();
71 #endif
72 
73 
74 static bool gUseGraphicsView = false;
75 static bool gUseCompositing = false;
76 static bool gCacheWebView = false;
77 static bool gShowFrameRate = false;
78 static QGraphicsView::ViewportUpdateMode gViewportUpdateMode = QGraphicsView::MinimalViewportUpdate;
79 
80 
81 class LauncherWindow : public MainWindow {
82     Q_OBJECT
83 
84 public:
85     LauncherWindow(QString url = QString());
86     virtual ~LauncherWindow();
87 
88     virtual void keyPressEvent(QKeyEvent* event);
89     void grabZoomKeys(bool grab);
90 
91 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
92     void sendTouchEvent();
93     bool eventFilter(QObject* obj, QEvent* event);
94 #endif
95 
96 protected slots:
97     void loadStarted();
98     void loadFinished();
99 
100     void showLinkHover(const QString &link, const QString &toolTip);
101 
102     void zoomIn();
103     void zoomOut();
104     void resetZoom();
105     void toggleZoomTextOnly(bool on);
106 
107     void print();
108     void screenshot();
109 
110     void setEditable(bool on);
111 
112     /* void dumpPlugins() */
113     void dumpHtml();
114 
115     void selectElements();
116 
117     void setTouchMocking(bool on);
118     void toggleAcceleratedCompositing(bool toggle);
119     void initializeView(bool useGraphicsView = false);
120 
121 public slots:
122     void newWindow(const QString& url = QString());
123 
124 private:
125     // create the status bar, tool bar & menu
126     void setupUI();
127 
128 private:
129     QVector<int> zoomLevels;
130     int currentZoom;
131 
132     QWidget* m_view;
133     WebInspector* inspector;
134 
135     QAction* formatMenuAction;
136 
137 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
138     QList<QTouchEvent::TouchPoint> touchPoints;
139     bool touchMocking;
140 #endif
141 };
142 
143 
LauncherWindow(QString url)144 LauncherWindow::LauncherWindow(QString url)
145     : MainWindow(url)
146     , currentZoom(100)
147 {
148     QSplitter* splitter = new QSplitter(Qt::Vertical, this);
149     setCentralWidget(splitter);
150 
151 #if defined(Q_WS_S60)
152     showMaximized();
153 #else
154     resize(800, 600);
155 #endif
156 
157     m_view = 0;
158     initializeView();
159 
160     connect(page(), SIGNAL(loadStarted()), this, SLOT(loadStarted()));
161     connect(page(), SIGNAL(loadFinished(bool)), this, SLOT(loadFinished()));
162     connect(page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)),
163             this, SLOT(showLinkHover(const QString&, const QString&)));
164 
165     inspector = new WebInspector(splitter);
166     inspector->setPage(page());
167     inspector->hide();
168     connect(this, SIGNAL(destroyed()), inspector, SLOT(deleteLater()));
169 
170     setupUI();
171 
172     // the zoom values are chosen to be like in Mozilla Firefox 3
173     zoomLevels << 30 << 50 << 67 << 80 << 90;
174     zoomLevels << 100;
175     zoomLevels << 110 << 120 << 133 << 150 << 170 << 200 << 240 << 300;
176 
177     grabZoomKeys(true);
178 
179     load(url);
180 }
181 
~LauncherWindow()182 LauncherWindow::~LauncherWindow()
183 {
184     grabZoomKeys(false);
185 }
186 
keyPressEvent(QKeyEvent * event)187 void LauncherWindow::keyPressEvent(QKeyEvent* event)
188 {
189 #ifdef Q_WS_MAEMO_5
190     switch (event->key()) {
191     case Qt::Key_F7:
192         zoomIn();
193         event->accept();
194         break;
195     case Qt::Key_F8:
196         zoomOut();
197         event->accept();
198         break;
199     }
200 #endif
201     MainWindow::keyPressEvent(event);
202 }
203 
grabZoomKeys(bool grab)204 void LauncherWindow::grabZoomKeys(bool grab)
205 {
206 #ifdef Q_WS_MAEMO_5
207     if (!winId()) {
208         qWarning("Can't grab keys unless we have a window id");
209         return;
210     }
211 
212     Atom atom = XInternAtom(QX11Info::display(), "_HILDON_ZOOM_KEY_ATOM", False);
213     if (!atom) {
214         qWarning("Unable to obtain _HILDON_ZOOM_KEY_ATOM");
215         return;
216     }
217 
218     unsigned long val = (grab) ? 1 : 0;
219     XChangeProperty(QX11Info::display(), winId(), atom, XA_INTEGER, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&val), 1);
220 #endif
221 }
222 
223 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
sendTouchEvent()224 void LauncherWindow::sendTouchEvent()
225 {
226     if (touchPoints.isEmpty())
227         return;
228 
229     QEvent::Type type = QEvent::TouchUpdate;
230     if (touchPoints.size() == 1) {
231         if (touchPoints[0].state() == Qt::TouchPointReleased)
232             type = QEvent::TouchEnd;
233         else if (touchPoints[0].state() == Qt::TouchPointPressed)
234             type = QEvent::TouchBegin;
235     }
236 
237     QTouchEvent touchEv(type);
238     touchEv.setTouchPoints(touchPoints);
239     QCoreApplication::sendEvent(page(), &touchEv);
240 
241     // After sending the event, remove all touchpoints that were released
242     if (touchPoints[0].state() == Qt::TouchPointReleased)
243         touchPoints.removeAt(0);
244     if (touchPoints.size() > 1 && touchPoints[1].state() == Qt::TouchPointReleased)
245         touchPoints.removeAt(1);
246 }
247 
eventFilter(QObject * obj,QEvent * event)248 bool LauncherWindow::eventFilter(QObject* obj, QEvent* event)
249 {
250     if (!touchMocking || obj != m_view)
251         return QObject::eventFilter(obj, event);
252 
253     if (event->type() == QEvent::MouseButtonPress
254         || event->type() == QEvent::MouseButtonRelease
255         || event->type() == QEvent::MouseButtonDblClick
256         || event->type() == QEvent::MouseMove) {
257 
258         QMouseEvent* ev = static_cast<QMouseEvent*>(event);
259         if (ev->type() == QEvent::MouseMove
260             && !(ev->buttons() & Qt::LeftButton))
261             return false;
262 
263         QTouchEvent::TouchPoint touchPoint;
264         touchPoint.setState(Qt::TouchPointMoved);
265         if ((ev->type() == QEvent::MouseButtonPress
266              || ev->type() == QEvent::MouseButtonDblClick))
267             touchPoint.setState(Qt::TouchPointPressed);
268         else if (ev->type() == QEvent::MouseButtonRelease)
269             touchPoint.setState(Qt::TouchPointReleased);
270 
271         touchPoint.setId(0);
272         touchPoint.setScreenPos(ev->globalPos());
273         touchPoint.setPos(ev->pos());
274         touchPoint.setPressure(1);
275 
276         // If the point already exists, update it. Otherwise create it.
277         if (touchPoints.size() > 0 && !touchPoints[0].id())
278             touchPoints[0] = touchPoint;
279         else if (touchPoints.size() > 1 && !touchPoints[1].id())
280             touchPoints[1] = touchPoint;
281         else
282             touchPoints.append(touchPoint);
283 
284         sendTouchEvent();
285     } else if (event->type() == QEvent::KeyPress
286         && static_cast<QKeyEvent*>(event)->key() == Qt::Key_F
287         && static_cast<QKeyEvent*>(event)->modifiers() == Qt::ControlModifier) {
288 
289         // If the keyboard point is already pressed, release it.
290         // Otherwise create it and append to touchPoints.
291         if (touchPoints.size() > 0 && touchPoints[0].id() == 1) {
292             touchPoints[0].setState(Qt::TouchPointReleased);
293             sendTouchEvent();
294         } else if (touchPoints.size() > 1 && touchPoints[1].id() == 1) {
295             touchPoints[1].setState(Qt::TouchPointReleased);
296             sendTouchEvent();
297         } else {
298             QTouchEvent::TouchPoint touchPoint;
299             touchPoint.setState(Qt::TouchPointPressed);
300             touchPoint.setId(1);
301             touchPoint.setScreenPos(QCursor::pos());
302             touchPoint.setPos(m_view->mapFromGlobal(QCursor::pos()));
303             touchPoint.setPressure(1);
304             touchPoints.append(touchPoint);
305             sendTouchEvent();
306 
307             // After sending the event, change the touchpoint state to stationary
308             touchPoints.last().setState(Qt::TouchPointStationary);
309         }
310     }
311     return false;
312 }
313 #endif // QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
314 
loadStarted()315 void LauncherWindow::loadStarted()
316 {
317     m_view->setFocus(Qt::OtherFocusReason);
318 }
319 
loadFinished()320 void LauncherWindow::loadFinished()
321 {
322     QUrl url = page()->mainFrame()->url();
323     setAddressUrl(url.toString());
324     addCompleterEntry(url);
325 }
326 
showLinkHover(const QString & link,const QString & toolTip)327 void LauncherWindow::showLinkHover(const QString &link, const QString &toolTip)
328 {
329 #ifndef Q_WS_MAEMO_5
330     statusBar()->showMessage(link);
331 #endif
332 #ifndef QT_NO_TOOLTIP
333     if (!toolTip.isEmpty())
334         QToolTip::showText(QCursor::pos(), toolTip);
335 #endif
336 }
337 
zoomIn()338 void LauncherWindow::zoomIn()
339 {
340     int i = zoomLevels.indexOf(currentZoom);
341     Q_ASSERT(i >= 0);
342     if (i < zoomLevels.count() - 1)
343         currentZoom = zoomLevels[i + 1];
344 
345     page()->mainFrame()->setZoomFactor(qreal(currentZoom) / 100.0);
346 }
347 
zoomOut()348 void LauncherWindow::zoomOut()
349 {
350     int i = zoomLevels.indexOf(currentZoom);
351     Q_ASSERT(i >= 0);
352     if (i > 0)
353         currentZoom = zoomLevels[i - 1];
354 
355     page()->mainFrame()->setZoomFactor(qreal(currentZoom) / 100.0);
356 }
357 
resetZoom()358 void LauncherWindow::resetZoom()
359 {
360    currentZoom = 100;
361    page()->mainFrame()->setZoomFactor(1.0);
362 }
363 
toggleZoomTextOnly(bool b)364 void LauncherWindow::toggleZoomTextOnly(bool b)
365 {
366     page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, b);
367 }
368 
print()369 void LauncherWindow::print()
370 {
371 #if !defined(QT_NO_PRINTER)
372     QPrintPreviewDialog dlg(this);
373     connect(&dlg, SIGNAL(paintRequested(QPrinter*)),
374             m_view, SLOT(print(QPrinter*)));
375     dlg.exec();
376 #endif
377 }
378 
screenshot()379 void LauncherWindow::screenshot()
380 {
381     QPixmap pixmap = QPixmap::grabWidget(m_view);
382     QLabel* label = new QLabel;
383     label->setAttribute(Qt::WA_DeleteOnClose);
384     label->setWindowTitle("Screenshot - Preview");
385     label->setPixmap(pixmap);
386     label->show();
387 
388     QString fileName = QFileDialog::getSaveFileName(label, "Screenshot");
389     if (!fileName.isEmpty()) {
390         pixmap.save(fileName, "png");
391         label->setWindowTitle(QString("Screenshot - Saved at %1").arg(fileName));
392     }
393 }
394 
setEditable(bool on)395 void LauncherWindow::setEditable(bool on)
396 {
397     page()->setContentEditable(on);
398     formatMenuAction->setVisible(on);
399 }
400 
401 /*
402 void LauncherWindow::dumpPlugins() {
403     QList<QWebPluginInfo> plugins = QWebSettings::pluginDatabase()->plugins();
404     foreach (const QWebPluginInfo plugin, plugins) {
405         qDebug() << "Plugin:" << plugin.name();
406         foreach (const QWebPluginInfo::MimeType mime, plugin.mimeTypes()) {
407             qDebug() << "   " << mime.name;
408         }
409     }
410 }
411 */
412 
dumpHtml()413 void LauncherWindow::dumpHtml()
414 {
415     qDebug() << "HTML: " << page()->mainFrame()->toHtml();
416 }
417 
selectElements()418 void LauncherWindow::selectElements()
419 {
420     bool ok;
421     QString str = QInputDialog::getText(this, "Select elements", "Choose elements",
422                                         QLineEdit::Normal, "a", &ok);
423 
424     if (ok && !str.isEmpty()) {
425         QWebElementCollection result =  page()->mainFrame()->findAllElements(str);
426         foreach (QWebElement e, result)
427             e.setStyleProperty("background-color", "yellow");
428 #ifndef Q_WS_MAEMO_5
429         statusBar()->showMessage(QString("%1 element(s) selected").arg(result.count()), 5000);
430 #endif
431     }
432 }
433 
setTouchMocking(bool on)434 void LauncherWindow::setTouchMocking(bool on)
435 {
436 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
437     touchMocking = on;
438 #endif
439 }
440 
toggleAcceleratedCompositing(bool toggle)441 void LauncherWindow::toggleAcceleratedCompositing(bool toggle)
442 {
443     page()->settings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, toggle);
444 }
445 
initializeView(bool useGraphicsView)446 void LauncherWindow::initializeView(bool useGraphicsView)
447 {
448     delete m_view;
449 
450     QSplitter* splitter = static_cast<QSplitter*>(centralWidget());
451 
452     if (!useGraphicsView) {
453         WebViewTraditional* view = new WebViewTraditional(splitter);
454         view->setPage(page());
455         m_view = view;
456     } else {
457         WebViewGraphicsBased* view = new WebViewGraphicsBased(splitter);
458         view->setPage(page());
459         view->setViewportUpdateMode(gViewportUpdateMode);
460         view->setItemCacheMode(gCacheWebView ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache);
461         if (gShowFrameRate)
462             view->enableFrameRateMeasurement();
463         page()->settings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, gUseCompositing);
464         m_view = view;
465     }
466 
467 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
468     m_view->installEventFilter(this);
469     touchMocking = false;
470 #endif
471 }
472 
newWindow(const QString & url)473 void LauncherWindow::newWindow(const QString& url)
474 {
475     LauncherWindow* mw = new LauncherWindow(url);
476     mw->show();
477 }
478 
setupUI()479 void LauncherWindow::setupUI()
480 {
481     QMenu* fileMenu = menuBar()->addMenu("&File");
482     fileMenu->addAction("New Window", this, SLOT(newWindow()), QKeySequence::New);
483     fileMenu->addAction(tr("Open File..."), this, SLOT(openFile()), QKeySequence::Open);
484     fileMenu->addAction("Close Window", this, SLOT(close()), QKeySequence::Close);
485     fileMenu->addSeparator();
486     fileMenu->addAction("Take Screen Shot...", this, SLOT(screenshot()));
487     fileMenu->addAction(tr("Print..."), this, SLOT(print()), QKeySequence::Print);
488     fileMenu->addSeparator();
489     fileMenu->addAction("Quit", QApplication::instance(), SLOT(closeAllWindows()), QKeySequence(Qt::CTRL | Qt::Key_Q));
490 
491     QMenu* editMenu = menuBar()->addMenu("&Edit");
492     editMenu->addAction(page()->action(QWebPage::Undo));
493     editMenu->addAction(page()->action(QWebPage::Redo));
494     editMenu->addSeparator();
495     editMenu->addAction(page()->action(QWebPage::Cut));
496     editMenu->addAction(page()->action(QWebPage::Copy));
497     editMenu->addAction(page()->action(QWebPage::Paste));
498     editMenu->addSeparator();
499     QAction* setEditable = editMenu->addAction("Set Editable", this, SLOT(setEditable(bool)));
500     setEditable->setCheckable(true);
501 
502     QMenu* viewMenu = menuBar()->addMenu("&View");
503     viewMenu->addAction(page()->action(QWebPage::Stop));
504     viewMenu->addAction(page()->action(QWebPage::Reload));
505     viewMenu->addSeparator();
506     QAction* zoomIn = viewMenu->addAction("Zoom &In", this, SLOT(zoomIn()));
507     QAction* zoomOut = viewMenu->addAction("Zoom &Out", this, SLOT(zoomOut()));
508     QAction* resetZoom = viewMenu->addAction("Reset Zoom", this, SLOT(resetZoom()));
509     QAction* zoomTextOnly = viewMenu->addAction("Zoom Text Only", this, SLOT(toggleZoomTextOnly(bool)));
510     zoomTextOnly->setCheckable(true);
511     zoomTextOnly->setChecked(false);
512     viewMenu->addSeparator();
513     viewMenu->addAction("Dump HTML", this, SLOT(dumpHtml()));
514     // viewMenu->addAction("Dump plugins", this, SLOT(dumpPlugins()));
515 
516     QMenu* formatMenu = new QMenu("F&ormat", this);
517     formatMenuAction = menuBar()->addMenu(formatMenu);
518     formatMenuAction->setVisible(false);
519     formatMenu->addAction(page()->action(QWebPage::ToggleBold));
520     formatMenu->addAction(page()->action(QWebPage::ToggleItalic));
521     formatMenu->addAction(page()->action(QWebPage::ToggleUnderline));
522     QMenu* writingMenu = formatMenu->addMenu(tr("Writing Direction"));
523     writingMenu->addAction(page()->action(QWebPage::SetTextDirectionDefault));
524     writingMenu->addAction(page()->action(QWebPage::SetTextDirectionLeftToRight));
525     writingMenu->addAction(page()->action(QWebPage::SetTextDirectionRightToLeft));
526 
527     zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
528     zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
529     resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
530 
531     QMenu* toolsMenu = menuBar()->addMenu("&Develop");
532     toolsMenu->addAction("Select Elements...", this, SLOT(selectElements()));
533     QAction* showInspectorAction = toolsMenu->addAction("Show Web Inspector", inspector, SLOT(setVisible(bool)), QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_I));
534     showInspectorAction->setCheckable(true);
535     showInspectorAction->connect(inspector, SIGNAL(visibleChanged(bool)), SLOT(setChecked(bool)));
536 
537 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
538     QAction* touchMockAction = toolsMenu->addAction("Toggle multitouch mocking", this, SLOT(setTouchMocking(bool)));
539     touchMockAction->setCheckable(true);
540     touchMockAction->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_T));
541 #endif
542 
543     QAction* toggleAcceleratedCompositing = toolsMenu->addAction("Toggle Accelerated Compositing", this, SLOT(toggleAcceleratedCompositing(bool)));
544     toggleAcceleratedCompositing->setCheckable(true);
545     toggleAcceleratedCompositing->setChecked(false);
546 
547     QAction* toggleGraphicsView = toolsMenu->addAction("Toggle use of QGraphicsView", this, SLOT(initializeView(bool)));
548     toggleGraphicsView->setCheckable(true);
549     toggleGraphicsView->setChecked(false);
550 }
551 
createWindow(QWebPage::WebWindowType type)552 QWebPage* WebPage::createWindow(QWebPage::WebWindowType type)
553 {
554     LauncherWindow* mw = new LauncherWindow;
555     if (type == WebModalDialog)
556         mw->setWindowModality(Qt::ApplicationModal);
557     mw->show();
558     return mw->page();
559 }
560 
createPlugin(const QString & classId,const QUrl &,const QStringList &,const QStringList &)561 QObject* WebPage::createPlugin(const QString &classId, const QUrl&, const QStringList&, const QStringList&)
562 {
563     if (classId == "alien_QLabel") {
564         QLabel* l = new QLabel;
565         l->winId();
566         return l;
567     }
568 
569 #ifndef QT_NO_UITOOLS
570     QUiLoader loader;
571     return loader.createWidget(classId, view());
572 #else
573     Q_UNUSED(classId);
574     return 0;
575 #endif
576 }
577 
578 
launcherMain(const QApplication & app)579 int launcherMain(const QApplication& app)
580 {
581 #ifndef NDEBUG
582     int retVal = app.exec();
583     qt_drt_garbageCollector_collect();
584     QWebSettings::clearMemoryCaches();
585     return retVal;
586 #else
587     return app.exec();
588 #endif
589 }
590 
591 class LauncherApplication : public QApplication {
592     Q_OBJECT
593 
594 public:
595     LauncherApplication(int& argc, char** argv);
urls() const596     QStringList urls() const { return m_urls; }
isRobotized() const597     bool isRobotized() const { return m_isRobotized; }
598 
599 private:
600     void handleUserOptions();
601     void applyDefaultSettings();
602 
603 private:
604     bool m_isRobotized;
605     QStringList m_urls;
606 };
607 
applyDefaultSettings()608 void LauncherApplication::applyDefaultSettings()
609 {
610     QWebSettings::setMaximumPagesInCache(4);
611 
612     QWebSettings::setObjectCacheCapacities((16*1024*1024) / 8, (16*1024*1024) / 8, 16*1024*1024);
613 
614     QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
615     QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
616     QWebSettings::enablePersistentStorage();
617 }
618 
LauncherApplication(int & argc,char ** argv)619 LauncherApplication::LauncherApplication(int& argc, char** argv)
620     : QApplication(argc, argv)
621     , m_isRobotized(false)
622 {
623     // To allow QWebInspector's configuration persistence
624     setOrganizationName("Nokia");
625     setApplicationName("QtLauncher");
626     setApplicationVersion("0.1");
627 
628     applyDefaultSettings();
629 
630     handleUserOptions();
631 }
632 
requiresGraphicsView(const QString & option)633 static void requiresGraphicsView(const QString& option)
634 {
635     if (gUseGraphicsView)
636         return;
637     appQuit(1, QString("%1 only works in combination with the -graphicsbased option").arg(option));
638 }
639 
handleUserOptions()640 void LauncherApplication::handleUserOptions()
641 {
642     QStringList args = arguments();
643     QFileInfo program(args.at(0));
644     QString programName("QtLauncher");
645     if (program.exists())
646         programName = program.baseName();
647 
648     QList<QString> updateModes(enumToKeys(QGraphicsView::staticMetaObject,
649             "ViewportUpdateMode", "ViewportUpdate"));
650 
651     if (args.contains("-help")) {
652         qDebug() << "Usage:" << programName.toLatin1().data()
653              << "[-graphicsbased]"
654              << "[-compositing]"
655              << QString("[-viewport-update-mode %1]").arg(formatKeys(updateModes)).toLatin1().data()
656              << "[-cache-webview]"
657              << "[-show-fps]"
658              << "[-r list]"
659              << "URLs";
660         appQuit(0);
661     }
662 
663     if (args.contains("-graphicsbased"))
664         gUseGraphicsView = true;
665 
666     if (args.contains("-compositing")) {
667         requiresGraphicsView("-compositing");
668         gUseCompositing = true;
669     }
670 
671     if (args.contains("-show-fps")) {
672         requiresGraphicsView("-show-fps");
673         gShowFrameRate = true;
674     }
675 
676     if (args.contains("-cache-webview")) {
677         requiresGraphicsView("-cache-webview");
678         gCacheWebView = true;
679     }
680 
681     QString arg1("-viewport-update-mode");
682     int modeIndex = args.indexOf(arg1);
683     if (modeIndex != -1) {
684         requiresGraphicsView(arg1);
685 
686         QString mode = takeOptionValue(&args, modeIndex);
687         if (mode.isEmpty())
688             appQuit(1, QString("%1 needs a value of one of [%2]").arg(arg1).arg(formatKeys(updateModes)));
689         int idx = updateModes.indexOf(mode);
690         if (idx == -1)
691             appQuit(1, QString("%1 value has to be one of [%2]").arg(arg1).arg(formatKeys(updateModes)));
692 
693         gViewportUpdateMode = static_cast<QGraphicsView::ViewportUpdateMode>(idx);
694     }
695 
696     int robotIndex = args.indexOf("-r");
697     if (robotIndex != -1) {
698         QString listFile = takeOptionValue(&args, robotIndex);
699         if (listFile.isEmpty())
700             appQuit(1, "-r needs a list file to start in robotized mode");
701         if (!QFile::exists(listFile))
702             appQuit(1, "The list file supplied to -r does not exist.");
703 
704         m_isRobotized = true;
705         m_urls = QStringList(listFile);
706         return;
707     }
708 
709     int lastArg = args.lastIndexOf(QRegExp("^-.*"));
710     m_urls = (lastArg != -1) ? args.mid(++lastArg) : args.mid(1);
711 }
712 
713 
main(int argc,char ** argv)714 int main(int argc, char **argv)
715 {
716     LauncherApplication app(argc, argv);
717 
718     if (app.isRobotized()) {
719         LauncherWindow* window = new LauncherWindow();
720         UrlLoader loader(window->page()->mainFrame(), app.urls().at(0));
721         QObject::connect(window->page()->mainFrame(), SIGNAL(loadFinished(bool)), &loader, SLOT(loadNext()));
722         loader.loadNext();
723         window->show();
724         return launcherMain(app);
725     }
726 
727     QStringList urls = app.urls();
728 
729     if (urls.isEmpty()) {
730         QString defaultUrl = QString("file://%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
731         if (QDir(defaultUrl).exists())
732             urls.append(defaultUrl);
733         else
734             urls.append("");
735     }
736 
737     LauncherWindow* window = 0;
738     foreach (QString url, urls) {
739         if (!window)
740             window = new LauncherWindow(url);
741         else
742             window->newWindow(url);
743     }
744 
745     window->show();
746     return launcherMain(app);
747 }
748 
749 #include "main.moc"
750