tools/qml/qmlruntime.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <qdeclarativeview.h>
       
    43 
       
    44 #ifdef hz
       
    45 #undef hz
       
    46 #endif
       
    47 #include "ui_recopts.h"
       
    48 
       
    49 #include "qmlruntime.h"
       
    50 #include <qdeclarativecontext.h>
       
    51 #include <qdeclarativeengine.h>
       
    52 #include <qdeclarativenetworkaccessmanagerfactory.h>
       
    53 #include "qdeclarative.h"
       
    54 #include <private/qabstractanimation_p.h>
       
    55 #include <QAbstractAnimation>
       
    56 
       
    57 #include <QSettings>
       
    58 #include <QXmlStreamReader>
       
    59 #include <QBuffer>
       
    60 #include <QNetworkReply>
       
    61 #include <QNetworkCookieJar>
       
    62 #include <QNetworkDiskCache>
       
    63 #include <QNetworkAccessManager>
       
    64 #include <QSignalMapper>
       
    65 #include <QDeclarativeComponent>
       
    66 #include <QWidget>
       
    67 #include <QApplication>
       
    68 #include <QTranslator>
       
    69 #include <QDir>
       
    70 #include <QTextBrowser>
       
    71 #include <QFile>
       
    72 #include <QFileInfo>
       
    73 #include <QVBoxLayout>
       
    74 #include <QProgressDialog>
       
    75 #include <QProcess>
       
    76 #include <QMenuBar>
       
    77 #include <QMenu>
       
    78 #include <QAction>
       
    79 #include <QFileDialog>
       
    80 #include <QTimer>
       
    81 #include <QGraphicsObject>
       
    82 #include <QNetworkProxyFactory>
       
    83 #include <QKeyEvent>
       
    84 #include <QMutex>
       
    85 #include <QMutexLocker>
       
    86 #include "proxysettings.h"
       
    87 #include "deviceorientation.h"
       
    88 
       
    89 #ifdef GL_SUPPORTED
       
    90 #include <QGLWidget>
       
    91 #endif
       
    92 
       
    93 #include <qdeclarativetester.h>
       
    94 
       
    95 #if defined (Q_OS_SYMBIAN)
       
    96 #define SYMBIAN_NETWORK_INIT
       
    97 #endif
       
    98 
       
    99 #if defined (SYMBIAN_NETWORK_INIT)
       
   100 #include <sys/types.h>
       
   101 #include <sys/stat.h>
       
   102 #include <fcntl.h>
       
   103 #include <unistd.h>
       
   104 #include <QTextCodec>
       
   105 #include "sym_iap_util.h"
       
   106 #endif
       
   107 
       
   108 QT_BEGIN_NAMESPACE
       
   109 
       
   110 class Runtime : public QObject
       
   111 {
       
   112     Q_OBJECT
       
   113 
       
   114     Q_PROPERTY(bool isActiveWindow READ isActiveWindow NOTIFY isActiveWindowChanged)
       
   115     Q_PROPERTY(DeviceOrientation::Orientation orientation READ orientation NOTIFY orientationChanged)
       
   116 
       
   117 public:
       
   118     static Runtime* instance()
       
   119     {
       
   120         static Runtime *instance = 0;
       
   121         if (!instance)
       
   122             instance = new Runtime;
       
   123         return instance;
       
   124     }
       
   125 
       
   126     bool isActiveWindow() const { return activeWindow; }
       
   127     void setActiveWindow(bool active)
       
   128     {
       
   129         if (active == activeWindow)
       
   130             return;
       
   131         activeWindow = active;
       
   132         emit isActiveWindowChanged();
       
   133     }
       
   134 
       
   135     DeviceOrientation::Orientation orientation() const { return DeviceOrientation::instance()->orientation(); }
       
   136 
       
   137 Q_SIGNALS:
       
   138     void isActiveWindowChanged();
       
   139     void orientationChanged();
       
   140 
       
   141 private:
       
   142     Runtime(QObject *parent=0) : QObject(parent), activeWindow(false)
       
   143     {
       
   144         connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()),
       
   145                 this, SIGNAL(orientationChanged()));
       
   146     }
       
   147 
       
   148     bool activeWindow;
       
   149 };
       
   150 
       
   151 
       
   152 class SizedMenuBar : public QMenuBar
       
   153 {
       
   154     Q_OBJECT
       
   155 public:
       
   156     SizedMenuBar(QWidget *parent, QWidget *referenceWidget)
       
   157         : QMenuBar(parent), refWidget(referenceWidget)
       
   158     {
       
   159     }
       
   160 
       
   161     virtual QSize sizeHint() const
       
   162     {
       
   163         return QSize(refWidget->sizeHint().width(), QMenuBar::sizeHint().height());
       
   164     }
       
   165 
       
   166 private:
       
   167     QWidget *refWidget;
       
   168 };
       
   169 
       
   170 static struct { const char *name, *args; } ffmpegprofiles[] = {
       
   171     {"Maximum Quality", "-sameq"},
       
   172     {"High Quality", "-qmax 2"},
       
   173     {"Medium Quality", "-qmax 6"},
       
   174     {"Low Quality", "-qmax 16"},
       
   175     {"Custom ffmpeg arguments", ""},
       
   176     {0,0}
       
   177 };
       
   178 
       
   179 class RecordingDialog : public QDialog, public Ui::RecordingOptions {
       
   180     Q_OBJECT
       
   181 
       
   182 public:
       
   183     RecordingDialog(QWidget *parent) : QDialog(parent)
       
   184     {
       
   185         setupUi(this);
       
   186         hz->setValidator(new QDoubleValidator(hz));
       
   187         for (int i=0; ffmpegprofiles[i].name; ++i) {
       
   188             profile->addItem(ffmpegprofiles[i].name);
       
   189         }
       
   190     }
       
   191 
       
   192     void setArguments(QString a)
       
   193     {
       
   194         int i;
       
   195         for (i=0; ffmpegprofiles[i].args[0]; ++i) {
       
   196             if (ffmpegprofiles[i].args == a) {
       
   197                 profile->setCurrentIndex(i);
       
   198                 args->setText(QLatin1String(ffmpegprofiles[i].args));
       
   199                 return;
       
   200             }
       
   201         }
       
   202         customargs = a;
       
   203         args->setText(a);
       
   204         profile->setCurrentIndex(i);
       
   205     }
       
   206 
       
   207     QString arguments() const
       
   208     {
       
   209         int i = profile->currentIndex();
       
   210         return ffmpegprofiles[i].args[0] ? QLatin1String(ffmpegprofiles[i].args) : customargs;
       
   211     }
       
   212 
       
   213 private slots:
       
   214     void pickProfile(int i)
       
   215     {
       
   216         if (ffmpegprofiles[i].args[0]) {
       
   217             args->setText(QLatin1String(ffmpegprofiles[i].args));
       
   218         } else {
       
   219             args->setText(customargs);
       
   220         }
       
   221     }
       
   222 
       
   223     void storeCustomArgs(QString s)
       
   224     {
       
   225         setArguments(s);
       
   226     }
       
   227 
       
   228 private:
       
   229     QString customargs;
       
   230 };
       
   231 
       
   232 class PersistentCookieJar : public QNetworkCookieJar {
       
   233 public:
       
   234     PersistentCookieJar(QObject *parent) : QNetworkCookieJar(parent) { load(); }
       
   235     ~PersistentCookieJar() { save(); }
       
   236 
       
   237     virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const
       
   238     {
       
   239         QMutexLocker lock(&mutex);
       
   240         return QNetworkCookieJar::cookiesForUrl(url);
       
   241     }
       
   242 
       
   243     virtual bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
       
   244     {
       
   245         QMutexLocker lock(&mutex);
       
   246         return QNetworkCookieJar::setCookiesFromUrl(cookieList, url);
       
   247     }
       
   248 
       
   249 private:
       
   250     void save()
       
   251     {
       
   252         QMutexLocker lock(&mutex);
       
   253         QList<QNetworkCookie> list = allCookies();
       
   254         QByteArray data;
       
   255         foreach (QNetworkCookie cookie, list) {
       
   256             if (!cookie.isSessionCookie()) {
       
   257                 data.append(cookie.toRawForm());
       
   258                 data.append("\n");
       
   259             }
       
   260         }
       
   261         QSettings settings;
       
   262         settings.setValue("Cookies",data);
       
   263     }
       
   264 
       
   265     void load()
       
   266     {
       
   267         QMutexLocker lock(&mutex);
       
   268         QSettings settings;
       
   269         QByteArray data = settings.value("Cookies").toByteArray();
       
   270         setAllCookies(QNetworkCookie::parseCookies(data));
       
   271     }
       
   272 
       
   273     mutable QMutex mutex;
       
   274 };
       
   275 
       
   276 class NetworkAccessManagerFactory : public QDeclarativeNetworkAccessManagerFactory
       
   277 {
       
   278 public:
       
   279     NetworkAccessManagerFactory() : cacheSize(0) {}
       
   280     ~NetworkAccessManagerFactory() {}
       
   281 
       
   282     QNetworkAccessManager *create(QObject *parent);
       
   283 
       
   284     void setupProxy(QNetworkAccessManager *nam)
       
   285     {
       
   286         class SystemProxyFactory : public QNetworkProxyFactory
       
   287         {
       
   288         public:
       
   289             virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
       
   290             {
       
   291                 QString protocolTag = query.protocolTag();
       
   292                 if (httpProxyInUse && (protocolTag == "http" || protocolTag == "https")) {
       
   293                     QList<QNetworkProxy> ret;
       
   294                     ret << httpProxy;
       
   295                     return ret;
       
   296                 }
       
   297                 return QNetworkProxyFactory::systemProxyForQuery(query);
       
   298             }
       
   299             void setHttpProxy (QNetworkProxy proxy)
       
   300             {
       
   301                 httpProxy = proxy;
       
   302                 httpProxyInUse = true;
       
   303             }
       
   304             void unsetHttpProxy ()
       
   305             {
       
   306                 httpProxyInUse = false;
       
   307             }
       
   308         private:
       
   309             bool httpProxyInUse;
       
   310             QNetworkProxy httpProxy;
       
   311         };
       
   312 
       
   313         SystemProxyFactory *proxyFactory = new SystemProxyFactory;
       
   314         if (ProxySettings::httpProxyInUse())
       
   315             proxyFactory->setHttpProxy(ProxySettings::httpProxy());
       
   316         else
       
   317             proxyFactory->unsetHttpProxy();
       
   318         nam->setProxyFactory(proxyFactory);
       
   319     }
       
   320 
       
   321     void setCacheSize(int size) {
       
   322         if (size != cacheSize) {
       
   323             cacheSize = size;
       
   324         }
       
   325     }
       
   326 
       
   327     static PersistentCookieJar *cookieJar;
       
   328     QMutex mutex;
       
   329     int cacheSize;
       
   330 };
       
   331 
       
   332 PersistentCookieJar *NetworkAccessManagerFactory::cookieJar = 0;
       
   333 
       
   334 static void cleanup_cookieJar()
       
   335 {
       
   336     delete NetworkAccessManagerFactory::cookieJar;
       
   337     NetworkAccessManagerFactory::cookieJar = 0;
       
   338 }
       
   339 
       
   340 QNetworkAccessManager *NetworkAccessManagerFactory::create(QObject *parent)
       
   341 {
       
   342     QMutexLocker lock(&mutex);
       
   343     QNetworkAccessManager *manager = new QNetworkAccessManager(parent);
       
   344     if (!cookieJar) {
       
   345         qAddPostRoutine(cleanup_cookieJar);
       
   346         cookieJar = new PersistentCookieJar(0);
       
   347     }
       
   348     manager->setCookieJar(cookieJar);
       
   349     cookieJar->setParent(0);
       
   350     setupProxy(manager);
       
   351     if (cacheSize > 0) {
       
   352         QNetworkDiskCache *cache = new QNetworkDiskCache;
       
   353         cache->setCacheDirectory(QDir::tempPath()+QLatin1String("/qml-viewer-network-cache"));
       
   354         cache->setMaximumCacheSize(cacheSize);
       
   355         manager->setCache(cache);
       
   356     } else {
       
   357         manager->setCache(0);
       
   358     }
       
   359     qDebug() << "created new network access manager for" << parent;
       
   360     return manager;
       
   361 }
       
   362 
       
   363 QString QDeclarativeViewer::getVideoFileName()
       
   364 {
       
   365     QString title = convertAvailable || ffmpegAvailable ? tr("Save Video File") : tr("Save PNG Frames");
       
   366     QStringList types;
       
   367     if (ffmpegAvailable) types += tr("Common Video files")+QLatin1String(" (*.avi *.mpeg *.mov)");
       
   368     if (convertAvailable) types += tr("GIF Animation")+QLatin1String(" (*.gif)");
       
   369     types += tr("Individual PNG frames")+QLatin1String(" (*.png)");
       
   370     if (ffmpegAvailable) types += tr("All ffmpeg formats (*.*)");
       
   371     return QFileDialog::getSaveFileName(this, title, "", types.join(";; "));
       
   372 }
       
   373 
       
   374 
       
   375 QDeclarativeViewer::QDeclarativeViewer(QWidget *parent, Qt::WindowFlags flags)
       
   376 #if defined(Q_OS_SYMBIAN)
       
   377     : QMainWindow(parent, flags)
       
   378 #else
       
   379     : QWidget(parent, flags)
       
   380 #endif
       
   381       , loggerWindow(new LoggerWidget())
       
   382       , frame_stream(0), mb(0)
       
   383       , portraitOrientation(0), landscapeOrientation(0)
       
   384       , showWarningsWindow(0)
       
   385       , m_scriptOptions(0)
       
   386       , tester(0)
       
   387       , useQmlFileBrowser(true)
       
   388       , translator(0)
       
   389 {
       
   390     QDeclarativeViewer::registerTypes();
       
   391     setWindowTitle(tr("Qt QML Viewer"));
       
   392 
       
   393     devicemode = false;
       
   394     canvas = 0;
       
   395     record_autotime = 0;
       
   396     record_rate = 50;
       
   397     record_args += QLatin1String("-sameq");
       
   398 
       
   399     recdlg = new RecordingDialog(this);
       
   400     connect(recdlg->pickfile, SIGNAL(clicked()), this, SLOT(pickRecordingFile()));
       
   401     senseFfmpeg();
       
   402     senseImageMagick();
       
   403     if (!ffmpegAvailable)
       
   404         recdlg->ffmpegOptions->hide();
       
   405     if (!ffmpegAvailable && !convertAvailable)
       
   406         recdlg->rateOptions->hide();
       
   407     QString warn;
       
   408     if (!ffmpegAvailable) {
       
   409         if (!convertAvailable)
       
   410             warn = tr("ffmpeg and ImageMagick not available - no video output");
       
   411         else
       
   412             warn = tr("ffmpeg not available - GIF and PNG outputs only");
       
   413         recdlg->warning->setText(warn);
       
   414     } else {
       
   415         recdlg->warning->hide();
       
   416     }
       
   417 
       
   418     canvas = new QDeclarativeView(this);
       
   419 
       
   420     canvas->setAttribute(Qt::WA_OpaquePaintEvent);
       
   421     canvas->setAttribute(Qt::WA_NoSystemBackground);
       
   422 
       
   423     canvas->setFocus();
       
   424 
       
   425     QObject::connect(canvas, SIGNAL(sceneResized(QSize)), this, SLOT(sceneResized(QSize)));
       
   426     QObject::connect(canvas, SIGNAL(statusChanged(QDeclarativeView::Status)), this, SLOT(statusChanged()));
       
   427     QObject::connect(canvas->engine(), SIGNAL(quit()), QCoreApplication::instance (), SLOT(quit()));
       
   428 
       
   429     QObject::connect(warningsWidget(), SIGNAL(opened()), this, SLOT(warningsWidgetOpened()));
       
   430     QObject::connect(warningsWidget(), SIGNAL(closed()), this, SLOT(warningsWidgetClosed()));
       
   431 
       
   432     if (!(flags & Qt::FramelessWindowHint)) {
       
   433         createMenu(menuBar(),0);
       
   434         setPortrait();
       
   435     }
       
   436 
       
   437 #if !defined(Q_OS_SYMBIAN)
       
   438     QVBoxLayout *layout = new QVBoxLayout;
       
   439     layout->setMargin(0);
       
   440     layout->setSpacing(0);
       
   441     setLayout(layout);
       
   442     if (mb)
       
   443         layout->addWidget(mb);
       
   444     layout->addWidget(canvas);
       
   445 #else
       
   446     setCentralWidget(canvas);
       
   447 #endif
       
   448     namFactory = new NetworkAccessManagerFactory;
       
   449     canvas->engine()->setNetworkAccessManagerFactory(namFactory);
       
   450 
       
   451     connect(&autoStartTimer, SIGNAL(triggered()), this, SLOT(autoStartRecording()));
       
   452     connect(&autoStopTimer, SIGNAL(triggered()), this, SLOT(autoStopRecording()));
       
   453     connect(&recordTimer, SIGNAL(triggered()), this, SLOT(recordFrame()));
       
   454     connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()),
       
   455             this, SLOT(orientationChanged()), Qt::QueuedConnection);
       
   456     autoStartTimer.setRunning(false);
       
   457     autoStopTimer.setRunning(false);
       
   458     recordTimer.setRunning(false);
       
   459     recordTimer.setRepeating(true);
       
   460 }
       
   461 
       
   462 QDeclarativeViewer::~QDeclarativeViewer()
       
   463 {
       
   464     delete loggerWindow;
       
   465     canvas->engine()->setNetworkAccessManagerFactory(0);
       
   466     delete namFactory;
       
   467 }
       
   468 
       
   469 void QDeclarativeViewer::enableExperimentalGestures()
       
   470 {
       
   471     canvas->viewport()->grabGesture(Qt::TapGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
       
   472     canvas->viewport()->grabGesture(Qt::TapAndHoldGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
       
   473     canvas->viewport()->grabGesture(Qt::PanGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
       
   474     canvas->viewport()->grabGesture(Qt::PinchGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
       
   475     canvas->viewport()->grabGesture(Qt::SwipeGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
       
   476     canvas->viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
       
   477 }
       
   478 
       
   479 int QDeclarativeViewer::menuBarHeight() const
       
   480 {
       
   481     if (!(windowFlags() & Qt::FramelessWindowHint))
       
   482         return menuBar()->height();
       
   483     else
       
   484         return 0; // don't create menu
       
   485 }
       
   486 
       
   487 QMenuBar *QDeclarativeViewer::menuBar() const
       
   488 {
       
   489 #if !defined(Q_OS_SYMBIAN)
       
   490     if (!mb)
       
   491         mb = new SizedMenuBar((QWidget*)this, canvas);
       
   492 #else
       
   493     mb = QMainWindow::menuBar();
       
   494 #endif
       
   495 
       
   496     return mb;
       
   497 }
       
   498 
       
   499 QDeclarativeView *QDeclarativeViewer::view() const
       
   500 {
       
   501     return canvas;
       
   502 }
       
   503 
       
   504 LoggerWidget *QDeclarativeViewer::warningsWidget() const
       
   505 {
       
   506     return loggerWindow;
       
   507 }
       
   508 
       
   509 void QDeclarativeViewer::createMenu(QMenuBar *menu, QMenu *flatmenu)
       
   510 {
       
   511     QObject *parent = flatmenu ? (QObject*)flatmenu : (QObject*)menu;
       
   512 
       
   513     QMenu *fileMenu = flatmenu ? flatmenu : menu->addMenu(tr("&File"));
       
   514 
       
   515     QAction *openAction = new QAction(tr("&Open..."), parent);
       
   516     openAction->setShortcut(QKeySequence("Ctrl+O"));
       
   517     connect(openAction, SIGNAL(triggered()), this, SLOT(openFile()));
       
   518     fileMenu->addAction(openAction);
       
   519 
       
   520     QAction *reloadAction = new QAction(tr("&Reload"), parent);
       
   521     reloadAction->setShortcut(QKeySequence("Ctrl+R"));
       
   522     connect(reloadAction, SIGNAL(triggered()), this, SLOT(reload()));
       
   523     fileMenu->addAction(reloadAction);
       
   524 
       
   525 #if defined(Q_OS_SYMBIAN)
       
   526     QAction *networkAction = new QAction(tr("Start &Network"), parent);
       
   527     connect(networkAction, SIGNAL(triggered()), this, SLOT(startNetwork()));
       
   528     fileMenu->addAction(networkAction);
       
   529 #endif
       
   530 
       
   531 #if !defined(Q_OS_SYMBIAN)
       
   532     if (flatmenu) flatmenu->addSeparator();
       
   533 
       
   534     QMenu *recordMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Recording"));
       
   535 
       
   536     QAction *snapshotAction = new QAction(tr("&Take Snapshot\tF3"), parent);
       
   537     connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot()));
       
   538     recordMenu->addAction(snapshotAction);
       
   539 
       
   540     recordAction = new QAction(tr("Start Recording &Video\tF9"), parent);
       
   541     connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection()));
       
   542     recordMenu->addAction(recordAction);
       
   543 
       
   544     QAction *recordOptions = new QAction(tr("Video &Options..."), parent);
       
   545     connect(recordOptions, SIGNAL(triggered()), this, SLOT(chooseRecordingOptions()));
       
   546 
       
   547     if (flatmenu)
       
   548         flatmenu->addAction(recordOptions);
       
   549 
       
   550     if (flatmenu) flatmenu->addSeparator();
       
   551 
       
   552     QMenu *debugMenu = flatmenu ? flatmenu->addMenu(tr("&Debugging")) : menu->addMenu(tr("&Debugging"));
       
   553 
       
   554     QAction *slowAction = new QAction(tr("&Slow Down Animations"), parent);
       
   555     slowAction->setShortcut(QKeySequence("Ctrl+."));
       
   556     slowAction->setCheckable(true);
       
   557     connect(slowAction, SIGNAL(triggered(bool)), this, SLOT(setSlowMode(bool)));
       
   558     debugMenu->addAction(slowAction);
       
   559 
       
   560     showWarningsWindow = new QAction(tr("Show Warnings"), parent);
       
   561     showWarningsWindow->setCheckable((true));
       
   562     showWarningsWindow->setChecked(loggerWindow->isVisible());
       
   563     connect(showWarningsWindow, SIGNAL(triggered(bool)), this, SLOT(showWarnings(bool)));
       
   564 
       
   565 #if !defined(Q_OS_SYMBIAN)
       
   566     debugMenu->addAction(showWarningsWindow);
       
   567 #endif
       
   568 
       
   569     if (flatmenu) flatmenu->addSeparator();
       
   570 
       
   571 #endif // Q_OS_SYMBIAN
       
   572 
       
   573     QMenu *settingsMenu = flatmenu ? flatmenu : menu->addMenu(tr("S&ettings"));
       
   574     QAction *proxyAction = new QAction(tr("Http &proxy..."), parent);
       
   575     connect(proxyAction, SIGNAL(triggered()), this, SLOT(showProxySettings()));
       
   576     settingsMenu->addAction(proxyAction);
       
   577 #if !defined(Q_OS_SYMBIAN)
       
   578     if (!flatmenu)
       
   579         settingsMenu->addAction(recordOptions);
       
   580 
       
   581     settingsMenu->addMenu(loggerWindow->preferencesMenu());
       
   582 #else
       
   583     QAction *fullscreenAction = new QAction(tr("Full Screen"), parent);
       
   584     fullscreenAction->setCheckable(true);
       
   585     connect(fullscreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
       
   586     settingsMenu->addAction(fullscreenAction);
       
   587 #endif
       
   588 
       
   589     if (flatmenu) flatmenu->addSeparator();
       
   590 
       
   591     QMenu *propertiesMenu = settingsMenu->addMenu(tr("Properties"));
       
   592 
       
   593     QActionGroup *orientation = new QActionGroup(parent);
       
   594 
       
   595     QAction *toggleOrientation = new QAction(tr("&Toggle Orientation"), parent);
       
   596     toggleOrientation->setCheckable(true);
       
   597     toggleOrientation->setShortcut(QKeySequence("Ctrl+T"));
       
   598     settingsMenu->addAction(toggleOrientation);
       
   599     connect(toggleOrientation, SIGNAL(triggered()), this, SLOT(toggleOrientation()));
       
   600 
       
   601     orientation->setExclusive(true);
       
   602     portraitOrientation = new QAction(tr("orientation: Portrait"), parent);
       
   603     portraitOrientation->setCheckable(true);
       
   604     connect(portraitOrientation, SIGNAL(triggered()), this, SLOT(setPortrait()));
       
   605     orientation->addAction(portraitOrientation);
       
   606     propertiesMenu->addAction(portraitOrientation);
       
   607 
       
   608     landscapeOrientation = new QAction(tr("orientation: Landscape"), parent);
       
   609     landscapeOrientation->setCheckable(true);
       
   610     connect(landscapeOrientation, SIGNAL(triggered()), this, SLOT(setLandscape()));
       
   611     orientation->addAction(landscapeOrientation);
       
   612     propertiesMenu->addAction(landscapeOrientation);
       
   613 
       
   614     if (flatmenu) flatmenu->addSeparator();
       
   615 
       
   616     QMenu *helpMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Help"));
       
   617     QAction *aboutAction = new QAction(tr("&About Qt..."), parent);
       
   618     connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
       
   619     helpMenu->addAction(aboutAction);
       
   620 
       
   621     QAction *quitAction = new QAction(tr("&Quit"), parent);
       
   622     quitAction->setShortcut(QKeySequence("Ctrl+Q"));
       
   623     connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
       
   624     fileMenu->addSeparator();
       
   625     fileMenu->addAction(quitAction);
       
   626     if (menu) {
       
   627         menu->setFixedHeight(menu->sizeHint().height());
       
   628         menu->setMinimumWidth(10);
       
   629     }
       
   630 }
       
   631 
       
   632 void QDeclarativeViewer::showProxySettings()
       
   633 {
       
   634     ProxySettings settingsDlg (this);
       
   635 
       
   636     connect (&settingsDlg, SIGNAL (accepted()), this, SLOT (proxySettingsChanged ()));
       
   637 
       
   638     settingsDlg.exec();
       
   639 }
       
   640 
       
   641 void QDeclarativeViewer::proxySettingsChanged()
       
   642 {
       
   643     reload ();
       
   644 }
       
   645 
       
   646 void QDeclarativeViewer::setPortrait()
       
   647 {
       
   648     DeviceOrientation::instance()->setOrientation(DeviceOrientation::Portrait);
       
   649     portraitOrientation->setChecked(true);
       
   650 }
       
   651 
       
   652 void QDeclarativeViewer::setLandscape()
       
   653 {
       
   654     DeviceOrientation::instance()->setOrientation(DeviceOrientation::Landscape);
       
   655     landscapeOrientation->setChecked(true);
       
   656 }
       
   657 
       
   658 void QDeclarativeViewer::toggleOrientation()
       
   659 {
       
   660     DeviceOrientation::instance()->setOrientation(DeviceOrientation::instance()->orientation()==DeviceOrientation::Portrait?DeviceOrientation::Landscape:DeviceOrientation::Portrait);
       
   661 }
       
   662 
       
   663 void QDeclarativeViewer::toggleFullScreen()
       
   664 {
       
   665     if (isFullScreen())
       
   666         showMaximized();
       
   667     else
       
   668         showFullScreen();
       
   669 }
       
   670 
       
   671 void QDeclarativeViewer::showWarnings(bool show)
       
   672 {
       
   673     loggerWindow->setVisible(show);
       
   674 }
       
   675 
       
   676 void QDeclarativeViewer::warningsWidgetOpened()
       
   677 {
       
   678     showWarningsWindow->setChecked(true);
       
   679 }
       
   680 
       
   681 void QDeclarativeViewer::warningsWidgetClosed()
       
   682 {
       
   683     showWarningsWindow->setChecked(false);
       
   684 }
       
   685 
       
   686 void QDeclarativeViewer::takeSnapShot()
       
   687 {
       
   688     static int snapshotcount = 1;
       
   689     QString snapFileName = QString(QLatin1String("snapshot%1.png")).arg(snapshotcount);
       
   690     QPixmap::grabWidget(canvas).save(snapFileName);
       
   691     qDebug() << "Wrote" << snapFileName;
       
   692     ++snapshotcount;
       
   693 }
       
   694 
       
   695 void QDeclarativeViewer::pickRecordingFile()
       
   696 {
       
   697     QString fileName = getVideoFileName();
       
   698     if (!fileName.isEmpty())
       
   699         recdlg->file->setText(fileName);
       
   700 }
       
   701 
       
   702 void QDeclarativeViewer::chooseRecordingOptions()
       
   703 {
       
   704     // File
       
   705     recdlg->file->setText(record_file);
       
   706 
       
   707     // Size
       
   708     recdlg->sizeOriginal->setText(tr("Original (%1x%2)").arg(canvas->width()).arg(canvas->height()));
       
   709     if (recdlg->sizeWidth->value()<=1) {
       
   710         recdlg->sizeWidth->setValue(canvas->width());
       
   711         recdlg->sizeHeight->setValue(canvas->height());
       
   712     }
       
   713 
       
   714     // Rate
       
   715     if (record_rate == 24)
       
   716         recdlg->hz24->setChecked(true);
       
   717     else if (record_rate == 25)
       
   718         recdlg->hz25->setChecked(true);
       
   719     else if (record_rate == 50)
       
   720         recdlg->hz50->setChecked(true);
       
   721     else if (record_rate == 60)
       
   722         recdlg->hz60->setChecked(true);
       
   723     else {
       
   724         recdlg->hzCustom->setChecked(true);
       
   725         recdlg->hz->setText(QString::number(record_rate));
       
   726     }
       
   727 
       
   728     // Profile
       
   729     recdlg->setArguments(record_args.join(" "));
       
   730     if (recdlg->exec()) {
       
   731         // File
       
   732         record_file = recdlg->file->text();
       
   733         // Size
       
   734         if (recdlg->sizeOriginal->isChecked())
       
   735             record_outsize = QSize();
       
   736         else if (recdlg->size720p->isChecked())
       
   737             record_outsize = QSize(1280,720);
       
   738         else if (recdlg->sizeVGA->isChecked())
       
   739             record_outsize = QSize(640,480);
       
   740         else if (recdlg->sizeQVGA->isChecked())
       
   741             record_outsize = QSize(320,240);
       
   742         else
       
   743             record_outsize = QSize(recdlg->sizeWidth->value(),recdlg->sizeHeight->value());
       
   744         // Rate
       
   745         if (recdlg->hz24->isChecked())
       
   746             record_rate = 24;
       
   747         else if (recdlg->hz25->isChecked())
       
   748             record_rate = 25;
       
   749         else if (recdlg->hz50->isChecked())
       
   750             record_rate = 50;
       
   751         else if (recdlg->hz60->isChecked())
       
   752             record_rate = 60;
       
   753         else {
       
   754             record_rate = recdlg->hz->text().toDouble();
       
   755         }
       
   756         // Profile
       
   757         record_args = recdlg->arguments().split(" ",QString::SkipEmptyParts);
       
   758     }
       
   759 }
       
   760 
       
   761 void QDeclarativeViewer::toggleRecordingWithSelection()
       
   762 {
       
   763     if (!recordTimer.isRunning()) {
       
   764         if (record_file.isEmpty()) {
       
   765             QString fileName = getVideoFileName();
       
   766             if (fileName.isEmpty())
       
   767                 return;
       
   768             if (!fileName.contains(QRegExp(".[^\\/]*$")))
       
   769                 fileName += ".avi";
       
   770             setRecordFile(fileName);
       
   771         }
       
   772     }
       
   773     toggleRecording();
       
   774 }
       
   775 
       
   776 void QDeclarativeViewer::toggleRecording()
       
   777 {
       
   778     if (record_file.isEmpty()) {
       
   779         toggleRecordingWithSelection();
       
   780         return;
       
   781     }
       
   782     bool recording = !recordTimer.isRunning();
       
   783     recordAction->setText(recording ? tr("&Stop Recording Video\tF9") : tr("&Start Recording Video\tF9"));
       
   784     setRecording(recording);
       
   785 }
       
   786 
       
   787 void QDeclarativeViewer::setSlowMode(bool enable)
       
   788 {
       
   789     QUnifiedTimer::instance()->setSlowModeEnabled(enable);
       
   790 }
       
   791 
       
   792 void QDeclarativeViewer::addLibraryPath(const QString& lib)
       
   793 {
       
   794     canvas->engine()->addImportPath(lib);
       
   795 }
       
   796 
       
   797 void QDeclarativeViewer::addPluginPath(const QString& plugin)
       
   798 {
       
   799     canvas->engine()->addPluginPath(plugin);
       
   800 }
       
   801 
       
   802 void QDeclarativeViewer::reload()
       
   803 {
       
   804     open(currentFileOrUrl);
       
   805 }
       
   806 
       
   807 void QDeclarativeViewer::openFile()
       
   808 {
       
   809     QString cur = canvas->source().toLocalFile();
       
   810     if (useQmlFileBrowser) {
       
   811         open("qrc:/content/Browser.qml");
       
   812     } else {
       
   813         QString fileName = QFileDialog::getOpenFileName(this, tr("Open QML file"), cur, tr("QML Files (*.qml)"));
       
   814         if (!fileName.isEmpty()) {
       
   815             QFileInfo fi(fileName);
       
   816             open(fi.absoluteFilePath());
       
   817         }
       
   818     }
       
   819 }
       
   820 
       
   821 void QDeclarativeViewer::statusChanged()
       
   822 {
       
   823     if (canvas->status() == QDeclarativeView::Error && tester)
       
   824         tester->executefailure();
       
   825 
       
   826     if (canvas->status() == QDeclarativeView::Ready) {
       
   827         initialSize = canvas->sizeHint();
       
   828         if (canvas->resizeMode() == QDeclarativeView::SizeRootObjectToView) {
       
   829             updateSizeHints();
       
   830             resize(QSize(initialSize.width(), initialSize.height()+menuBarHeight()));
       
   831         }
       
   832     }
       
   833 }
       
   834 
       
   835 void QDeclarativeViewer::launch(const QString& file_or_url)
       
   836 {
       
   837     QMetaObject::invokeMethod(this, "open", Qt::QueuedConnection, Q_ARG(QString, file_or_url));
       
   838 }
       
   839 
       
   840 void QDeclarativeViewer::loadTranslationFile(const QString& directory)
       
   841 {
       
   842     if (!translator) {
       
   843         translator = new QTranslator(this);
       
   844         QApplication::installTranslator(translator);
       
   845     }
       
   846 
       
   847     translator->load(QLatin1String("qml_" )+QLocale::system().name(), directory + QLatin1String("/i18n"));
       
   848 }
       
   849 
       
   850 void QDeclarativeViewer::loadDummyDataFiles(const QString& directory)
       
   851 {
       
   852     QDir dir(directory+"/dummydata", "*.qml");
       
   853     QStringList list = dir.entryList();
       
   854     for (int i = 0; i < list.size(); ++i) {
       
   855         QString qml = list.at(i);
       
   856         QFile f(dir.filePath(qml));
       
   857         f.open(QIODevice::ReadOnly);
       
   858         QByteArray data = f.readAll();
       
   859         QDeclarativeComponent comp(canvas->engine());
       
   860         comp.setData(data, QUrl());
       
   861         QObject *dummyData = comp.create();
       
   862 
       
   863         if(comp.isError()) {
       
   864             QList<QDeclarativeError> errors = comp.errors();
       
   865             foreach (const QDeclarativeError &error, errors) {
       
   866                 qWarning() << error;
       
   867             }
       
   868             if (tester) tester->executefailure();
       
   869         }
       
   870 
       
   871         if (dummyData) {
       
   872             qWarning() << "Loaded dummy data:" << dir.filePath(qml);
       
   873             qml.truncate(qml.length()-4);
       
   874             canvas->rootContext()->setContextProperty(qml, dummyData);
       
   875             dummyData->setParent(this);
       
   876         }
       
   877     }
       
   878 }
       
   879 
       
   880 bool QDeclarativeViewer::open(const QString& file_or_url)
       
   881 {
       
   882     currentFileOrUrl = file_or_url;
       
   883 
       
   884     QUrl url;
       
   885     QFileInfo fi(file_or_url);
       
   886     if (fi.exists())
       
   887         url = QUrl::fromLocalFile(fi.absoluteFilePath());
       
   888     else
       
   889         url = QUrl(file_or_url);
       
   890     setWindowTitle(tr("%1 - Qt QML Viewer").arg(file_or_url));
       
   891 
       
   892     if (!m_script.isEmpty())
       
   893         tester = new QDeclarativeTester(m_script, m_scriptOptions, canvas);
       
   894 
       
   895     delete canvas->rootObject();
       
   896     canvas->engine()->clearComponentCache();
       
   897     QDeclarativeContext *ctxt = canvas->rootContext();
       
   898     ctxt->setContextProperty("qmlViewer", this);
       
   899 #ifdef Q_OS_SYMBIAN
       
   900     ctxt->setContextProperty("qmlViewerFolder", "E:\\"); // Documents on your S60 phone
       
   901 #else
       
   902     ctxt->setContextProperty("qmlViewerFolder", QDir::currentPath());
       
   903 #endif
       
   904 
       
   905     ctxt->setContextProperty("runtime", Runtime::instance());
       
   906 
       
   907     QString fileName = url.toLocalFile();
       
   908     if (!fileName.isEmpty()) {
       
   909         fi.setFile(fileName);
       
   910         if (fi.exists()) {
       
   911             if (fi.suffix().toLower() != QLatin1String("qml")) {
       
   912                 qWarning() << "qml cannot open non-QML file" << fileName;
       
   913                 return false;
       
   914             }
       
   915 
       
   916             QFileInfo fi(fileName);
       
   917             loadTranslationFile(fi.path());
       
   918             loadDummyDataFiles(fi.path());
       
   919         } else {
       
   920             qWarning() << "qml cannot find file:" << fileName;
       
   921             return false;
       
   922         }
       
   923     }
       
   924 
       
   925     QTime t;
       
   926     t.start();
       
   927 
       
   928     canvas->setSource(url);
       
   929 
       
   930     return true;
       
   931 }
       
   932 
       
   933 void QDeclarativeViewer::startNetwork()
       
   934 {
       
   935 #if defined(SYMBIAN_NETWORK_INIT)
       
   936     qt_SetDefaultIap();
       
   937 #endif
       
   938 }
       
   939 
       
   940 void QDeclarativeViewer::setAutoRecord(int from, int to)
       
   941 {
       
   942     if (from==0) from=1; // ensure resized
       
   943     record_autotime = to-from;
       
   944     autoStartTimer.setInterval(from);
       
   945     autoStartTimer.setRunning(true);
       
   946 }
       
   947 
       
   948 void QDeclarativeViewer::setRecordArgs(const QStringList& a)
       
   949 {
       
   950     record_args = a;
       
   951 }
       
   952 
       
   953 void QDeclarativeViewer::setRecordFile(const QString& f)
       
   954 {
       
   955     record_file = f;
       
   956 }
       
   957 
       
   958 void QDeclarativeViewer::setRecordRate(int fps)
       
   959 {
       
   960     record_rate = fps;
       
   961 }
       
   962 
       
   963 void QDeclarativeViewer::sceneResized(QSize size)
       
   964 {
       
   965     if (size.width() > 0 && size.height() > 0) {
       
   966         if (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject) {
       
   967             updateSizeHints();
       
   968         }
       
   969      }
       
   970 }
       
   971 
       
   972 void QDeclarativeViewer::keyPressEvent(QKeyEvent *event)
       
   973 {
       
   974     if (event->key() == Qt::Key_0 && devicemode)
       
   975         exit(0);
       
   976     else if (event->key() == Qt::Key_F1 || (event->key() == Qt::Key_1 && devicemode)) {
       
   977         qDebug() << "F1 - help\n"
       
   978                  << "F2 - save test script\n"
       
   979                  << "F3 - take PNG snapshot\n"
       
   980                  << "F4 - show items and state\n"
       
   981                  << "F5 - reload QML\n"
       
   982                  << "F6 - show object tree\n"
       
   983                  << "F7 - show timing\n"
       
   984                  << "F9 - toggle video recording\n"
       
   985                  << "F10 - toggle orientation\n"
       
   986                  << "device keys: 0=quit, 1..8=F1..F8"
       
   987                 ;
       
   988     } else if (event->key() == Qt::Key_F2 || (event->key() == Qt::Key_2 && devicemode)) {
       
   989         if (tester && m_scriptOptions & Record)
       
   990             tester->save();
       
   991     } else if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_3 && devicemode)) {
       
   992         takeSnapShot();
       
   993     } else if (event->key() == Qt::Key_F5 || (event->key() == Qt::Key_5 && devicemode)) {
       
   994         reload();
       
   995     } else if (event->key() == Qt::Key_F9 || (event->key() == Qt::Key_9 && devicemode)) {
       
   996         toggleRecording();
       
   997     } else if (event->key() == Qt::Key_F10) {
       
   998         if (portraitOrientation) {
       
   999             if (portraitOrientation->isChecked())
       
  1000                 setLandscape();
       
  1001             else
       
  1002                 setPortrait();
       
  1003         }
       
  1004     }
       
  1005 
       
  1006     QWidget::keyPressEvent(event);
       
  1007 }
       
  1008 
       
  1009 bool QDeclarativeViewer::event(QEvent *event)
       
  1010 {
       
  1011     if (event->type() == QEvent::WindowActivate) {
       
  1012         Runtime::instance()->setActiveWindow(true);
       
  1013     } else if (event->type() == QEvent::WindowDeactivate) {
       
  1014         Runtime::instance()->setActiveWindow(false);
       
  1015     }
       
  1016     return QWidget::event(event);
       
  1017 }
       
  1018 
       
  1019 void QDeclarativeViewer::senseImageMagick()
       
  1020 {
       
  1021     QProcess proc;
       
  1022     proc.start("convert", QStringList() << "-h");
       
  1023     proc.waitForFinished(2000);
       
  1024     QString help = proc.readAllStandardOutput();
       
  1025     convertAvailable = help.contains("ImageMagick");
       
  1026 }
       
  1027 
       
  1028 void QDeclarativeViewer::senseFfmpeg()
       
  1029 {
       
  1030     QProcess proc;
       
  1031     proc.start("ffmpeg", QStringList() << "-h");
       
  1032     proc.waitForFinished(2000);
       
  1033     QString ffmpegHelp = proc.readAllStandardOutput();
       
  1034     ffmpegAvailable = ffmpegHelp.contains("-s ");
       
  1035     ffmpegHelp = tr("Video recording uses ffmpeg:")+"\n\n"+ffmpegHelp;
       
  1036 
       
  1037     QDialog *d = new QDialog(recdlg);
       
  1038     QVBoxLayout *l = new QVBoxLayout(d);
       
  1039     QTextBrowser *b = new QTextBrowser(d);
       
  1040     QFont f = b->font();
       
  1041     f.setFamily("courier");
       
  1042     b->setFont(f);
       
  1043     b->setText(ffmpegHelp);
       
  1044     l->addWidget(b);
       
  1045     d->setLayout(l);
       
  1046     ffmpegHelpWindow = d;
       
  1047     connect(recdlg->ffmpegHelp,SIGNAL(clicked()), ffmpegHelpWindow, SLOT(show()));
       
  1048 }
       
  1049 
       
  1050 void QDeclarativeViewer::setRecording(bool on)
       
  1051 {
       
  1052     if (on == recordTimer.isRunning())
       
  1053         return;
       
  1054 
       
  1055     int period = int(1000/record_rate+0.5);
       
  1056     QUnifiedTimer::instance()->setTimingInterval(on ? period:16);
       
  1057     QUnifiedTimer::instance()->setConsistentTiming(on);
       
  1058     if (on) {
       
  1059         canvas->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
       
  1060         recordTimer.setInterval(period);
       
  1061         recordTimer.setRunning(true);
       
  1062         frame_fmt = record_file.right(4).toLower();
       
  1063         frame = QImage(canvas->width(),canvas->height(),QImage::Format_RGB32);
       
  1064         if (frame_fmt != ".png" && (!convertAvailable || frame_fmt != ".gif")) {
       
  1065             // Stream video to ffmpeg
       
  1066 
       
  1067             QProcess *proc = new QProcess(this);
       
  1068             connect(proc, SIGNAL(finished(int)), this, SLOT(ffmpegFinished(int)));
       
  1069             frame_stream = proc;
       
  1070 
       
  1071             QStringList args;
       
  1072             args << "-y";
       
  1073             args << "-r" << QString::number(record_rate);
       
  1074             args << "-f" << "rawvideo";
       
  1075             args << "-pix_fmt" << (frame_fmt == ".gif" ? "rgb24" : "rgb32");
       
  1076             args << "-s" << QString("%1x%2").arg(canvas->width()).arg(canvas->height());
       
  1077             args << "-i" << "-";
       
  1078             if (record_outsize.isValid()) {
       
  1079                 args << "-s" << QString("%1x%2").arg(record_outsize.width()).arg(record_outsize.height());
       
  1080                 args << "-aspect" << QString::number(double(canvas->width())/canvas->height());
       
  1081             }
       
  1082             args += record_args;
       
  1083             args << record_file;
       
  1084             proc->start("ffmpeg",args);
       
  1085 
       
  1086         } else {
       
  1087             // Store frames, save to GIF/PNG
       
  1088             frame_stream = 0;
       
  1089         }
       
  1090     } else {
       
  1091         canvas->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
       
  1092         recordTimer.setRunning(false);
       
  1093         if (frame_stream) {
       
  1094             qDebug() << "Saving video...";
       
  1095             frame_stream->close();
       
  1096             qDebug() << "Wrote" << record_file;
       
  1097         } else {
       
  1098             QProgressDialog progress(tr("Saving frames..."), tr("Cancel"), 0, frames.count()+10, this);
       
  1099             progress.setWindowModality(Qt::WindowModal);
       
  1100 
       
  1101             int frame=0;
       
  1102             QStringList inputs;
       
  1103             qDebug() << "Saving frames...";
       
  1104 
       
  1105             QString framename;
       
  1106             bool png_output = false;
       
  1107             if (record_file.right(4).toLower()==".png") {
       
  1108                 if (record_file.contains('%'))
       
  1109                     framename = record_file;
       
  1110                 else
       
  1111                     framename = record_file.left(record_file.length()-4)+"%04d"+record_file.right(4);
       
  1112                 png_output = true;
       
  1113             } else {
       
  1114                 framename = "tmp-frame%04d.png";
       
  1115                 png_output = false;
       
  1116             }
       
  1117             foreach (QImage* img, frames) {
       
  1118                 progress.setValue(progress.value()+1);
       
  1119                 if (progress.wasCanceled())
       
  1120                     break;
       
  1121                 QString name;
       
  1122                 name.sprintf(framename.toLocal8Bit(),frame++);
       
  1123                 if (record_outsize.isValid())
       
  1124                     *img = img->scaled(record_outsize,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
       
  1125                 if (record_dither=="ordered")
       
  1126                     img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name);
       
  1127                 else if (record_dither=="threshold")
       
  1128                     img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name);
       
  1129                 else if (record_dither=="floyd")
       
  1130                     img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name);
       
  1131                 else
       
  1132                     img->save(name);
       
  1133                 inputs << name;
       
  1134                 delete img;
       
  1135             }
       
  1136 
       
  1137             if (!progress.wasCanceled()) {
       
  1138                 if (png_output) {
       
  1139                     framename.replace(QRegExp("%\\d*."),"*");
       
  1140                     qDebug() << "Wrote frames" << framename;
       
  1141                     inputs.clear(); // don't remove them
       
  1142                 } else {
       
  1143                     // ImageMagick and gifsicle for GIF encoding
       
  1144                     progress.setLabelText(tr("Converting frames to GIF file..."));
       
  1145                     QStringList args;
       
  1146                     args << "-delay" << QString::number(period/10);
       
  1147                     args << inputs;
       
  1148                     args << record_file;
       
  1149                     qDebug() << "Converting..." << record_file << "(this may take a while)";
       
  1150                     if (0!=QProcess::execute("convert", args)) {
       
  1151                         qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted";
       
  1152                         inputs.clear(); // don't remove them
       
  1153                         qDebug() << "Wrote frames tmp-frame*.png";
       
  1154                     } else {
       
  1155                         if (record_file.right(4).toLower() == ".gif") {
       
  1156                             qDebug() << "Compressing..." << record_file;
       
  1157                             if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << record_file << record_file))
       
  1158                                 qWarning() << "Cannot run 'gifsicle' - not compressed";
       
  1159                         }
       
  1160                         qDebug() << "Wrote" << record_file;
       
  1161                     }
       
  1162                 }
       
  1163             }
       
  1164 
       
  1165             progress.setValue(progress.maximum()-1);
       
  1166             foreach (QString name, inputs)
       
  1167                 QFile::remove(name);
       
  1168 
       
  1169             frames.clear();
       
  1170         }
       
  1171     }
       
  1172     qDebug() << "Recording: " << (recordTimer.isRunning()?"ON":"OFF");
       
  1173 }
       
  1174 
       
  1175 void QDeclarativeViewer::ffmpegFinished(int code)
       
  1176 {
       
  1177     qDebug() << "ffmpeg returned" << code << frame_stream->readAllStandardError();
       
  1178 }
       
  1179 
       
  1180 void QDeclarativeViewer::autoStartRecording()
       
  1181 {
       
  1182     setRecording(true);
       
  1183     autoStopTimer.setInterval(record_autotime);
       
  1184     autoStopTimer.setRunning(true);
       
  1185 }
       
  1186 
       
  1187 void QDeclarativeViewer::autoStopRecording()
       
  1188 {
       
  1189     setRecording(false);
       
  1190 }
       
  1191 
       
  1192 void QDeclarativeViewer::recordFrame()
       
  1193 {
       
  1194     canvas->QWidget::render(&frame);
       
  1195     if (frame_stream) {
       
  1196         if (frame_fmt == ".gif") {
       
  1197             // ffmpeg can't do 32bpp with gif
       
  1198             QImage rgb24 = frame.convertToFormat(QImage::Format_RGB888);
       
  1199             frame_stream->write((char*)rgb24.bits(),rgb24.numBytes());
       
  1200         } else {
       
  1201             frame_stream->write((char*)frame.bits(),frame.numBytes());
       
  1202         }
       
  1203     } else {
       
  1204         frames.append(new QImage(frame));
       
  1205     }
       
  1206 }
       
  1207 
       
  1208 void QDeclarativeViewer::orientationChanged()
       
  1209 {
       
  1210     if (canvas->resizeMode() == QDeclarativeView::SizeRootObjectToView) {
       
  1211         if (canvas->rootObject()) {
       
  1212             QSizeF rootObjectSize = canvas->rootObject()->boundingRect().size();
       
  1213             QSize newSize(rootObjectSize.width(), rootObjectSize.height()+menuBarHeight());
       
  1214             if (size() != newSize) {
       
  1215                 resize(newSize);
       
  1216             }
       
  1217         }
       
  1218     }
       
  1219 }
       
  1220 
       
  1221 void QDeclarativeViewer::setDeviceKeys(bool on)
       
  1222 {
       
  1223     devicemode = on;
       
  1224 }
       
  1225 
       
  1226 void QDeclarativeViewer::setNetworkCacheSize(int size)
       
  1227 {
       
  1228     namFactory->setCacheSize(size);
       
  1229 }
       
  1230 
       
  1231 void QDeclarativeViewer::setUseGL(bool useGL)
       
  1232 {
       
  1233 #ifdef GL_SUPPORTED
       
  1234     if (useGL) {
       
  1235         QGLFormat format = QGLFormat::defaultFormat();
       
  1236 #ifdef Q_WS_MAC
       
  1237         format.setSampleBuffers(true);
       
  1238 #else
       
  1239         format.setSampleBuffers(false);
       
  1240 #endif
       
  1241 
       
  1242         QGLWidget *glWidget = new QGLWidget(format);
       
  1243         //### potentially faster, but causes junk to appear if top-level is Item, not Rectangle
       
  1244         //glWidget->setAutoFillBackground(false);
       
  1245 
       
  1246         canvas->setViewport(glWidget);
       
  1247     }
       
  1248 #endif
       
  1249 }
       
  1250 
       
  1251 void QDeclarativeViewer::setUseNativeFileBrowser(bool use)
       
  1252 {
       
  1253     useQmlFileBrowser = !use;
       
  1254 }
       
  1255 
       
  1256 void QDeclarativeViewer::setSizeToView(bool sizeToView)
       
  1257 {
       
  1258     QDeclarativeView::ResizeMode resizeMode = sizeToView ? QDeclarativeView::SizeRootObjectToView : QDeclarativeView::SizeViewToRootObject;
       
  1259     if (resizeMode != canvas->resizeMode()) {
       
  1260         canvas->setResizeMode(resizeMode);
       
  1261         updateSizeHints();
       
  1262     }
       
  1263 }
       
  1264 
       
  1265 void QDeclarativeViewer::updateSizeHints()
       
  1266 {
       
  1267     if (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject) {
       
  1268         QSize newWindowSize = canvas->sizeHint();
       
  1269         newWindowSize.setHeight(newWindowSize.height()+menuBarHeight());
       
  1270         if (!isFullScreen() && !isMaximized()) {
       
  1271             resize(newWindowSize);
       
  1272             setFixedSize(newWindowSize);
       
  1273         }
       
  1274     } else { // QDeclarativeView::SizeRootObjectToView
       
  1275         canvas->setMinimumSize(QSize(0,0));
       
  1276         canvas->setMaximumSize(QSize(16777215,16777215));
       
  1277         setMinimumSize(QSize(0,0));
       
  1278         setMaximumSize(QSize(16777215,16777215));
       
  1279     }
       
  1280     updateGeometry();
       
  1281 }
       
  1282 
       
  1283 void QDeclarativeViewer::registerTypes()
       
  1284 {
       
  1285     static bool registered = false;
       
  1286 
       
  1287     if (!registered) {
       
  1288         // registering only for exposing the DeviceOrientation::Orientation enum
       
  1289         qmlRegisterUncreatableType<DeviceOrientation>("Qt",4,7,"Orientation","");
       
  1290         registered = true;
       
  1291     }
       
  1292 }
       
  1293 
       
  1294 QT_END_NAMESPACE
       
  1295 
       
  1296 #include "qmlruntime.moc"