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