/tools/qml/qmlruntime.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 1554 lines · 1288 code · 202 blank · 64 comment · 236 complexity · bc6d42f43d5fd65c6de169e38dcd86d3 MD5 · raw file

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