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