Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
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(QString::fromAscii(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 (QString::fromAscii(ffmpegprofiles[i].args) == a) {
277 profile->setCurrentIndex(i);
278 args->setText(QString::fromAscii(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(QLatin1String("Cookies"), data);
469 }
470
471 void load()
472 {
473 QMutexLocker lock(&mutex);
474 QSettings settings;
475 QByteArray data = settings.value(QLatin1String("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 == QLatin1String("http") || protocolTag == QLatin1String("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 return manager;
590}
591
592QString QDeclarativeViewer::getVideoFileName()
593{
594 QString title = convertAvailable || ffmpegAvailable ? tr("Save Video File") : tr("Save PNG Frames");
595 QStringList types;
596 if (ffmpegAvailable) types += tr("Common Video files")+QLatin1String(" (*.avi *.mpeg *.mov)");
597 if (convertAvailable) types += tr("GIF Animation")+QLatin1String(" (*.gif)");
598 types += tr("Individual PNG frames")+QLatin1String(" (*.png)");
599 if (ffmpegAvailable) types += tr("All ffmpeg formats (*.*)");
600 return QFileDialog::getSaveFileName(this, title, QString(), types.join(QLatin1String(";; ")));
601}
602
603// Check for presence of ImageMagick by launching its command line
604// convert tool except on Windows, where convert.exe is a file system converter.
605static bool senseImageMagick()
606{
607#ifdef Q_OS_WIN
608 return false;
609#else
610 static int imageMagickFound = -1;
611 if (imageMagickFound == -1) {
612 QProcess proc;
613 proc.start(QLatin1String("convert"), QStringList(QLatin1String("-h")));
614 imageMagickFound = proc.waitForStarted() && proc.waitForFinished(2000)
615 && proc.readAllStandardOutput().contains("ImageMagick") ?
616 1 : 0;
617 }
618 return imageMagickFound != 0;
619#endif
620}
621
622QDeclarativeViewer::QDeclarativeViewer(QWidget *parent, Qt::WindowFlags flags)
623 : QMainWindow(parent, flags)
624 , loggerWindow(new LoggerWidget(this))
625 , frame_stream(0)
626 , convertAvailable(senseImageMagick())
627 , rotateAction(0)
628 , orientation(0)
629 , showWarningsWindow(0)
630 , m_scriptOptions(0)
631 , tester(0)
632 , useQmlFileBrowser(true)
633 , translator(0)
634{
635 QDeclarativeViewer::registerTypes();
636 setWindowTitle(tr("Qt QML Viewer"));
637#ifdef Q_WS_MAEMO_5
638 setAttribute(Qt::WA_Maemo5StackedWindow);
639// setPalette(QApplication::palette("QLabel"));
640#endif
641
642 devicemode = false;
643 canvas = 0;
644 record_autotime = 0;
645 record_rate = 50;
646 record_args += QLatin1String("-sameq");
647
648 recdlg = new RecordingDialog(this);
649 connect(recdlg->pickfile, SIGNAL(clicked()), this, SLOT(pickRecordingFile()));
650 senseFfmpeg();
651 if (!ffmpegAvailable)
652 recdlg->showffmpegOptions(false);
653 if (!ffmpegAvailable && !convertAvailable)
654 recdlg->showRateOptions(false);
655 QString warn;
656 if (!ffmpegAvailable) {
657 if (!convertAvailable)
658 warn = tr("ffmpeg and ImageMagick not available - no video output");
659 else
660 warn = tr("ffmpeg not available - GIF and PNG outputs only");
661 recdlg->warning->setText(warn);
662 } else {
663 recdlg->warning->hide();
664 }
665
666 canvas = new DragAndDropView(this);
667
668 canvas->setAttribute(Qt::WA_OpaquePaintEvent);
669 canvas->setAttribute(Qt::WA_NoSystemBackground);
670
671 canvas->setFocus();
672
673 QObject::connect(canvas, SIGNAL(sceneResized(QSize)), this, SLOT(sceneResized(QSize)));
674 QObject::connect(canvas, SIGNAL(statusChanged(QDeclarativeView::Status)), this, SLOT(statusChanged()));
675 QObject::connect(canvas->engine(), SIGNAL(quit()), this, SLOT(close()));
676
677 QObject::connect(warningsWidget(), SIGNAL(opened()), this, SLOT(warningsWidgetOpened()));
678 QObject::connect(warningsWidget(), SIGNAL(closed()), this, SLOT(warningsWidgetClosed()));
679
680 if (!(flags & Qt::FramelessWindowHint)) {
681 createMenu();
682 changeOrientation(orientation->actions().value(0));
683 } else {
684 setMenuBar(0);
685 }
686
687 setCentralWidget(canvas);
688
689 namFactory = new NetworkAccessManagerFactory;
690 canvas->engine()->setNetworkAccessManagerFactory(namFactory);
691
692 connect(&autoStartTimer, SIGNAL(timeout()), this, SLOT(autoStartRecording()));
693 connect(&autoStopTimer, SIGNAL(timeout()), this, SLOT(autoStopRecording()));
694 connect(&recordTimer, SIGNAL(timeout()), this, SLOT(recordFrame()));
695 connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()),
696 this, SLOT(orientationChanged()), Qt::QueuedConnection);
697 autoStartTimer.setSingleShot(true);
698 autoStopTimer.setSingleShot(true);
699 recordTimer.setSingleShot(false);
700
701 QObject::connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(appAboutToQuit()));
702}
703
704QDeclarativeViewer::~QDeclarativeViewer()
705{
706 delete loggerWindow;
707 canvas->engine()->setNetworkAccessManagerFactory(0);
708 delete namFactory;
709}
710
711void QDeclarativeViewer::enableExperimentalGestures()
712{
713#ifndef QT_NO_GESTURES
714 canvas->viewport()->grabGesture(Qt::TapGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
715 canvas->viewport()->grabGesture(Qt::TapAndHoldGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
716 canvas->viewport()->grabGesture(Qt::PanGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
717 canvas->viewport()->grabGesture(Qt::PinchGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
718 canvas->viewport()->grabGesture(Qt::SwipeGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
719 canvas->viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
720#endif
721}
722
723QDeclarativeView *QDeclarativeViewer::view() const
724{
725 return canvas;
726}
727
728LoggerWidget *QDeclarativeViewer::warningsWidget() const
729{
730 return loggerWindow;
731}
732
733void QDeclarativeViewer::createMenu()
734{
735 QAction *openAction = new QAction(tr("&Open..."), this);
736 openAction->setShortcuts(QKeySequence::Open);
737 connect(openAction, SIGNAL(triggered()), this, SLOT(openFile()));
738
739 QAction *openUrlAction = new QAction(tr("Open &URL..."), this);
740 connect(openUrlAction, SIGNAL(triggered()), this, SLOT(openUrl()));
741
742 QAction *reloadAction = new QAction(tr("&Reload"), this);
743 reloadAction->setShortcuts(QKeySequence::Refresh);
744 connect(reloadAction, SIGNAL(triggered()), this, SLOT(reload()));
745
746 QAction *snapshotAction = new QAction(tr("&Take Snapshot"), this);
747 snapshotAction->setShortcut(QKeySequence(tr("F3")));
748 connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot()));
749
750 recordAction = new QAction(tr("Start Recording &Video"), this);
751 recordAction->setShortcut(QKeySequence(tr("F9")));
752 connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection()));
753
754 QAction *recordOptions = new QAction(tr("Video &Options..."), this);
755 connect(recordOptions, SIGNAL(triggered()), this, SLOT(chooseRecordingOptions()));
756
757 QAction *slowAction = new QAction(tr("&Slow Down Animations"), this);
758 slowAction->setShortcut(QKeySequence(tr("Ctrl+.")));
759 slowAction->setCheckable(true);
760 connect(slowAction, SIGNAL(triggered(bool)), this, SLOT(setSlowMode(bool)));
761
762 showWarningsWindow = new QAction(tr("Show Warnings"), this);
763#if !defined(Q_OS_SYMBIAN)
764 showWarningsWindow->setCheckable((true));
765 showWarningsWindow->setChecked(loggerWindow->isVisible());
766#endif
767 connect(showWarningsWindow, SIGNAL(triggered(bool)), this, SLOT(showWarnings(bool)));
768
769 QAction *proxyAction = new QAction(tr("HTTP &Proxy..."), this);
770 connect(proxyAction, SIGNAL(triggered()), this, SLOT(showProxySettings()));
771
772 QAction *fullscreenAction = new QAction(tr("Full Screen"), this);
773 fullscreenAction->setCheckable(true);
774 connect(fullscreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
775
776 rotateAction = new QAction(tr("Rotate orientation"), this);
777 rotateAction->setShortcut(QKeySequence(tr("Ctrl+T")));
778 connect(rotateAction, SIGNAL(triggered()), this, SLOT(rotateOrientation()));
779
780 orientation = new QActionGroup(this);
781 orientation->setExclusive(true);
782 connect(orientation, SIGNAL(triggered(QAction*)), this, SLOT(changeOrientation(QAction*)));
783
784#if defined(Q_OS_SYMBIAN)
785 QAction *autoOrientationAction = new QAction(tr("Auto-orientation"), this);
786 autoOrientationAction->setCheckable(true);
787#endif
788 QAction *portraitAction = new QAction(tr("Portrait"), this);
789 portraitAction->setCheckable(true);
790 QAction *landscapeAction = new QAction(tr("Landscape"), this);
791 landscapeAction->setCheckable(true);
792#if !defined(Q_OS_SYMBIAN)
793 QAction *portraitInvAction = new QAction(tr("Portrait (inverted)"), this);
794 portraitInvAction->setCheckable(true);
795 QAction *landscapeInvAction = new QAction(tr("Landscape (inverted)"), this);
796 landscapeInvAction->setCheckable(true);
797#endif
798
799 QAction *aboutAction = new QAction(tr("&About Qt..."), this);
800 aboutAction->setMenuRole(QAction::AboutQtRole);
801 connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
802
803#if !defined(Q_OS_SYMBIAN)
804 QAction *closeAction = new QAction(tr("&Close"), this);
805 closeAction->setShortcuts(QKeySequence::Close);
806 connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
807#endif
808
809 QAction *quitAction = new QAction(tr("&Quit"), this);
810 quitAction->setMenuRole(QAction::QuitRole);
811 quitAction->setShortcuts(QKeySequence::Quit);
812 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
813
814 QMenuBar *menu = menuBar();
815 if (!menu)
816 return;
817
818#if defined(Q_WS_MAEMO_5)
819 menu->addAction(openAction);
820 menu->addAction(openUrlAction);
821 menu->addAction(reloadAction);
822
823 menu->addAction(snapshotAction);
824 menu->addAction(recordAction);
825
826 menu->addAction(recordOptions);
827 menu->addAction(proxyAction);
828
829 menu->addAction(slowAction);
830 menu->addAction(showWarningsWindow);
831
832 orientation->addAction(landscapeAction);
833 orientation->addAction(portraitAction);
834 menu->addAction(new Maemo5PickerAction(tr("Set orientation"), orientation, this));
835 menu->addAction(fullscreenAction);
836 return;
837#endif // Q_WS_MAEMO_5
838
839 QMenu *fileMenu = menu->addMenu(tr("&File"));
840 fileMenu->addAction(openAction);
841 fileMenu->addAction(openUrlAction);
842 fileMenu->addAction(reloadAction);
843#if !defined(Q_OS_SYMBIAN)
844 fileMenu->addSeparator();
845 fileMenu->addAction(closeAction);
846 fileMenu->addAction(quitAction);
847
848 QMenu *recordMenu = menu->addMenu(tr("&Recording"));
849 recordMenu->addAction(snapshotAction);
850 recordMenu->addAction(recordAction);
851#endif // ! Q_OS_SYMBIAN
852
853 QMenu *debugMenu = menu->addMenu(tr("&Debugging"));
854 debugMenu->addAction(slowAction);
855 debugMenu->addAction(showWarningsWindow);
856
857 QMenu *settingsMenu = menu->addMenu(tr("&Settings"));
858 settingsMenu->addAction(proxyAction);
859#if defined(Q_OS_SYMBIAN)
860 settingsMenu->addAction(fullscreenAction);
861#else
862 settingsMenu->addAction(recordOptions);
863 settingsMenu->addMenu(loggerWindow->preferencesMenu());
864#endif // !Q_OS_SYMBIAN
865 settingsMenu->addAction(rotateAction);
866
867 QMenu *propertiesMenu = settingsMenu->addMenu(tr("Properties"));
868
869#if defined(Q_OS_SYMBIAN)
870 orientation->addAction(autoOrientationAction);
871#endif
872 orientation->addAction(portraitAction);
873 orientation->addAction(landscapeAction);
874#if !defined(Q_OS_SYMBIAN)
875 orientation->addAction(portraitInvAction);
876 orientation->addAction(landscapeInvAction);
877#endif
878 propertiesMenu->addActions(orientation->actions());
879
880 QMenu *helpMenu = menu->addMenu(tr("&Help"));
881 helpMenu->addAction(aboutAction);
882}
883
884void QDeclarativeViewer::showProxySettings()
885{
886 ProxySettings settingsDlg (this);
887
888 connect (&settingsDlg, SIGNAL (accepted()), this, SLOT (proxySettingsChanged ()));
889
890 settingsDlg.exec();
891}
892
893void QDeclarativeViewer::proxySettingsChanged()
894{
895 namFactory->proxyChanged();
896 reload ();
897}
898
899void QDeclarativeViewer::rotateOrientation()
900{
901#if defined(Q_WS_S60)
902 CAknAppUi *appUi = static_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
903 if (appUi) {
904 CAknAppUi::TAppUiOrientation oldOrientation = appUi->Orientation();
905 QString newOrientation;
906 if (oldOrientation == CAknAppUi::EAppUiOrientationPortrait) {
907 newOrientation = QLatin1String("Landscape");
908 } else {
909 newOrientation = QLatin1String("Portrait");
910 }
911 foreach (QAction *action, orientation->actions()) {
912 if (action->text() == newOrientation) {
913 changeOrientation(action);
914 }
915 }
916 }
917#else
918 QAction *current = orientation->checkedAction();
919 QList<QAction *> actions = orientation->actions();
920 int index = actions.indexOf(current);
921 if (index < 0)
922 return;
923
924 QAction *newOrientation = actions[(index + 1) % actions.count()];
925 changeOrientation(newOrientation);
926#endif
927}
928
929void QDeclarativeViewer::toggleFullScreen()
930{
931 if (isFullScreen())
932 showMaximized();
933 else
934 showFullScreen();
935}
936
937void QDeclarativeViewer::showWarnings(bool show)
938{
939#if defined(Q_OS_SYMBIAN)
940 loggerWindow->showMaximized();
941#else
942 loggerWindow->setVisible(show);
943#endif
944}
945
946void QDeclarativeViewer::warningsWidgetOpened()
947{
948 showWarningsWindow->setChecked(true);
949}
950
951void QDeclarativeViewer::warningsWidgetClosed()
952{
953 showWarningsWindow->setChecked(false);
954}
955
956void QDeclarativeViewer::takeSnapShot()
957{
958 static int snapshotcount = 1;
959 QString snapFileName = QString(QLatin1String("snapshot%1.png")).arg(snapshotcount);
960 QPixmap::grabWidget(canvas).save(snapFileName);
961 qDebug() << "Wrote" << snapFileName;
962 ++snapshotcount;
963}
964
965void QDeclarativeViewer::pickRecordingFile()
966{
967 QString fileName = getVideoFileName();
968 if (!fileName.isEmpty())
969 recdlg->file->setText(fileName);
970}
971
972void QDeclarativeViewer::chooseRecordingOptions()
973{
974 // File
975 recdlg->file->setText(record_file);
976
977 // Size
978 recdlg->setOriginalSize(canvas->size());
979
980 // Rate
981 recdlg->setVideoRate(record_rate);
982
983
984 // Profile
985 recdlg->setArguments(record_args.join(QLatin1String(" ")));
986 if (recdlg->exec()) {
987 // File
988 record_file = recdlg->file->text();
989 // Size
990 record_outsize = recdlg->videoSize();
991 // Rate
992 record_rate = recdlg->videoRate();
993 // Profile
994 record_args = recdlg->arguments().split(QLatin1Char(' '),QString::SkipEmptyParts);
995 }
996}
997
998void QDeclarativeViewer::toggleRecordingWithSelection()
999{
1000 if (!recordTimer.isActive()) {
1001 if (record_file.isEmpty()) {
1002 QString fileName = getVideoFileName();
1003 if (fileName.isEmpty())
1004 return;
1005 if (!fileName.contains(QRegExp(QLatin1String(".[^\\/]*$"))))
1006 fileName += QLatin1String(".avi");
1007 setRecordFile(fileName);
1008 }
1009 }
1010 toggleRecording();
1011}
1012
1013void QDeclarativeViewer::toggleRecording()
1014{
1015 if (record_file.isEmpty()) {
1016 toggleRecordingWithSelection();
1017 return;
1018 }
1019 bool recording = !recordTimer.isActive();
1020 recordAction->setText(recording ? tr("&Stop Recording Video\tF9") : tr("&Start Recording Video\tF9"));
1021 setRecording(recording);
1022}
1023
1024void QDeclarativeViewer::setSlowMode(bool enable)
1025{
1026 QUnifiedTimer::instance()->setSlowModeEnabled(enable);
1027}
1028
1029void QDeclarativeViewer::addLibraryPath(const QString& lib)
1030{
1031 canvas->engine()->addImportPath(lib);
1032}
1033
1034void QDeclarativeViewer::addPluginPath(const QString& plugin)
1035{
1036 canvas->engine()->addPluginPath(plugin);
1037}
1038
1039void QDeclarativeViewer::reload()
1040{
1041 launch(currentFileOrUrl);
1042}
1043
1044void QDeclarativeViewer::openFile()
1045{
1046 QString cur = canvas->source().toLocalFile();
1047 if (useQmlFileBrowser) {
1048 open(QLatin1String("qrc:/browser/Browser.qml"));
1049 } else {
1050 QString fileName = QFileDialog::getOpenFileName(this, tr("Open QML file"), cur, tr("QML Files (*.qml)"));
1051 if (!fileName.isEmpty()) {
1052 QFileInfo fi(fileName);
1053 open(fi.absoluteFilePath());
1054 }
1055 }
1056}
1057
1058void QDeclarativeViewer::openUrl()
1059{
1060 QString cur = canvas->source().toLocalFile();
1061 QString url= QInputDialog::getText(this, tr("Open QML file"), tr("URL of main QML file:"), QLineEdit::Normal, cur);
1062 if (!url.isEmpty())
1063 open(url);
1064}
1065
1066void QDeclarativeViewer::statusChanged()
1067{
1068 if (canvas->status() == QDeclarativeView::Error && tester)
1069 tester->executefailure();
1070
1071 if (canvas->status() == QDeclarativeView::Ready) {
1072 initialSize = canvas->initialSize();
1073 updateSizeHints(true);
1074 }
1075}
1076
1077void QDeclarativeViewer::launch(const QString& file_or_url)
1078{
1079 QMetaObject::invokeMethod(this, "open", Qt::QueuedConnection, Q_ARG(QString, file_or_url));
1080}
1081
1082void QDeclarativeViewer::loadTranslationFile(const QString& directory)
1083{
1084 if (!translator) {
1085 translator = new QTranslator(this);
1086 QApplication::installTranslator(translator);
1087 }
1088
1089 translator->load(QLatin1String("qml_" )+QLocale::system().name(), directory + QLatin1String("/i18n"));
1090}
1091
1092void QDeclarativeViewer::loadDummyDataFiles(const QString& directory)
1093{
1094 QDir dir(directory + QLatin1String("/dummydata"), QLatin1String("*.qml"));
1095 QStringList list = dir.entryList();
1096 for (int i = 0; i < list.size(); ++i) {
1097 QString qml = list.at(i);
1098 QDeclarativeComponent comp(canvas->engine(), dir.filePath(qml));
1099 QObject *dummyData = comp.create();
1100
1101 if(comp.isError()) {
1102 QList<QDeclarativeError> errors = comp.errors();
1103 foreach (const QDeclarativeError &error, errors) {
1104 qWarning() << error;
1105 }
1106 if (tester) tester->executefailure();
1107 }
1108
1109 if (dummyData) {
1110 qWarning() << "Loaded dummy data:" << dir.filePath(qml);
1111 qml.truncate(qml.length()-4);
1112 canvas->rootContext()->setContextProperty(qml, dummyData);
1113 dummyData->setParent(this);
1114 }
1115 }
1116}
1117
1118bool QDeclarativeViewer::open(const QString& file_or_url)
1119{
1120 currentFileOrUrl = file_or_url;
1121
1122 QUrl url;
1123 QFileInfo fi(file_or_url);
1124 if (fi.exists())
1125 url = QUrl::fromLocalFile(fi.absoluteFilePath());
1126 else
1127 url = QUrl(file_or_url);
1128 setWindowTitle(tr("%1 - Qt QML Viewer").arg(file_or_url));
1129
1130 if (!m_script.isEmpty())
1131 tester = new QDeclarativeTester(m_script, m_scriptOptions, canvas);
1132
1133 delete canvas->rootObject();
1134 canvas->engine()->clearComponentCache();
1135 QDeclarativeContext *ctxt = canvas->rootContext();
1136 ctxt->setContextProperty(QLatin1String("qmlViewer"), this);
1137#ifdef Q_OS_SYMBIAN
1138 ctxt->setContextProperty(QLatin1String("qmlViewerFolder"), QLatin1String("E:\\")); // Documents on your S60 phone
1139#else
1140 ctxt->setContextProperty(QLatin1String("qmlViewerFolder"), QDir::currentPath());
1141#endif
1142
1143 ctxt->setContextProperty(QLatin1String("runtime"), Runtime::instance());
1144
1145 QString fileName = url.toLocalFile();
1146 if (!fileName.isEmpty()) {
1147 fi.setFile(fileName);
1148 if (fi.exists()) {
1149 if (fi.suffix().toLower() != QLatin1String("qml")) {
1150 qWarning() << "qml cannot open non-QML file" << fileName;
1151 return false;
1152 }
1153
1154 QFileInfo fi(fileName);
1155 loadTranslationFile(fi.path());
1156 loadDummyDataFiles(fi.path());
1157 } else {
1158 qWarning() << "qml cannot find file:" << fileName;
1159 return false;
1160 }
1161 }
1162
1163 QTime t;
1164 t.start();
1165
1166 canvas->setSource(url);
1167
1168 return true;
1169}
1170
1171void QDeclarativeViewer::setAutoRecord(int from, int to)
1172{
1173 if (from==0) from=1; // ensure resized
1174 record_autotime = to-from;
1175 autoStartTimer.setInterval(from);
1176 autoStartTimer.start();
1177}
1178
1179void QDeclarativeViewer::setRecordArgs(const QStringList& a)
1180{
1181 record_args = a;
1182}
1183
1184void QDeclarativeViewer::setRecordFile(const QString& f)
1185{
1186 record_file = f;
1187}
1188
1189void QDeclarativeViewer::setRecordRate(int fps)
1190{
1191 record_rate = fps;
1192}
1193
1194void QDeclarativeViewer::sceneResized(QSize)
1195{
1196 updateSizeHints();
1197}
1198
1199void QDeclarativeViewer::keyPressEvent(QKeyEvent *event)
1200{
1201 if (event->key() == Qt::Key_0 && devicemode)
1202 exit(0);
1203 else if (event->key() == Qt::Key_F1 || (event->key() == Qt::Key_1 && devicemode)) {
1204 qDebug() << "F1 - help\n"
1205 << "F2 - save test script\n"
1206 << "F3 - take PNG snapshot\n"
1207 << "F4 - show items and state\n"
1208 << "F5 - reload QML\n"
1209 << "F6 - show object tree\n"
1210 << "F7 - show timing\n"
1211 << "F9 - toggle video recording\n"
1212 << "F10 - toggle orientation\n"
1213 << "device keys: 0=quit, 1..8=F1..F8"
1214 ;
1215 } else if (event->key() == Qt::Key_F2 || (event->key() == Qt::Key_2 && devicemode)) {
1216 if (tester && m_scriptOptions & Record)
1217 tester->save();
1218 } else if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_3 && devicemode)) {
1219 takeSnapShot();
1220 } else if (event->key() == Qt::Key_F5 || (event->key() == Qt::Key_5 && devicemode)) {
1221 reload();
1222 } else if (event->key() == Qt::Key_F9 || (event->key() == Qt::Key_9 && devicemode)) {
1223 toggleRecording();
1224 } else if (event->key() == Qt::Key_F10) {
1225 rotateOrientation();
1226 }
1227
1228 QWidget::keyPressEvent(event);
1229}
1230
1231bool QDeclarativeViewer::event(QEvent *event)
1232{
1233 if (event->type() == QEvent::WindowActivate) {
1234 Runtime::instance()->setActiveWindow(true);
1235 DeviceOrientation::instance()->resumeListening();
1236 } else if (event->type() == QEvent::WindowDeactivate) {
1237 Runtime::instance()->setActiveWindow(false);
1238 DeviceOrientation::instance()->pauseListening();
1239 }
1240 return QWidget::event(event);
1241}
1242
1243// Detect ffmpeg, return its help string.
1244static inline QString detectFfmpeg()
1245{
1246 static QString ffmpegHelp;
1247 if (ffmpegHelp.isNull()) {
1248 QProcess proc;
1249 proc.start(QLatin1String("ffmpeg"), QStringList(QLatin1String("-h")));
1250 if (proc.waitForStarted() && proc.waitForFinished(2000)) {
1251 ffmpegHelp = QString::fromLocal8Bit(proc.readAllStandardOutput());
1252 } else {
1253 ffmpegHelp = QLatin1String("");
1254 }
1255 }
1256 return ffmpegHelp;
1257}
1258
1259void QDeclarativeViewer::senseFfmpeg()
1260{
1261 const QString ffmpegHelp = detectFfmpeg();
1262 ffmpegAvailable = ffmpegHelp.contains(QLatin1String("-s "));
1263 const QString text = tr("Video recording uses ffmpeg:") + QLatin1String("\n\n") + ffmpegHelp;
1264
1265 QDialog *d = new QDialog(recdlg);
1266 QVBoxLayout *l = new QVBoxLayout(d);
1267 QTextBrowser *b = new QTextBrowser(d);
1268 QFont f = b->font();
1269 f.setFamily(QLatin1String("courier"));
1270 b->setFont(f);
1271 b->setText(text);
1272 l->addWidget(b);
1273 d->setLayout(l);
1274 ffmpegHelpWindow = d;
1275 connect(recdlg->ffmpegHelp,SIGNAL(clicked()), ffmpegHelpWindow, SLOT(show()));
1276}
1277
1278void QDeclarativeViewer::setRecording(bool on)
1279{
1280 if (on == recordTimer.isActive())
1281 return;
1282
1283 int period = int(1000/record_rate+0.5);
1284 QUnifiedTimer::instance()->setTimingInterval(on ? period:16);
1285 QUnifiedTimer::instance()->setConsistentTiming(on);
1286 if (on) {
1287 canvas->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
1288 recordTimer.setInterval(period);
1289 recordTimer.start();
1290 frame_fmt = record_file.right(4).toLower();
1291 frame = QImage(canvas->width(),canvas->height(),QImage::Format_RGB32);
1292 if (frame_fmt != QLatin1String(".png") && (!convertAvailable || frame_fmt != QLatin1String(".gif"))) {
1293 // Stream video to ffmpeg
1294
1295 QProcess *proc = new QProcess(this);
1296 connect(proc, SIGNAL(finished(int)), this, SLOT(ffmpegFinished(int)));
1297 frame_stream = proc;
1298
1299 QStringList args;
1300 args << QLatin1String("-y");
1301 args << QLatin1String("-r") << QString::number(record_rate);
1302 args << QLatin1String("-f") << QLatin1String("rawvideo");
1303 args << QLatin1String("-pix_fmt") << (frame_fmt == QLatin1String(".gif") ? QLatin1String("rgb24") : QLatin1String("rgb32"));
1304 args << QLatin1String("-s") << QString::fromAscii("%1x%2").arg(canvas->width()).arg(canvas->height());
1305 args << QLatin1String("-i") << QLatin1String("-");
1306 if (record_outsize.isValid()) {
1307 args << QLatin1String("-s") << QString::fromAscii("%1x%2").arg(record_outsize.width()).arg(record_outsize.height());
1308 args << QLatin1String("-aspect") << QString::number(double(canvas->width())/canvas->height());
1309 }
1310 args += record_args;
1311 args << record_file;
1312 proc->start(QLatin1String("ffmpeg"), args);
1313
1314 } else {
1315 // Store frames, save to GIF/PNG
1316 frame_stream = 0;
1317 }
1318 } else {
1319 canvas->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
1320 recordTimer.stop();
1321 if (frame_stream) {
1322 qDebug() << "Saving video...";
1323 frame_stream->close();
1324 qDebug() << "Wrote" << record_file;
1325 } else {
1326 QProgressDialog progress(tr("Saving frames..."), tr("Cancel"), 0, frames.count()+10, this);
1327 progress.setWindowModality(Qt::WindowModal);
1328
1329 int frame=0;
1330 QStringList inputs;
1331 qDebug() << "Saving frames...";
1332
1333 QString framename;
1334 bool png_output = false;
1335 if (record_file.right(4).toLower() == QLatin1String(".png")) {
1336 if (record_file.contains(QLatin1Char('%')))
1337 framename = record_file;
1338 else
1339 framename = record_file.left(record_file.length()-4) + QLatin1String("%04d") + record_file.right(4);
1340 png_output = true;
1341 } else {
1342 framename = QLatin1String("tmp-frame%04d.png");
1343 png_output = false;
1344 }
1345 foreach (QImage* img, frames) {
1346 progress.setValue(progress.value()+1);
1347 if (progress.wasCanceled())
1348 break;
1349 QString name;
1350 name.sprintf(framename.toLocal8Bit(),frame++);
1351 if (record_outsize.isValid())
1352 *img = img->scaled(record_outsize,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
1353 if (record_dither==QLatin1String("ordered"))
1354 img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name);
1355 else if (record_dither==QLatin1String("threshold"))
1356 img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name);
1357 else if (record_dither==QLatin1String("floyd"))
1358 img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name);
1359 else
1360 img->save(name);
1361 inputs << name;
1362 delete img;
1363 }
1364
1365 if (!progress.wasCanceled()) {
1366 if (png_output) {
1367 framename.replace(QRegExp(QLatin1String("%\\d*.")), QLatin1String("*"));
1368 qDebug() << "Wrote frames" << framename;
1369 inputs.clear(); // don't remove them
1370 } else {
1371 // ImageMagick and gifsicle for GIF encoding
1372 progress.setLabelText(tr("Converting frames to GIF file..."));
1373 QStringList args;
1374 args << QLatin1String("-delay") << QString::number(period/10);
1375 args << inputs;
1376 args << record_file;
1377 qDebug() << "Converting..." << record_file << "(this may take a while)";
1378 if (0!=QProcess::execute(QLatin1String("convert"), args)) {
1379 qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted";
1380 inputs.clear(); // don't remove them
1381 qDebug() << "Wrote frames tmp-frame*.png";
1382 } else {
1383 if (record_file.right(4).toLower() == QLatin1String(".gif")) {
1384 qDebug() << "Compressing..." << record_file;
1385 if (0!=QProcess::execute(QLatin1String("gifsicle"), QStringList() << QLatin1String("-O2")
1386 << QLatin1String("-o") << record_file << record_file))
1387 qWarning() << "Cannot run 'gifsicle' - not compressed";
1388 }
1389 qDebug() << "Wrote" << record_file;
1390 }
1391 }
1392 }
1393
1394 progress.setValue(progress.maximum()-1);
1395 foreach (QString name, inputs)
1396 QFile::remove(name);
1397
1398 frames.clear();
1399 }
1400 }
1401 qDebug() << "Recording: " << (recordTimer.isActive()?"ON":"OFF");
1402}
1403
1404void QDeclarativeViewer::ffmpegFinished(int code)
1405{
1406 qDebug() << "ffmpeg returned" << code << frame_stream->readAllStandardError();
1407}
1408
1409void QDeclarativeViewer::appAboutToQuit()
1410{
1411 // avoid QGLContext errors about invalid contexts on exit
1412 canvas->setViewport(0);
1413
1414 // avoid crashes if messages are received after app has closed
1415 delete loggerWindow;
1416 loggerWindow = 0;
1417 delete tester;
1418 tester = 0;
1419 close();
1420}
1421
1422void QDeclarativeViewer::autoStartRecording()
1423{
1424 setRecording(true);
1425 autoStopTimer.setInterval(record_autotime);
1426 autoStopTimer.start();
1427}
1428
1429void QDeclarativeViewer::autoStopRecording()
1430{
1431 setRecording(false);
1432}
1433
1434void QDeclarativeViewer::recordFrame()
1435{
1436 canvas->QWidget::render(&frame);
1437 if (frame_stream) {
1438 if (frame_fmt == QLatin1String(".gif")) {
1439 // ffmpeg can't do 32bpp with gif
1440 QImage rgb24 = frame.convertToFormat(QImage::Format_RGB888);
1441 frame_stream->write((char*)rgb24.bits(),rgb24.numBytes());
1442 } else {
1443 frame_stream->write((char*)frame.bits(),frame.numBytes());
1444 }
1445 } else {
1446 frames.append(new QImage(frame));
1447 }
1448}
1449
1450void QDeclarativeViewer::changeOrientation(QAction *action)
1451{
1452 if (!action)
1453 return;
1454 QString o = action->text();
1455 action->setChecked(true);
1456#if defined(Q_WS_S60)
1457 CAknAppUi *appUi = static_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
1458 if (appUi) {
1459 CAknAppUi::TAppUiOrientation orientation = appUi->Orientation();
1460 if (o == QLatin1String("Auto-orientation")) {
1461 appUi->SetOrientationL(CAknAppUi::EAppUiOrientationAutomatic);
1462 rotateAction->setVisible(false);
1463 } else if (o == QLatin1String("Portrait")) {
1464 appUi->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait);
1465 rotateAction->setVisible(true);
1466 } else if (o == QLatin1String("Landscape")) {
1467 appUi->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape);
1468 rotateAction->setVisible(true);
1469 }
1470 }
1471#else
1472 if (o == QLatin1String("Portrait"))
1473 DeviceOrientation::instance()->setOrientation(DeviceOrientation::Portrait);
1474 else if (o == QLatin1String("Landscape"))
1475 DeviceOrientation::instance()->setOrientation(DeviceOrientation::Landscape);
1476 else if (o == QLatin1String("Portrait (inverted)"))
1477 DeviceOrientation::instance()->setOrientation(DeviceOrientation::PortraitInverted);
1478 else if (o == QLatin1String("Landscape (inverted)"))
1479 DeviceOrientation::instance()->setOrientation(DeviceOrientation::LandscapeInverted);
1480#endif
1481}
1482
1483void QDeclarativeViewer::orientationChanged()
1484{
1485 updateSizeHints();
1486}
1487
1488void QDeclarativeViewer::setDeviceKeys(bool on)
1489{
1490 devicemode = on;
1491}
1492
1493void QDeclarativeViewer::setNetworkCacheSize(int size)
1494{
1495 namFactory->setCacheSize(size);
1496}
1497
1498void QDeclarativeViewer::setUseGL(bool useGL)
1499{
1500#ifdef GL_SUPPORTED
1501 if (useGL) {
1502 QGLFormat format = QGLFormat::defaultFormat();
1503#ifdef Q_WS_MAC
1504 format.setSampleBuffers(true);
1505#else
1506 format.setSampleBuffers(false);
1507#endif
1508
1509 QGLWidget *glWidget = new QGLWidget(format);
1510 //### potentially faster, but causes junk to appear if top-level is Item, not Rectangle
1511 //glWidget->setAutoFillBackground(false);
1512
1513 canvas->setViewport(glWidget);
1514 }
1515#else
1516 Q_UNUSED(useGL)
1517#endif
1518}
1519
1520void QDeclarativeViewer::setUseNativeFileBrowser(bool use)
1521{
1522 useQmlFileBrowser = !use;
1523}
1524
1525void QDeclarativeViewer::setSizeToView(bool sizeToView)
1526{
1527 QDeclarativeView::ResizeMode resizeMode = sizeToView ? QDeclarativeView::SizeRootObjectToView : QDeclarativeView::SizeViewToRootObject;
1528 if (resizeMode != canvas->resizeMode()) {
1529 canvas->setResizeMode(resizeMode);
1530 updateSizeHints();
1531 }
1532}
1533
1534void QDeclarativeViewer::updateSizeHints(bool initial)
1535{
1536 static bool isRecursive = false;
1537
1538 if (isRecursive)
1539 return;
1540 isRecursive = true;
1541
1542 if (initial || (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject)) {
1543 QSize newWindowSize = initial ? initialSize : canvas->sizeHint();
1544 //qWarning() << "USH:" << (initial ? "INIT:" : "V2R:") << "setting fixed size " << newWindowSize;
1545 if (!isFullScreen() && !isMaximized()) {
1546 canvas->setFixedSize(newWindowSize);
1547 resize(1, 1);
1548 layout()->setSizeConstraint(QLayout::SetFixedSize);
1549 layout()->activate();
1550 }
1551 }
1552 //qWarning() << "USH: R2V: setting free size ";
1553 layout()->setSizeConstraint(QLayout::SetNoConstraint);
1554 layout()->activate();
1555 setMinimumSize(minimumSizeHint());
1556 setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
1557 canvas->setMinimumSize(QSize(0,0));
1558 canvas->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
1559
1560 isRecursive = false;
1561}
1562
1563void QDeclarativeViewer::registerTypes()
1564{
1565 static bool registered = false;
1566
1567 if (!registered) {
1568 // registering only for exposing the DeviceOrientation::Orientation enum
1569 qmlRegisterUncreatableType<DeviceOrientation>("Qt", 4, 7, "Orientation", QString());
1570 qmlRegisterUncreatableType<DeviceOrientation>("QtQuick", 1, 0, "Orientation", QString());
1571 registered = true;
1572 }
1573}
1574
1575QT_END_NAMESPACE
1576
1577#include "qmlruntime.moc"
1578

Warning: That file was not part of the compilation database. It may have many parsing errors.