Home | History | Annotate | Download | only in QtLauncher
      1 /*
      2  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
      3  * Copyright (C) 2009 Girish Ramakrishnan <girish (at) forwardbias.in>
      4  * Copyright (C) 2006 George Staikos <staikos (at) kde.org>
      5  * Copyright (C) 2006 Dirk Mueller <mueller (at) kde.org>
      6  * Copyright (C) 2006 Zack Rusin <zack (at) kde.org>
      7  * Copyright (C) 2006 Simon Hausmann <hausmann (at) 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 
    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 
    182 LauncherWindow::~LauncherWindow()
    183 {
    184     grabZoomKeys(false);
    185 }
    186 
    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 
    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)
    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 
    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 
    315 void LauncherWindow::loadStarted()
    316 {
    317     m_view->setFocus(Qt::OtherFocusReason);
    318 }
    319 
    320 void LauncherWindow::loadFinished()
    321 {
    322     QUrl url = page()->mainFrame()->url();
    323     setAddressUrl(url.toString());
    324     addCompleterEntry(url);
    325 }
    326 
    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 
    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 
    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 
    358 void LauncherWindow::resetZoom()
    359 {
    360    currentZoom = 100;
    361    page()->mainFrame()->setZoomFactor(1.0);
    362 }
    363 
    364 void LauncherWindow::toggleZoomTextOnly(bool b)
    365 {
    366     page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, b);
    367 }
    368 
    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 
    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 
    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 
    413 void LauncherWindow::dumpHtml()
    414 {
    415     qDebug() << "HTML: " << page()->mainFrame()->toHtml();
    416 }
    417 
    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 
    434 void LauncherWindow::setTouchMocking(bool on)
    435 {
    436 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
    437     touchMocking = on;
    438 #endif
    439 }
    440 
    441 void LauncherWindow::toggleAcceleratedCompositing(bool toggle)
    442 {
    443     page()->settings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, toggle);
    444 }
    445 
    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 
    473 void LauncherWindow::newWindow(const QString& url)
    474 {
    475     LauncherWindow* mw = new LauncherWindow(url);
    476     mw->show();
    477 }
    478 
    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 
    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 
    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 
    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);
    596     QStringList urls() const { return m_urls; }
    597     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 
    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 
    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 
    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 
    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 
    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