source: trunk/tools/qml/qmlruntime.cpp@ 966

Last change on this file since 966 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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