forked from qt-creator/qt-creator
Change-Id: I61e7cf189a1c4ea04e2a88a80a4f15e43cd3c018 Reviewed-on: http://codereview.qt.nokia.com/1187 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Eike Ziller <eike.ziller@nokia.com>
1658 lines
51 KiB
C++
1658 lines
51 KiB
C++
/**************************************************************************
|
|
**
|
|
** This file is part of Qt Creator
|
|
**
|
|
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
|
**
|
|
** Contact: Nokia Corporation (info@qt.nokia.com)
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
**
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
|
** Please review the following information to ensure the GNU Lesser General
|
|
** Public License version 2.1 requirements will be met:
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** Other Usage
|
|
**
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
**
|
|
** If you have questions regarding the use of this file, please contact
|
|
** Nokia at info@qt.nokia.com.
|
|
**
|
|
**************************************************************************/
|
|
|
|
#include <qdeclarativeview.h>
|
|
|
|
#ifdef hz
|
|
#undef hz
|
|
#endif
|
|
#ifdef Q_WS_MAEMO_5
|
|
# include <QMaemo5ValueButton>
|
|
# include <QMaemo5ListPickSelector>
|
|
# include <QWidgetAction>
|
|
# include <QStringListModel>
|
|
# include "ui_recopts_maemo5.h"
|
|
#else
|
|
# include "ui_recopts.h"
|
|
#endif
|
|
|
|
#include "qmlruntime.h"
|
|
#include <qdeclarativecontext.h>
|
|
#include <qdeclarativeengine.h>
|
|
#include <qdeclarativenetworkaccessmanagerfactory.h>
|
|
#include "qdeclarative.h"
|
|
#include <QAbstractAnimation>
|
|
#ifndef NO_PRIVATE_HEADERS
|
|
#include <private/qabstractanimation_p.h>
|
|
#endif
|
|
|
|
#include <qdeclarativeviewinspector.h>
|
|
#include <qdeclarativeinspectorservice.h>
|
|
|
|
#include <QtNetwork/QNetworkReply>
|
|
#include <QtNetwork/QNetworkCookieJar>
|
|
#include <QtNetwork/QNetworkDiskCache>
|
|
#include <QtNetwork/QNetworkAccessManager>
|
|
#include <QtNetwork/QNetworkProxyFactory>
|
|
|
|
#include <QtDeclarative/QDeclarativeComponent>
|
|
|
|
#include <QtGui/QWidget>
|
|
#include <QtGui/QApplication>
|
|
#include <QtGui/QTextBrowser>
|
|
#include <QtGui/QVBoxLayout>
|
|
#include <QtGui/QProgressDialog>
|
|
#include <QtGui/QMenuBar>
|
|
#include <QtGui/QMenu>
|
|
#include <QtGui/QAction>
|
|
#include <QtGui/QFileDialog>
|
|
#include <QtGui/QInputDialog>
|
|
#include <QtGui/QGraphicsObject>
|
|
#include <QtGui/QKeyEvent>
|
|
|
|
#include <QtCore/QSignalMapper>
|
|
#include <QtCore/QSettings>
|
|
#include <QtCore/QXmlStreamReader>
|
|
#include <QtCore/QBuffer>
|
|
#include <QtCore/QTranslator>
|
|
#include <QtCore/QDir>
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QFileInfo>
|
|
#include <QtCore/QProcess>
|
|
#include <QtCore/QTimer>
|
|
#include <QtCore/QMutex>
|
|
#include <QtCore/QMutexLocker>
|
|
|
|
#include "proxysettings.h"
|
|
#include "deviceorientation.h"
|
|
|
|
#ifdef GL_SUPPORTED
|
|
#include <QGLWidget>
|
|
#endif
|
|
|
|
#if defined(Q_WS_S60)
|
|
#include <aknappui.h> // For locking app orientation
|
|
#endif
|
|
|
|
#include <qdeclarativetester.h>
|
|
|
|
#include "jsdebuggeragent.h"
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
class DragAndDropView : public QDeclarativeView
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
DragAndDropView(QDeclarativeViewer *parent = 0)
|
|
: QDeclarativeView(parent)
|
|
{
|
|
setAcceptDrops(true);
|
|
}
|
|
|
|
void dragEnterEvent(QDragEnterEvent *event)
|
|
{
|
|
const QMimeData *mimeData = event->mimeData();
|
|
if (mimeData->hasUrls())
|
|
event->acceptProposedAction();
|
|
}
|
|
|
|
void dragMoveEvent(QDragMoveEvent *event)
|
|
{
|
|
event->acceptProposedAction();
|
|
}
|
|
|
|
void dragLeaveEvent(QDragLeaveEvent *event)
|
|
{
|
|
event->accept();
|
|
}
|
|
|
|
void dropEvent(QDropEvent *event)
|
|
{
|
|
const QMimeData *mimeData = event->mimeData();
|
|
if (!mimeData->hasUrls())
|
|
return;
|
|
const QList<QUrl> urlList = mimeData->urls();
|
|
foreach (const QUrl &url, urlList) {
|
|
if (url.scheme() == QLatin1String("file")) {
|
|
static_cast<QDeclarativeViewer *>(parent())->open(url.toLocalFile());
|
|
event->accept();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
class Runtime : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
Q_PROPERTY(bool isActiveWindow READ isActiveWindow NOTIFY isActiveWindowChanged)
|
|
Q_PROPERTY(DeviceOrientation::Orientation orientation READ orientation NOTIFY orientationChanged)
|
|
|
|
public:
|
|
static Runtime* instance()
|
|
{
|
|
static Runtime *instance = 0;
|
|
if (!instance)
|
|
instance = new Runtime;
|
|
return instance;
|
|
}
|
|
|
|
bool isActiveWindow() const { return activeWindow; }
|
|
void setActiveWindow(bool active)
|
|
{
|
|
if (active == activeWindow)
|
|
return;
|
|
activeWindow = active;
|
|
emit isActiveWindowChanged();
|
|
}
|
|
|
|
DeviceOrientation::Orientation orientation() const { return DeviceOrientation::instance()->orientation(); }
|
|
|
|
Q_SIGNALS:
|
|
void isActiveWindowChanged();
|
|
void orientationChanged();
|
|
|
|
private:
|
|
Runtime(QObject *parent=0) : QObject(parent), activeWindow(false)
|
|
{
|
|
connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()),
|
|
this, SIGNAL(orientationChanged()));
|
|
}
|
|
|
|
bool activeWindow;
|
|
};
|
|
|
|
|
|
|
|
#if defined(Q_WS_MAEMO_5)
|
|
|
|
class Maemo5PickerAction : public QWidgetAction {
|
|
Q_OBJECT
|
|
public:
|
|
Maemo5PickerAction(const QString &text, QActionGroup *actions, QObject *parent)
|
|
: QWidgetAction(parent), m_text(text), m_actions(actions)
|
|
{ }
|
|
|
|
QWidget *createWidget(QWidget *parent)
|
|
{
|
|
QMaemo5ValueButton *button = new QMaemo5ValueButton(m_text, parent);
|
|
button->setValueLayout(QMaemo5ValueButton::ValueUnderTextCentered);
|
|
QMaemo5ListPickSelector *pick = new QMaemo5ListPickSelector(button);
|
|
button->setPickSelector(pick);
|
|
if (m_actions) {
|
|
QStringList sl;
|
|
int curIdx = -1, idx = 0;
|
|
foreach (QAction *a, m_actions->actions()) {
|
|
sl << a->text();
|
|
if (a->isChecked())
|
|
curIdx = idx;
|
|
idx++;
|
|
}
|
|
pick->setModel(new QStringListModel(sl));
|
|
pick->setCurrentIndex(curIdx);
|
|
} else {
|
|
button->setEnabled(false);
|
|
}
|
|
connect(pick, SIGNAL(selected(QString)), this, SLOT(emitTriggered()));
|
|
return button;
|
|
}
|
|
|
|
private slots:
|
|
void emitTriggered()
|
|
{
|
|
QMaemo5ListPickSelector *pick = qobject_cast<QMaemo5ListPickSelector *>(sender());
|
|
if (!pick)
|
|
return;
|
|
int idx = pick->currentIndex();
|
|
|
|
if (m_actions && idx >= 0 && idx < m_actions->actions().count())
|
|
m_actions->actions().at(idx)->trigger();
|
|
}
|
|
|
|
private:
|
|
QString m_text;
|
|
QPointer<QActionGroup> m_actions;
|
|
};
|
|
|
|
#endif // Q_WS_MAEMO_5
|
|
|
|
static struct { const char *name, *args; } ffmpegprofiles[] = {
|
|
{"Maximum Quality", "-sameq"},
|
|
{"High Quality", "-qmax 2"},
|
|
{"Medium Quality", "-qmax 6"},
|
|
{"Low Quality", "-qmax 16"},
|
|
{"Custom ffmpeg arguments", ""},
|
|
{0,0}
|
|
};
|
|
|
|
class RecordingDialog : public QDialog, public Ui::RecordingOptions {
|
|
Q_OBJECT
|
|
|
|
public:
|
|
RecordingDialog(QWidget *parent) : QDialog(parent)
|
|
{
|
|
setupUi(this);
|
|
#ifndef Q_WS_MAEMO_5
|
|
hz->setValidator(new QDoubleValidator(hz));
|
|
#endif
|
|
for (int i=0; ffmpegprofiles[i].name; ++i) {
|
|
profile->addItem(ffmpegprofiles[i].name);
|
|
}
|
|
}
|
|
|
|
void setArguments(QString a)
|
|
{
|
|
int i;
|
|
for (i=0; ffmpegprofiles[i].args[0]; ++i) {
|
|
if (ffmpegprofiles[i].args == a) {
|
|
profile->setCurrentIndex(i);
|
|
args->setText(QLatin1String(ffmpegprofiles[i].args));
|
|
return;
|
|
}
|
|
}
|
|
customargs = a;
|
|
args->setText(a);
|
|
profile->setCurrentIndex(i);
|
|
}
|
|
|
|
QString arguments() const
|
|
{
|
|
int i = profile->currentIndex();
|
|
return ffmpegprofiles[i].args[0] ? QLatin1String(ffmpegprofiles[i].args) : customargs;
|
|
}
|
|
|
|
void setOriginalSize(const QSize &s)
|
|
{
|
|
QString str = tr("Original (%1x%2)").arg(s.width()).arg(s.height());
|
|
|
|
#ifdef Q_WS_MAEMO_5
|
|
sizeCombo->setItemText(0, str);
|
|
#else
|
|
sizeOriginal->setText(str);
|
|
if (sizeWidth->value()<=1) {
|
|
sizeWidth->setValue(s.width());
|
|
sizeHeight->setValue(s.height());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void showffmpegOptions(bool b)
|
|
{
|
|
#ifdef Q_WS_MAEMO_5
|
|
profileLabel->setVisible(b);
|
|
profile->setVisible(b);
|
|
ffmpegHelp->setVisible(b);
|
|
args->setVisible(b);
|
|
#else
|
|
ffmpegOptions->setVisible(b);
|
|
#endif
|
|
}
|
|
|
|
void showRateOptions(bool b)
|
|
{
|
|
#ifdef Q_WS_MAEMO_5
|
|
rateLabel->setVisible(b);
|
|
rateCombo->setVisible(b);
|
|
#else
|
|
rateOptions->setVisible(b);
|
|
#endif
|
|
}
|
|
|
|
void setVideoRate(int rate)
|
|
{
|
|
#ifdef Q_WS_MAEMO_5
|
|
int idx;
|
|
if (rate >= 60)
|
|
idx = 0;
|
|
else if (rate >= 50)
|
|
idx = 2;
|
|
else if (rate >= 25)
|
|
idx = 3;
|
|
else if (rate >= 24)
|
|
idx = 4;
|
|
else if (rate >= 20)
|
|
idx = 5;
|
|
else if (rate >= 15)
|
|
idx = 6;
|
|
else
|
|
idx = 7;
|
|
rateCombo->setCurrentIndex(idx);
|
|
#else
|
|
if (rate == 24)
|
|
hz24->setChecked(true);
|
|
else if (rate == 25)
|
|
hz25->setChecked(true);
|
|
else if (rate == 50)
|
|
hz50->setChecked(true);
|
|
else if (rate == 60)
|
|
hz60->setChecked(true);
|
|
else {
|
|
hzCustom->setChecked(true);
|
|
hz->setText(QString::number(rate));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int videoRate() const
|
|
{
|
|
#ifdef Q_WS_MAEMO_5
|
|
switch (rateCombo->currentIndex()) {
|
|
case 0: return 60;
|
|
case 1: return 50;
|
|
case 2: return 25;
|
|
case 3: return 24;
|
|
case 4: return 20;
|
|
case 5: return 15;
|
|
case 7: return 10;
|
|
default: return 60;
|
|
}
|
|
#else
|
|
if (hz24->isChecked())
|
|
return 24;
|
|
else if (hz25->isChecked())
|
|
return 25;
|
|
else if (hz50->isChecked())
|
|
return 50;
|
|
else if (hz60->isChecked())
|
|
return 60;
|
|
else {
|
|
return hz->text().toInt();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
QSize videoSize() const
|
|
{
|
|
#ifdef Q_WS_MAEMO_5
|
|
switch (sizeCombo->currentIndex()) {
|
|
case 0: return QSize();
|
|
case 1: return QSize(640,480);
|
|
case 2: return QSize(320,240);
|
|
case 3: return QSize(1280,720);
|
|
default: return QSize();
|
|
}
|
|
#else
|
|
if (sizeOriginal->isChecked())
|
|
return QSize();
|
|
else if (size720p->isChecked())
|
|
return QSize(1280,720);
|
|
else if (sizeVGA->isChecked())
|
|
return QSize(640,480);
|
|
else if (sizeQVGA->isChecked())
|
|
return QSize(320,240);
|
|
else
|
|
return QSize(sizeWidth->value(), sizeHeight->value());
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
private slots:
|
|
void pickProfile(int i)
|
|
{
|
|
if (ffmpegprofiles[i].args[0]) {
|
|
args->setText(QLatin1String(ffmpegprofiles[i].args));
|
|
} else {
|
|
args->setText(customargs);
|
|
}
|
|
}
|
|
|
|
void storeCustomArgs(QString s)
|
|
{
|
|
setArguments(s);
|
|
}
|
|
|
|
private:
|
|
QString customargs;
|
|
};
|
|
|
|
class PersistentCookieJar : public QNetworkCookieJar {
|
|
public:
|
|
PersistentCookieJar(QObject *parent) : QNetworkCookieJar(parent) { load(); }
|
|
~PersistentCookieJar() { save(); }
|
|
|
|
virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const
|
|
{
|
|
QMutexLocker lock(&mutex);
|
|
return QNetworkCookieJar::cookiesForUrl(url);
|
|
}
|
|
|
|
virtual bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
|
|
{
|
|
QMutexLocker lock(&mutex);
|
|
return QNetworkCookieJar::setCookiesFromUrl(cookieList, url);
|
|
}
|
|
|
|
private:
|
|
void save()
|
|
{
|
|
QMutexLocker lock(&mutex);
|
|
QList<QNetworkCookie> list = allCookies();
|
|
QByteArray data;
|
|
foreach (const QNetworkCookie &cookie, list) {
|
|
if (!cookie.isSessionCookie()) {
|
|
data.append(cookie.toRawForm());
|
|
data.append('\n');
|
|
}
|
|
}
|
|
QSettings settings;
|
|
settings.setValue("Cookies",data);
|
|
}
|
|
|
|
void load()
|
|
{
|
|
QMutexLocker lock(&mutex);
|
|
QSettings settings;
|
|
QByteArray data = settings.value("Cookies").toByteArray();
|
|
setAllCookies(QNetworkCookie::parseCookies(data));
|
|
}
|
|
|
|
mutable QMutex mutex;
|
|
};
|
|
|
|
class SystemProxyFactory : public QNetworkProxyFactory
|
|
{
|
|
public:
|
|
SystemProxyFactory() : proxyDirty(true), httpProxyInUse(false) {
|
|
}
|
|
|
|
virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
|
|
{
|
|
if (proxyDirty)
|
|
setupProxy();
|
|
QString protocolTag = query.protocolTag();
|
|
if (httpProxyInUse && (protocolTag == "http" || protocolTag == "https")) {
|
|
QList<QNetworkProxy> ret;
|
|
ret << httpProxy;
|
|
return ret;
|
|
}
|
|
#ifdef Q_OS_WIN
|
|
// systemProxyForQuery can take insanely long on Windows (QTBUG-10106)
|
|
return QNetworkProxyFactory::proxyForQuery(query);
|
|
#else
|
|
return QNetworkProxyFactory::systemProxyForQuery(query);
|
|
#endif
|
|
}
|
|
|
|
void setupProxy() {
|
|
// Don't bother locking because we know that the proxy only
|
|
// changes in response to the settings dialog and that
|
|
// the view will be reloaded.
|
|
proxyDirty = false;
|
|
httpProxyInUse = ProxySettings::httpProxyInUse();
|
|
if (httpProxyInUse)
|
|
httpProxy = ProxySettings::httpProxy();
|
|
}
|
|
|
|
void proxyChanged() {
|
|
proxyDirty = true;
|
|
}
|
|
|
|
private:
|
|
volatile bool proxyDirty;
|
|
bool httpProxyInUse;
|
|
QNetworkProxy httpProxy;
|
|
};
|
|
|
|
class NetworkAccessManagerFactory : public QObject, public QDeclarativeNetworkAccessManagerFactory
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
NetworkAccessManagerFactory() : cacheSize(0) {}
|
|
~NetworkAccessManagerFactory() {}
|
|
|
|
QNetworkAccessManager *create(QObject *parent);
|
|
|
|
void setCacheSize(int size) {
|
|
if (size != cacheSize) {
|
|
cacheSize = size;
|
|
}
|
|
}
|
|
|
|
void proxyChanged() {
|
|
foreach (QNetworkAccessManager *nam, namList) {
|
|
static_cast<SystemProxyFactory*>(nam->proxyFactory())->proxyChanged();
|
|
}
|
|
}
|
|
|
|
static PersistentCookieJar *cookieJar;
|
|
|
|
private slots:
|
|
void managerDestroyed(QObject *obj) {
|
|
namList.removeOne(static_cast<QNetworkAccessManager*>(obj));
|
|
}
|
|
|
|
private:
|
|
QMutex mutex;
|
|
int cacheSize;
|
|
QList<QNetworkAccessManager*> namList;
|
|
};
|
|
|
|
PersistentCookieJar *NetworkAccessManagerFactory::cookieJar = 0;
|
|
|
|
static void cleanup_cookieJar()
|
|
{
|
|
delete NetworkAccessManagerFactory::cookieJar;
|
|
NetworkAccessManagerFactory::cookieJar = 0;
|
|
}
|
|
|
|
QNetworkAccessManager *NetworkAccessManagerFactory::create(QObject *parent)
|
|
{
|
|
QMutexLocker lock(&mutex);
|
|
QNetworkAccessManager *manager = new QNetworkAccessManager(parent);
|
|
if (!cookieJar) {
|
|
qAddPostRoutine(cleanup_cookieJar);
|
|
cookieJar = new PersistentCookieJar(0);
|
|
}
|
|
manager->setCookieJar(cookieJar);
|
|
cookieJar->setParent(0);
|
|
manager->setProxyFactory(new SystemProxyFactory);
|
|
if (cacheSize > 0) {
|
|
QNetworkDiskCache *cache = new QNetworkDiskCache;
|
|
cache->setCacheDirectory(QDir::tempPath()+QLatin1String("/qml-viewer-network-cache"));
|
|
cache->setMaximumCacheSize(cacheSize);
|
|
manager->setCache(cache);
|
|
} else {
|
|
manager->setCache(0);
|
|
}
|
|
connect(manager, SIGNAL(destroyed(QObject*)), this, SLOT(managerDestroyed(QObject*)));
|
|
namList.append(manager);
|
|
qDebug() << "created new network access manager for" << parent;
|
|
return manager;
|
|
}
|
|
|
|
QString QDeclarativeViewer::getVideoFileName()
|
|
{
|
|
QString title = convertAvailable || ffmpegAvailable ? tr("Save Video File") : tr("Save PNG Frames");
|
|
QStringList types;
|
|
if (ffmpegAvailable) types += tr("Common Video files")+QLatin1String(" (*.avi *.mpeg *.mov)");
|
|
if (convertAvailable) types += tr("GIF Animation")+QLatin1String(" (*.gif)");
|
|
types += tr("Individual PNG frames")+QLatin1String(" (*.png)");
|
|
if (ffmpegAvailable) types += tr("All ffmpeg formats (*.*)");
|
|
return QFileDialog::getSaveFileName(this, title, "", types.join(";; "));
|
|
}
|
|
|
|
QDeclarativeViewer::QDeclarativeViewer(QWidget *parent, Qt::WindowFlags flags)
|
|
: QMainWindow(parent, flags)
|
|
, loggerWindow(new LoggerWidget(this))
|
|
, frame_stream(0)
|
|
, rotateAction(0)
|
|
, orientation(0)
|
|
, showWarningsWindow(0)
|
|
, designModeBehaviorAction(0)
|
|
, m_scriptOptions(0)
|
|
, tester(0)
|
|
, useQmlFileBrowser(true)
|
|
, translator(0)
|
|
{
|
|
QDeclarativeViewer::registerTypes();
|
|
setWindowTitle(tr("Qt QML Viewer"));
|
|
#ifdef Q_WS_MAEMO_5
|
|
setAttribute(Qt::WA_Maemo5StackedWindow);
|
|
// setPalette(QApplication::palette("QLabel"));
|
|
#endif
|
|
|
|
devicemode = false;
|
|
canvas = 0;
|
|
record_autotime = 0;
|
|
record_rate = 50;
|
|
record_args += QLatin1String("-sameq");
|
|
|
|
recdlg = new RecordingDialog(this);
|
|
connect(recdlg->pickfile, SIGNAL(clicked()), this, SLOT(pickRecordingFile()));
|
|
senseFfmpeg();
|
|
senseImageMagick();
|
|
if (!ffmpegAvailable)
|
|
recdlg->showffmpegOptions(false);
|
|
if (!ffmpegAvailable && !convertAvailable)
|
|
recdlg->showRateOptions(false);
|
|
QString warn;
|
|
if (!ffmpegAvailable) {
|
|
if (!convertAvailable)
|
|
warn = tr("ffmpeg and ImageMagick not available - no video output");
|
|
else
|
|
warn = tr("ffmpeg not available - GIF and PNG outputs only");
|
|
recdlg->warning->setText(warn);
|
|
} else {
|
|
recdlg->warning->hide();
|
|
}
|
|
|
|
canvas = new DragAndDropView(this);
|
|
inspector = new QmlJSDebugger::QDeclarativeViewInspector(canvas, this);
|
|
new QmlJSDebugger::JSDebuggerAgent(canvas->engine());
|
|
|
|
canvas->setAttribute(Qt::WA_OpaquePaintEvent);
|
|
canvas->setAttribute(Qt::WA_NoSystemBackground);
|
|
|
|
canvas->setFocus();
|
|
|
|
QObject::connect(canvas, SIGNAL(sceneResized(QSize)), this, SLOT(sceneResized(QSize)));
|
|
QObject::connect(canvas, SIGNAL(statusChanged(QDeclarativeView::Status)), this, SLOT(statusChanged()));
|
|
QObject::connect(canvas->engine(), SIGNAL(quit()), this, SLOT(close()));
|
|
|
|
QObject::connect(warningsWidget(), SIGNAL(opened()), this, SLOT(warningsWidgetOpened()));
|
|
QObject::connect(warningsWidget(), SIGNAL(closed()), this, SLOT(warningsWidgetClosed()));
|
|
|
|
if (!(flags & Qt::FramelessWindowHint)) {
|
|
createMenu();
|
|
changeOrientation(orientation->actions().value(0));
|
|
} else {
|
|
setMenuBar(0);
|
|
}
|
|
|
|
setCentralWidget(canvas);
|
|
|
|
namFactory = new NetworkAccessManagerFactory;
|
|
canvas->engine()->setNetworkAccessManagerFactory(namFactory);
|
|
|
|
connect(&autoStartTimer, SIGNAL(timeout()), this, SLOT(autoStartRecording()));
|
|
connect(&autoStopTimer, SIGNAL(timeout()), this, SLOT(autoStopRecording()));
|
|
connect(&recordTimer, SIGNAL(timeout()), this, SLOT(recordFrame()));
|
|
connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()),
|
|
this, SLOT(orientationChanged()), Qt::QueuedConnection);
|
|
autoStartTimer.setSingleShot(true);
|
|
autoStopTimer.setSingleShot(true);
|
|
recordTimer.setSingleShot(false);
|
|
|
|
QObject::connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(appAboutToQuit()));
|
|
}
|
|
|
|
QDeclarativeViewer::~QDeclarativeViewer()
|
|
{
|
|
delete loggerWindow;
|
|
canvas->engine()->setNetworkAccessManagerFactory(0);
|
|
delete namFactory;
|
|
}
|
|
|
|
void QDeclarativeViewer::setDesignModeBehavior(bool value)
|
|
{
|
|
if (designModeBehaviorAction)
|
|
designModeBehaviorAction->setChecked(value);
|
|
inspector->setDesignModeBehavior(value);
|
|
}
|
|
|
|
void QDeclarativeViewer::enableExperimentalGestures()
|
|
{
|
|
#ifndef QT_NO_GESTURES
|
|
canvas->viewport()->grabGesture(Qt::TapGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
|
|
canvas->viewport()->grabGesture(Qt::TapAndHoldGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
|
|
canvas->viewport()->grabGesture(Qt::PanGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
|
|
canvas->viewport()->grabGesture(Qt::PinchGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
|
|
canvas->viewport()->grabGesture(Qt::SwipeGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);
|
|
canvas->viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
|
|
#endif
|
|
}
|
|
|
|
QDeclarativeView *QDeclarativeViewer::view() const
|
|
{
|
|
return canvas;
|
|
}
|
|
|
|
LoggerWidget *QDeclarativeViewer::warningsWidget() const
|
|
{
|
|
return loggerWindow;
|
|
}
|
|
|
|
void QDeclarativeViewer::createMenu()
|
|
{
|
|
QAction *openAction = new QAction(tr("&Open..."), this);
|
|
openAction->setShortcuts(QKeySequence::Open);
|
|
connect(openAction, SIGNAL(triggered()), this, SLOT(openFile()));
|
|
|
|
QAction *openUrlAction = new QAction(tr("Open &URL..."), this);
|
|
connect(openUrlAction, SIGNAL(triggered()), this, SLOT(openUrl()));
|
|
|
|
QAction *reloadAction = new QAction(tr("&Reload"), this);
|
|
reloadAction->setShortcuts(QKeySequence::Refresh);
|
|
connect(reloadAction, SIGNAL(triggered()), this, SLOT(reload()));
|
|
|
|
QAction *snapshotAction = new QAction(tr("&Take Snapshot"), this);
|
|
snapshotAction->setShortcut(QKeySequence("F3"));
|
|
connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot()));
|
|
|
|
recordAction = new QAction(tr("Start Recording &Video"), this);
|
|
recordAction->setShortcut(QKeySequence("F9"));
|
|
connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection()));
|
|
|
|
QAction *recordOptions = new QAction(tr("Video &Options..."), this);
|
|
connect(recordOptions, SIGNAL(triggered()), this, SLOT(chooseRecordingOptions()));
|
|
|
|
QMenu *playSpeedMenu = new QMenu(tr("Animation Speed"), this);
|
|
playSpeedMenuActions = new QActionGroup(this);
|
|
playSpeedMenuActions->setExclusive(true);
|
|
|
|
QAction *speedAction = playSpeedMenu->addAction(tr("1x"), this, SLOT(changeAnimationSpeed()));
|
|
speedAction->setCheckable(true);
|
|
speedAction->setChecked(true);
|
|
speedAction->setData(1.0f);
|
|
playSpeedMenuActions->addAction(speedAction);
|
|
|
|
speedAction = playSpeedMenu->addAction(tr("0.5x"), this, SLOT(changeAnimationSpeed()));
|
|
speedAction->setCheckable(true);
|
|
speedAction->setData(2.0f);
|
|
playSpeedMenuActions->addAction(speedAction);
|
|
|
|
speedAction = playSpeedMenu->addAction(tr("0.25x"), this, SLOT(changeAnimationSpeed()));
|
|
speedAction->setCheckable(true);
|
|
speedAction->setData(4.0f);
|
|
playSpeedMenuActions->addAction(speedAction);
|
|
|
|
speedAction = playSpeedMenu->addAction(tr("0.125x"), this, SLOT(changeAnimationSpeed()));
|
|
speedAction->setCheckable(true);
|
|
speedAction->setData(8.0f);
|
|
playSpeedMenuActions->addAction(speedAction);
|
|
|
|
speedAction = playSpeedMenu->addAction(tr("0.1x"), this, SLOT(changeAnimationSpeed()));
|
|
speedAction->setCheckable(true);
|
|
speedAction->setData(10.0f);
|
|
playSpeedMenuActions->addAction(speedAction);
|
|
|
|
pauseAnimationsAction = playSpeedMenu->addAction(tr("Pause"), inspector, SLOT(setAnimationPaused(bool)));
|
|
pauseAnimationsAction->setCheckable(true);
|
|
pauseAnimationsAction->setShortcut(QKeySequence("Ctrl+."));
|
|
|
|
animationStepAction = playSpeedMenu->addAction(tr("Pause and step"), this, SLOT(stepAnimations()));
|
|
animationStepAction->setShortcut(QKeySequence("Ctrl+,"));
|
|
|
|
animationSetStepAction = playSpeedMenu->addAction(tr("Set step"), this, SLOT(setAnimationStep()));
|
|
m_stepSize = 40;
|
|
|
|
QAction *playSpeedAction = new QAction(tr("Animations"), this);
|
|
playSpeedAction->setMenu(playSpeedMenu);
|
|
|
|
connect(inspector, SIGNAL(animationSpeedChanged(qreal)), SLOT(animationSpeedChanged(qreal)));
|
|
connect(inspector, SIGNAL(animationPausedChanged(bool)), pauseAnimationsAction, SLOT(setChecked(bool)));
|
|
|
|
showWarningsWindow = new QAction(tr("Show Warnings"), this);
|
|
showWarningsWindow->setCheckable((true));
|
|
showWarningsWindow->setChecked(loggerWindow->isVisible());
|
|
connect(showWarningsWindow, SIGNAL(triggered(bool)), this, SLOT(showWarnings(bool)));
|
|
|
|
designModeBehaviorAction = new QAction(tr("&Inspector Mode"), this);
|
|
designModeBehaviorAction->setShortcut(QKeySequence("Ctrl+D"));
|
|
designModeBehaviorAction->setCheckable(true);
|
|
designModeBehaviorAction->setChecked(inspector->designModeBehavior());
|
|
designModeBehaviorAction->setEnabled(QmlJSDebugger::QDeclarativeInspectorService::hasDebuggingClient());
|
|
connect(designModeBehaviorAction, SIGNAL(triggered(bool)), this, SLOT(setDesignModeBehavior(bool)));
|
|
connect(inspector, SIGNAL(designModeBehaviorChanged(bool)), designModeBehaviorAction, SLOT(setChecked(bool)));
|
|
connect(QmlJSDebugger::QDeclarativeInspectorService::instance(), SIGNAL(debuggingClientChanged(bool)),
|
|
designModeBehaviorAction, SLOT(setEnabled(bool)));
|
|
|
|
appOnTopAction = new QAction(tr("Keep Window on Top"), this);
|
|
appOnTopAction->setCheckable(true);
|
|
appOnTopAction->setChecked(inspector->showAppOnTop());
|
|
|
|
connect(appOnTopAction, SIGNAL(triggered(bool)), inspector, SLOT(setShowAppOnTop(bool)));
|
|
connect(inspector, SIGNAL(showAppOnTopChanged(bool)), appOnTopAction, SLOT(setChecked(bool)));
|
|
|
|
QAction *proxyAction = new QAction(tr("HTTP &Proxy..."), this);
|
|
connect(proxyAction, SIGNAL(triggered()), this, SLOT(showProxySettings()));
|
|
|
|
QAction *fullscreenAction = new QAction(tr("Full Screen"), this);
|
|
fullscreenAction->setCheckable(true);
|
|
connect(fullscreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
|
|
|
|
rotateAction = new QAction(tr("Rotate orientation"), this);
|
|
rotateAction->setShortcut(QKeySequence("Ctrl+T"));
|
|
connect(rotateAction, SIGNAL(triggered()), this, SLOT(rotateOrientation()));
|
|
|
|
orientation = new QActionGroup(this);
|
|
orientation->setExclusive(true);
|
|
connect(orientation, SIGNAL(triggered(QAction*)), this, SLOT(changeOrientation(QAction*)));
|
|
|
|
#if defined(Q_OS_SYMBIAN)
|
|
QAction *autoOrientationAction = new QAction(tr("Auto-orientation"), this);
|
|
autoOrientationAction->setCheckable(true);
|
|
#endif
|
|
QAction *portraitAction = new QAction(tr("Portrait"), this);
|
|
portraitAction->setCheckable(true);
|
|
QAction *landscapeAction = new QAction(tr("Landscape"), this);
|
|
landscapeAction->setCheckable(true);
|
|
#if !defined(Q_OS_SYMBIAN)
|
|
QAction *portraitInvAction = new QAction(tr("Portrait (inverted)"), this);
|
|
portraitInvAction->setCheckable(true);
|
|
QAction *landscapeInvAction = new QAction(tr("Landscape (inverted)"), this);
|
|
landscapeInvAction->setCheckable(true);
|
|
#endif
|
|
|
|
QAction *aboutAction = new QAction(tr("&About Qt..."), this);
|
|
aboutAction->setMenuRole(QAction::AboutQtRole);
|
|
connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
|
|
|
|
QAction *closeAction = new QAction(tr("&Close"), this);
|
|
closeAction->setShortcuts(QKeySequence::Close);
|
|
connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
|
|
|
|
QAction *quitAction = new QAction(tr("&Quit"), this);
|
|
quitAction->setMenuRole(QAction::QuitRole);
|
|
quitAction->setShortcuts(QKeySequence::Quit);
|
|
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
|
|
|
QMenuBar *menu = menuBar();
|
|
if (!menu)
|
|
return;
|
|
|
|
#if defined(Q_WS_MAEMO_5)
|
|
menu->addAction(openAction);
|
|
menu->addAction(openUrlAction);
|
|
menu->addAction(reloadAction);
|
|
|
|
menu->addAction(snapshotAction);
|
|
menu->addAction(recordAction);
|
|
|
|
menu->addAction(recordOptions);
|
|
menu->addAction(proxyAction);
|
|
|
|
menu->addAction(playSpeedMenu);
|
|
menu->addAction(showWarningsWindow);
|
|
|
|
orientation->addAction(landscapeAction);
|
|
orientation->addAction(portraitAction);
|
|
menu->addAction(new Maemo5PickerAction(tr("Set orientation"), orientation, this));
|
|
menu->addAction(fullscreenAction);
|
|
return;
|
|
#endif // Q_WS_MAEMO_5
|
|
|
|
QMenu *fileMenu = menu->addMenu(tr("&File"));
|
|
fileMenu->addAction(openAction);
|
|
fileMenu->addAction(openUrlAction);
|
|
fileMenu->addAction(reloadAction);
|
|
fileMenu->addSeparator();
|
|
fileMenu->addAction(closeAction);
|
|
#if !defined(Q_OS_SYMBIAN)
|
|
fileMenu->addAction(quitAction);
|
|
|
|
QMenu *recordMenu = menu->addMenu(tr("&Recording"));
|
|
recordMenu->addAction(snapshotAction);
|
|
recordMenu->addAction(recordAction);
|
|
|
|
QMenu *debugMenu = menu->addMenu(tr("&Debugging"));
|
|
debugMenu->addMenu(playSpeedMenu);
|
|
debugMenu->addAction(showWarningsWindow);
|
|
debugMenu->addAction(designModeBehaviorAction);
|
|
debugMenu->addAction(appOnTopAction);
|
|
#endif // ! Q_OS_SYMBIAN
|
|
|
|
QMenu *settingsMenu = menu->addMenu(tr("&Settings"));
|
|
settingsMenu->addAction(proxyAction);
|
|
#if defined(Q_OS_SYMBIAN)
|
|
settingsMenu->addAction(fullscreenAction);
|
|
#else
|
|
settingsMenu->addAction(recordOptions);
|
|
settingsMenu->addMenu(loggerWindow->preferencesMenu());
|
|
#endif // !Q_OS_SYMBIAN
|
|
settingsMenu->addAction(rotateAction);
|
|
|
|
QMenu *propertiesMenu = settingsMenu->addMenu(tr("Properties"));
|
|
|
|
#if defined(Q_OS_SYMBIAN)
|
|
orientation->addAction(autoOrientationAction);
|
|
#endif
|
|
orientation->addAction(portraitAction);
|
|
orientation->addAction(landscapeAction);
|
|
#if !defined(Q_OS_SYMBIAN)
|
|
orientation->addAction(portraitInvAction);
|
|
orientation->addAction(landscapeInvAction);
|
|
#endif
|
|
propertiesMenu->addActions(orientation->actions());
|
|
|
|
QMenu *helpMenu = menu->addMenu(tr("&Help"));
|
|
helpMenu->addAction(aboutAction);
|
|
}
|
|
|
|
void QDeclarativeViewer::showProxySettings()
|
|
{
|
|
ProxySettings settingsDlg (this);
|
|
|
|
connect (&settingsDlg, SIGNAL (accepted()), this, SLOT (proxySettingsChanged ()));
|
|
|
|
settingsDlg.exec();
|
|
}
|
|
|
|
void QDeclarativeViewer::proxySettingsChanged()
|
|
{
|
|
namFactory->proxyChanged();
|
|
reload ();
|
|
}
|
|
|
|
void QDeclarativeViewer::rotateOrientation()
|
|
{
|
|
#if defined(Q_WS_S60)
|
|
CAknAppUi *appUi = static_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
|
|
if (appUi) {
|
|
CAknAppUi::TAppUiOrientation oldOrientation = appUi->Orientation();
|
|
QString newOrientation;
|
|
if (oldOrientation == CAknAppUi::EAppUiOrientationPortrait) {
|
|
newOrientation = QLatin1String("Landscape");
|
|
} else {
|
|
newOrientation = QLatin1String("Portrait");
|
|
}
|
|
foreach (QAction *action, orientation->actions()) {
|
|
if (action->text() == newOrientation) {
|
|
changeOrientation(action);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
QAction *current = orientation->checkedAction();
|
|
QList<QAction *> actions = orientation->actions();
|
|
int index = actions.indexOf(current);
|
|
if (index < 0)
|
|
return;
|
|
|
|
QAction *newOrientation = actions[(index + 1) % actions.count()];
|
|
changeOrientation(newOrientation);
|
|
#endif
|
|
}
|
|
|
|
void QDeclarativeViewer::toggleFullScreen()
|
|
{
|
|
if (isFullScreen())
|
|
showMaximized();
|
|
else
|
|
showFullScreen();
|
|
}
|
|
|
|
void QDeclarativeViewer::showWarnings(bool show)
|
|
{
|
|
loggerWindow->setVisible(show);
|
|
}
|
|
|
|
void QDeclarativeViewer::warningsWidgetOpened()
|
|
{
|
|
showWarningsWindow->setChecked(true);
|
|
}
|
|
|
|
void QDeclarativeViewer::warningsWidgetClosed()
|
|
{
|
|
showWarningsWindow->setChecked(false);
|
|
}
|
|
|
|
void QDeclarativeViewer::takeSnapShot()
|
|
{
|
|
static int snapshotcount = 1;
|
|
QString snapFileName = QString(QLatin1String("snapshot%1.png")).arg(snapshotcount);
|
|
QPixmap::grabWidget(canvas).save(snapFileName);
|
|
qDebug() << "Wrote" << snapFileName;
|
|
++snapshotcount;
|
|
}
|
|
|
|
void QDeclarativeViewer::pickRecordingFile()
|
|
{
|
|
QString fileName = getVideoFileName();
|
|
if (!fileName.isEmpty())
|
|
recdlg->file->setText(fileName);
|
|
}
|
|
|
|
void QDeclarativeViewer::chooseRecordingOptions()
|
|
{
|
|
// File
|
|
recdlg->file->setText(record_file);
|
|
|
|
// Size
|
|
recdlg->setOriginalSize(canvas->size());
|
|
|
|
// Rate
|
|
recdlg->setVideoRate(record_rate);
|
|
|
|
|
|
// Profile
|
|
recdlg->setArguments(record_args.join(" "));
|
|
if (recdlg->exec()) {
|
|
// File
|
|
record_file = recdlg->file->text();
|
|
// Size
|
|
record_outsize = recdlg->videoSize();
|
|
// Rate
|
|
record_rate = recdlg->videoRate();
|
|
// Profile
|
|
record_args = recdlg->arguments().split(QLatin1Char(' '),QString::SkipEmptyParts);
|
|
}
|
|
}
|
|
|
|
void QDeclarativeViewer::toggleRecordingWithSelection()
|
|
{
|
|
if (!recordTimer.isActive()) {
|
|
if (record_file.isEmpty()) {
|
|
QString fileName = getVideoFileName();
|
|
if (fileName.isEmpty())
|
|
return;
|
|
if (!fileName.contains(QRegExp(".[^\\/]*$")))
|
|
fileName += ".avi";
|
|
setRecordFile(fileName);
|
|
}
|
|
}
|
|
toggleRecording();
|
|
}
|
|
|
|
void QDeclarativeViewer::toggleRecording()
|
|
{
|
|
#ifndef NO_PRIVATE_HEADERS
|
|
if (record_file.isEmpty()) {
|
|
toggleRecordingWithSelection();
|
|
return;
|
|
}
|
|
bool recording = !recordTimer.isActive();
|
|
recordAction->setText(recording ? tr("&Stop Recording Video\tF9") : tr("&Start Recording Video\tF9"));
|
|
setRecording(recording);
|
|
#endif
|
|
}
|
|
|
|
void QDeclarativeViewer::pauseAnimations()
|
|
{
|
|
inspector->setAnimationPaused(true);
|
|
}
|
|
|
|
void QDeclarativeViewer::stepAnimations()
|
|
{
|
|
inspector->setAnimationPaused(false);
|
|
QTimer::singleShot(m_stepSize, this, SLOT(pauseAnimations()));
|
|
}
|
|
|
|
void QDeclarativeViewer::setAnimationStep()
|
|
{
|
|
bool ok;
|
|
int stepSize = QInputDialog::getInt(this, tr("Set animation step duration"),
|
|
tr("Step duration (ms):"), m_stepSize, 20, 10000, 1, &ok);
|
|
if (ok) m_stepSize = stepSize;
|
|
}
|
|
|
|
void QDeclarativeViewer::changeAnimationSpeed()
|
|
{
|
|
if (QAction *action = qobject_cast<QAction*>(sender()))
|
|
inspector->setAnimationSpeed(action->data().toFloat());
|
|
}
|
|
|
|
void QDeclarativeViewer::addLibraryPath(const QString& lib)
|
|
{
|
|
canvas->engine()->addImportPath(lib);
|
|
}
|
|
|
|
void QDeclarativeViewer::addPluginPath(const QString& plugin)
|
|
{
|
|
canvas->engine()->addPluginPath(plugin);
|
|
}
|
|
|
|
void QDeclarativeViewer::reload()
|
|
{
|
|
launch(currentFileOrUrl);
|
|
}
|
|
|
|
void QDeclarativeViewer::openFile()
|
|
{
|
|
QString cur = canvas->source().toLocalFile();
|
|
if (useQmlFileBrowser) {
|
|
open("qrc:/browser/Browser.qml");
|
|
} else {
|
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Open QML file"), cur, tr("QML Files (*.qml)"));
|
|
if (!fileName.isEmpty()) {
|
|
QFileInfo fi(fileName);
|
|
open(fi.absoluteFilePath());
|
|
}
|
|
}
|
|
}
|
|
|
|
void QDeclarativeViewer::openUrl()
|
|
{
|
|
QString cur = canvas->source().toLocalFile();
|
|
QString url= QInputDialog::getText(this, tr("Open QML file"), tr("URL of main QML file:"), QLineEdit::Normal, cur);
|
|
if (!url.isEmpty())
|
|
open(url);
|
|
}
|
|
|
|
void QDeclarativeViewer::statusChanged()
|
|
{
|
|
if (canvas->status() == QDeclarativeView::Error && tester)
|
|
tester->executefailure();
|
|
|
|
if (canvas->status() == QDeclarativeView::Ready) {
|
|
initialSize = canvas->initialSize();
|
|
updateSizeHints(true);
|
|
}
|
|
}
|
|
|
|
void QDeclarativeViewer::launch(const QString& file_or_url)
|
|
{
|
|
QMetaObject::invokeMethod(this, "open", Qt::QueuedConnection, Q_ARG(QString, file_or_url));
|
|
}
|
|
|
|
void QDeclarativeViewer::loadTranslationFile(const QString& directory)
|
|
{
|
|
if (!translator) {
|
|
translator = new QTranslator(this);
|
|
QApplication::installTranslator(translator);
|
|
}
|
|
|
|
translator->load(QLatin1String("qml_" )+QLocale::system().name(), directory + QLatin1String("/i18n"));
|
|
}
|
|
|
|
void QDeclarativeViewer::loadDummyDataFiles(const QString& directory)
|
|
{
|
|
QDir dir(directory+"/dummydata", "*.qml");
|
|
QStringList list = dir.entryList();
|
|
for (int i = 0; i < list.size(); ++i) {
|
|
QString qml = list.at(i);
|
|
QDeclarativeComponent comp(canvas->engine(), dir.filePath(qml));
|
|
QObject *dummyData = comp.create();
|
|
|
|
if(comp.isError()) {
|
|
QList<QDeclarativeError> errors = comp.errors();
|
|
foreach (const QDeclarativeError &error, errors) {
|
|
qWarning() << error;
|
|
}
|
|
if (tester) tester->executefailure();
|
|
}
|
|
|
|
if (dummyData) {
|
|
qWarning() << "Loaded dummy data:" << dir.filePath(qml);
|
|
qml.truncate(qml.length()-4);
|
|
canvas->rootContext()->setContextProperty(qml, dummyData);
|
|
dummyData->setParent(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool QDeclarativeViewer::open(const QString& file_or_url)
|
|
{
|
|
currentFileOrUrl = file_or_url;
|
|
|
|
QUrl url;
|
|
QFileInfo fi(file_or_url);
|
|
if (fi.exists())
|
|
url = QUrl::fromLocalFile(fi.absoluteFilePath());
|
|
else
|
|
url = QUrl(file_or_url);
|
|
setWindowTitle(tr("%1 - Qt QML Viewer").arg(file_or_url));
|
|
|
|
#ifndef NO_PRIVATE_HEADERS
|
|
if (!m_script.isEmpty())
|
|
tester = new QDeclarativeTester(m_script, m_scriptOptions, canvas);
|
|
#endif
|
|
|
|
delete canvas->rootObject();
|
|
canvas->engine()->clearComponentCache();
|
|
QDeclarativeContext *ctxt = canvas->rootContext();
|
|
ctxt->setContextProperty("qmlViewer", this);
|
|
#ifdef Q_OS_SYMBIAN
|
|
ctxt->setContextProperty("qmlViewerFolder", "E:\\"); // Documents on your S60 phone
|
|
#else
|
|
ctxt->setContextProperty("qmlViewerFolder", QDir::currentPath());
|
|
#endif
|
|
|
|
ctxt->setContextProperty("runtime", Runtime::instance());
|
|
|
|
QString fileName = url.toLocalFile();
|
|
if (!fileName.isEmpty()) {
|
|
fi.setFile(fileName);
|
|
if (fi.exists()) {
|
|
if (fi.suffix().toLower() != QLatin1String("qml")) {
|
|
qWarning() << "qml cannot open non-QML file" << fileName;
|
|
return false;
|
|
}
|
|
|
|
QFileInfo fi(fileName);
|
|
loadTranslationFile(fi.path());
|
|
loadDummyDataFiles(fi.path());
|
|
} else {
|
|
qWarning() << "qml cannot find file:" << fileName;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
QTime t;
|
|
t.start();
|
|
|
|
canvas->setSource(url);
|
|
|
|
return true;
|
|
}
|
|
|
|
void QDeclarativeViewer::setAutoRecord(int from, int to)
|
|
{
|
|
if (from==0) from=1; // ensure resized
|
|
record_autotime = to-from;
|
|
autoStartTimer.setInterval(from);
|
|
autoStartTimer.start();
|
|
}
|
|
|
|
void QDeclarativeViewer::setRecordArgs(const QStringList& a)
|
|
{
|
|
record_args = a;
|
|
}
|
|
|
|
void QDeclarativeViewer::setRecordFile(const QString& f)
|
|
{
|
|
record_file = f;
|
|
}
|
|
|
|
void QDeclarativeViewer::setRecordRate(int fps)
|
|
{
|
|
record_rate = fps;
|
|
}
|
|
|
|
void QDeclarativeViewer::sceneResized(QSize)
|
|
{
|
|
updateSizeHints();
|
|
}
|
|
|
|
void QDeclarativeViewer::keyPressEvent(QKeyEvent *event)
|
|
{
|
|
if (event->key() == Qt::Key_0 && devicemode)
|
|
exit(0);
|
|
else if (event->key() == Qt::Key_F1 || (event->key() == Qt::Key_1 && devicemode)) {
|
|
qDebug() << "F1 - help\n"
|
|
<< "F2 - save test script\n"
|
|
<< "F3 - take PNG snapshot\n"
|
|
<< "F4 - show items and state\n"
|
|
<< "F5 - reload QML\n"
|
|
<< "F6 - show object tree\n"
|
|
<< "F7 - show timing\n"
|
|
<< "F9 - toggle video recording\n"
|
|
<< "F10 - toggle orientation\n"
|
|
<< "device keys: 0=quit, 1..8=F1..F8"
|
|
;
|
|
} else if (event->key() == Qt::Key_F2 || (event->key() == Qt::Key_2 && devicemode)) {
|
|
if (tester && m_scriptOptions & Record)
|
|
tester->save();
|
|
} else if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_3 && devicemode)) {
|
|
takeSnapShot();
|
|
} else if (event->key() == Qt::Key_F5 || (event->key() == Qt::Key_5 && devicemode)) {
|
|
reload();
|
|
} else if (event->key() == Qt::Key_F9 || (event->key() == Qt::Key_9 && devicemode)) {
|
|
toggleRecording();
|
|
} else if (event->key() == Qt::Key_F10) {
|
|
rotateOrientation();
|
|
}
|
|
|
|
QWidget::keyPressEvent(event);
|
|
}
|
|
|
|
bool QDeclarativeViewer::event(QEvent *event)
|
|
{
|
|
if (event->type() == QEvent::WindowActivate) {
|
|
Runtime::instance()->setActiveWindow(true);
|
|
DeviceOrientation::instance()->resumeListening();
|
|
} else if (event->type() == QEvent::WindowDeactivate) {
|
|
Runtime::instance()->setActiveWindow(false);
|
|
DeviceOrientation::instance()->pauseListening();
|
|
}
|
|
return QWidget::event(event);
|
|
}
|
|
|
|
void QDeclarativeViewer::senseImageMagick()
|
|
{
|
|
QProcess proc;
|
|
proc.start("convert", QStringList() << "-h");
|
|
proc.waitForFinished(2000);
|
|
QString help = proc.readAllStandardOutput();
|
|
convertAvailable = help.contains("ImageMagick");
|
|
}
|
|
|
|
void QDeclarativeViewer::senseFfmpeg()
|
|
{
|
|
QProcess proc;
|
|
proc.start("ffmpeg", QStringList() << "-h");
|
|
proc.waitForFinished(2000);
|
|
QString ffmpegHelp = proc.readAllStandardOutput();
|
|
ffmpegAvailable = ffmpegHelp.contains("-s ");
|
|
ffmpegHelp = tr("Video recording uses ffmpeg:")+"\n\n"+ffmpegHelp;
|
|
|
|
QDialog *d = new QDialog(recdlg);
|
|
QVBoxLayout *l = new QVBoxLayout(d);
|
|
QTextBrowser *b = new QTextBrowser(d);
|
|
QFont f = b->font();
|
|
f.setFamily("courier");
|
|
b->setFont(f);
|
|
b->setText(ffmpegHelp);
|
|
l->addWidget(b);
|
|
d->setLayout(l);
|
|
ffmpegHelpWindow = d;
|
|
connect(recdlg->ffmpegHelp,SIGNAL(clicked()), ffmpegHelpWindow, SLOT(show()));
|
|
}
|
|
|
|
void QDeclarativeViewer::setRecording(bool on)
|
|
{
|
|
if (on == recordTimer.isActive())
|
|
return;
|
|
|
|
int period = int(1000/record_rate+0.5);
|
|
#ifndef NO_PRIVATE_HEADERS
|
|
QUnifiedTimer::instance()->setTimingInterval(on ? period:16);
|
|
QUnifiedTimer::instance()->setConsistentTiming(on);
|
|
#endif
|
|
if (on) {
|
|
canvas->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
|
|
recordTimer.setInterval(period);
|
|
recordTimer.start();
|
|
frame_fmt = record_file.right(4).toLower();
|
|
frame = QImage(canvas->width(),canvas->height(),QImage::Format_RGB32);
|
|
if (frame_fmt != ".png" && (!convertAvailable || frame_fmt != ".gif")) {
|
|
// Stream video to ffmpeg
|
|
|
|
QProcess *proc = new QProcess(this);
|
|
connect(proc, SIGNAL(finished(int)), this, SLOT(ffmpegFinished(int)));
|
|
frame_stream = proc;
|
|
|
|
QStringList args;
|
|
args << "-y";
|
|
args << "-r" << QString::number(record_rate);
|
|
args << "-f" << "rawvideo";
|
|
args << "-pix_fmt" << (frame_fmt == ".gif" ? "rgb24" : "rgb32");
|
|
args << "-s" << QString("%1x%2").arg(canvas->width()).arg(canvas->height());
|
|
args << "-i" << "-";
|
|
if (record_outsize.isValid()) {
|
|
args << "-s" << QString("%1x%2").arg(record_outsize.width()).arg(record_outsize.height());
|
|
args << "-aspect" << QString::number(double(canvas->width())/canvas->height());
|
|
}
|
|
args += record_args;
|
|
args << record_file;
|
|
proc->start("ffmpeg",args);
|
|
|
|
} else {
|
|
// Store frames, save to GIF/PNG
|
|
frame_stream = 0;
|
|
}
|
|
} else {
|
|
canvas->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
|
|
recordTimer.stop();
|
|
if (frame_stream) {
|
|
qDebug() << "Saving video...";
|
|
frame_stream->close();
|
|
qDebug() << "Wrote" << record_file;
|
|
} else {
|
|
QProgressDialog progress(tr("Saving frames..."), tr("Cancel"), 0, frames.count()+10, this);
|
|
progress.setWindowModality(Qt::WindowModal);
|
|
|
|
int frame=0;
|
|
QStringList inputs;
|
|
qDebug() << "Saving frames...";
|
|
|
|
QString framename;
|
|
bool png_output = false;
|
|
if (record_file.right(4).toLower()==".png") {
|
|
if (record_file.contains('%'))
|
|
framename = record_file;
|
|
else
|
|
framename = record_file.left(record_file.length()-4)+"%04d"+record_file.right(4);
|
|
png_output = true;
|
|
} else {
|
|
framename = "tmp-frame%04d.png";
|
|
png_output = false;
|
|
}
|
|
foreach (QImage* img, frames) {
|
|
progress.setValue(progress.value()+1);
|
|
if (progress.wasCanceled())
|
|
break;
|
|
QString name;
|
|
name.sprintf(framename.toLocal8Bit(),frame++);
|
|
if (record_outsize.isValid())
|
|
*img = img->scaled(record_outsize,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
|
|
if (record_dither=="ordered")
|
|
img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name);
|
|
else if (record_dither=="threshold")
|
|
img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name);
|
|
else if (record_dither=="floyd")
|
|
img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name);
|
|
else
|
|
img->save(name);
|
|
inputs << name;
|
|
delete img;
|
|
}
|
|
|
|
if (!progress.wasCanceled()) {
|
|
if (png_output) {
|
|
framename.replace(QRegExp("%\\d*."),"*");
|
|
qDebug() << "Wrote frames" << framename;
|
|
inputs.clear(); // don't remove them
|
|
} else {
|
|
// ImageMagick and gifsicle for GIF encoding
|
|
progress.setLabelText(tr("Converting frames to GIF file..."));
|
|
QStringList args;
|
|
args << "-delay" << QString::number(period/10);
|
|
args << inputs;
|
|
args << record_file;
|
|
qDebug() << "Converting..." << record_file << "(this may take a while)";
|
|
if (0!=QProcess::execute("convert", args)) {
|
|
qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted";
|
|
inputs.clear(); // don't remove them
|
|
qDebug() << "Wrote frames tmp-frame*.png";
|
|
} else {
|
|
if (record_file.right(4).toLower() == ".gif") {
|
|
qDebug() << "Compressing..." << record_file;
|
|
if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << record_file << record_file))
|
|
qWarning() << "Cannot run 'gifsicle' - not compressed";
|
|
}
|
|
qDebug() << "Wrote" << record_file;
|
|
}
|
|
}
|
|
}
|
|
|
|
progress.setValue(progress.maximum()-1);
|
|
foreach (const QString &name, inputs)
|
|
QFile::remove(name);
|
|
|
|
frames.clear();
|
|
}
|
|
}
|
|
qDebug() << "Recording: " << (recordTimer.isActive()?"ON":"OFF");
|
|
}
|
|
|
|
void QDeclarativeViewer::ffmpegFinished(int code)
|
|
{
|
|
qDebug() << "ffmpeg returned" << code << frame_stream->readAllStandardError();
|
|
}
|
|
|
|
void QDeclarativeViewer::appAboutToQuit()
|
|
{
|
|
// avoid QGLContext errors about invalid contexts on exit
|
|
canvas->setViewport(0);
|
|
|
|
// avoid crashes if messages are received after app has closed
|
|
delete loggerWindow;
|
|
loggerWindow = 0;
|
|
delete tester;
|
|
tester = 0;
|
|
}
|
|
|
|
void QDeclarativeViewer::autoStartRecording()
|
|
{
|
|
setRecording(true);
|
|
autoStopTimer.setInterval(record_autotime);
|
|
autoStopTimer.start();
|
|
}
|
|
|
|
void QDeclarativeViewer::autoStopRecording()
|
|
{
|
|
setRecording(false);
|
|
}
|
|
|
|
void QDeclarativeViewer::recordFrame()
|
|
{
|
|
canvas->QWidget::render(&frame);
|
|
if (frame_stream) {
|
|
if (frame_fmt == ".gif") {
|
|
// ffmpeg can't do 32bpp with gif
|
|
QImage rgb24 = frame.convertToFormat(QImage::Format_RGB888);
|
|
frame_stream->write((char*)rgb24.bits(),rgb24.numBytes());
|
|
} else {
|
|
frame_stream->write((char*)frame.bits(),frame.numBytes());
|
|
}
|
|
} else {
|
|
frames.append(new QImage(frame));
|
|
}
|
|
}
|
|
|
|
void QDeclarativeViewer::changeOrientation(QAction *action)
|
|
{
|
|
if (!action)
|
|
return;
|
|
QString o = action->text();
|
|
action->setChecked(true);
|
|
#if defined(Q_WS_S60)
|
|
CAknAppUi *appUi = static_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
|
|
if (appUi) {
|
|
CAknAppUi::TAppUiOrientation orientation = appUi->Orientation();
|
|
if (o == QLatin1String("Auto-orientation")) {
|
|
appUi->SetOrientationL(CAknAppUi::EAppUiOrientationAutomatic);
|
|
rotateAction->setVisible(false);
|
|
} else if (o == QLatin1String("Portrait")) {
|
|
appUi->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait);
|
|
rotateAction->setVisible(true);
|
|
} else if (o == QLatin1String("Landscape")) {
|
|
appUi->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape);
|
|
rotateAction->setVisible(true);
|
|
}
|
|
}
|
|
#else
|
|
if (o == QLatin1String("Portrait"))
|
|
DeviceOrientation::instance()->setOrientation(DeviceOrientation::Portrait);
|
|
else if (o == QLatin1String("Landscape"))
|
|
DeviceOrientation::instance()->setOrientation(DeviceOrientation::Landscape);
|
|
else if (o == QLatin1String("Portrait (inverted)"))
|
|
DeviceOrientation::instance()->setOrientation(DeviceOrientation::PortraitInverted);
|
|
else if (o == QLatin1String("Landscape (inverted)"))
|
|
DeviceOrientation::instance()->setOrientation(DeviceOrientation::LandscapeInverted);
|
|
#endif
|
|
}
|
|
|
|
void QDeclarativeViewer::orientationChanged()
|
|
{
|
|
updateSizeHints();
|
|
}
|
|
|
|
void QDeclarativeViewer::animationSpeedChanged(qreal factor)
|
|
{
|
|
foreach (QAction *action, playSpeedMenuActions->actions()) {
|
|
if (action->data().toFloat() == factor) {
|
|
action->setChecked(true);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void QDeclarativeViewer::setDeviceKeys(bool on)
|
|
{
|
|
devicemode = on;
|
|
}
|
|
|
|
void QDeclarativeViewer::setNetworkCacheSize(int size)
|
|
{
|
|
namFactory->setCacheSize(size);
|
|
}
|
|
|
|
void QDeclarativeViewer::setUseGL(bool useGL)
|
|
{
|
|
#ifdef GL_SUPPORTED
|
|
if (useGL) {
|
|
QGLFormat format = QGLFormat::defaultFormat();
|
|
#ifdef Q_WS_MAC
|
|
format.setSampleBuffers(true);
|
|
#else
|
|
format.setSampleBuffers(false);
|
|
#endif
|
|
|
|
QGLWidget *glWidget = new QGLWidget(format);
|
|
//### potentially faster, but causes junk to appear if top-level is Item, not Rectangle
|
|
//glWidget->setAutoFillBackground(false);
|
|
|
|
canvas->setViewport(glWidget);
|
|
}
|
|
#else
|
|
Q_UNUSED(useGL)
|
|
#endif
|
|
}
|
|
|
|
void QDeclarativeViewer::setUseNativeFileBrowser(bool use)
|
|
{
|
|
useQmlFileBrowser = !use;
|
|
}
|
|
|
|
void QDeclarativeViewer::setSizeToView(bool sizeToView)
|
|
{
|
|
QDeclarativeView::ResizeMode resizeMode = sizeToView ? QDeclarativeView::SizeRootObjectToView : QDeclarativeView::SizeViewToRootObject;
|
|
if (resizeMode != canvas->resizeMode()) {
|
|
canvas->setResizeMode(resizeMode);
|
|
updateSizeHints();
|
|
}
|
|
}
|
|
|
|
void QDeclarativeViewer::setStayOnTop(bool stayOnTop)
|
|
{
|
|
appOnTopAction->setChecked(stayOnTop);
|
|
}
|
|
|
|
void QDeclarativeViewer::updateSizeHints(bool initial)
|
|
{
|
|
static bool isRecursive = false;
|
|
|
|
if (isRecursive)
|
|
return;
|
|
isRecursive = true;
|
|
|
|
if (initial || (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject)) {
|
|
QSize newWindowSize = initial ? initialSize : canvas->sizeHint();
|
|
//qWarning() << "USH:" << (initial ? "INIT:" : "V2R:") << "setting fixed size " << newWindowSize;
|
|
if (!isFullScreen() && !isMaximized()) {
|
|
canvas->setFixedSize(newWindowSize);
|
|
resize(1, 1);
|
|
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
|
layout()->activate();
|
|
}
|
|
}
|
|
//qWarning() << "USH: R2V: setting free size ";
|
|
layout()->setSizeConstraint(QLayout::SetNoConstraint);
|
|
layout()->activate();
|
|
setMinimumSize(minimumSizeHint());
|
|
setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
|
|
canvas->setMinimumSize(QSize(0,0));
|
|
canvas->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
|
|
|
|
isRecursive = false;
|
|
}
|
|
|
|
void QDeclarativeViewer::registerTypes()
|
|
{
|
|
static bool registered = false;
|
|
|
|
if (!registered) {
|
|
// registering only for exposing the DeviceOrientation::Orientation enum
|
|
qmlRegisterUncreatableType<DeviceOrientation>("Qt",4,7,"Orientation","");
|
|
qmlRegisterUncreatableType<DeviceOrientation>("QtQuick",1,0,"Orientation","");
|
|
registered = true;
|
|
}
|
|
}
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
#include "qmlruntime.moc"
|