From fb5d5ce1cd1e2714343c3e26338601aa5dd79a54 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 15 Oct 2009 10:13:55 +1000 Subject: Give more information about the value of a property when the variant toString() is empty. --- src/declarative/qml/qmlenginedebug.cpp | 12 +++++++++--- tools/qmldebugger/objectpropertiesview.cpp | 16 +++++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index e20616a..1c7450a 100644 --- a/src/declarative/qml/qmlenginedebug.cpp +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -318,7 +318,7 @@ void QmlEngineDebugServer::propertyChanged(int id, int objectId, const QByteArra QByteArray reply; QVariant v; QDataStream rs(&reply, QIODevice::WriteOnly); - + if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { QObject *o = QmlMetaType::toQObject(value); if (o) { @@ -327,9 +327,15 @@ void QmlEngineDebugServer::propertyChanged(int id, int objectId, const QByteArra objectName = QLatin1String(""); v = QString::fromUtf8(o->metaObject()->className()) + QLatin1String(": ") + objectName; + } else { + v = QString::fromUtf8(value.typeName()); + } + if (v.isNull()) { + QString s = value.toString(); + if (s.isEmpty()) + s = QLatin1String(""); + v = s; } - if (v.isNull()) - v = value.toString(); } else { v = value; } diff --git a/tools/qmldebugger/objectpropertiesview.cpp b/tools/qmldebugger/objectpropertiesview.cpp index f725194..864468c 100644 --- a/tools/qmldebugger/objectpropertiesview.cpp +++ b/tools/qmldebugger/objectpropertiesview.cpp @@ -109,7 +109,7 @@ void ObjectPropertiesView::setObject(const QmlDebugObjectReference &object) item->setText(0, p.name()); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); if (!p.hasNotifySignal()) - item->setForeground(0, Qt::lightGray); + item->setForeground(0, Qt::gray); if (!p.binding().isEmpty()) { PropertiesViewItem *binding = new PropertiesViewItem(item); @@ -159,8 +159,18 @@ void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant & { for (int i=0; itopLevelItemCount(); i++) { PropertiesViewItem *item = static_cast(m_tree->topLevelItem(i)); - if (item->property.name() == name) - item->setText(1, value.toString()); + if (item->property.name() == name) { + if (value.isNull()) { + item->setText(1, QLatin1String("null")); + item->setForeground(1, Qt::gray); + } else { + QString s = value.toString(); + if (s.isEmpty()) + s = QString::fromUtf8(value.typeName()); + item->setText(1, s); + item->setForeground(1, QBrush()); + } + } } } -- cgit v0.12 From b5702e57ff6ab2e6fda63d760198ea417d312e89 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Fri, 16 Oct 2009 16:02:56 +1000 Subject: Don't try to open non-qml files. --- tools/qmlviewer/qmlviewer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 07b68ea..a8034cf 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -630,6 +630,11 @@ void QmlViewer::openQml(const QString& fileName) QUrl url(fileName); QFileInfo fi(fileName); if (fi.exists()) { + if (fi.suffix().toLower() != QLatin1String("qml")) { + qWarning() << "qmlviewer cannot open non-QML file" << fileName; + return; + } + url = QUrl::fromLocalFile(fi.absoluteFilePath()); QmlContext *ctxt = canvas->rootContext(); QDir dir(fi.path()+"/dummydata", "*.qml"); @@ -658,6 +663,9 @@ void QmlViewer::openQml(const QString& fileName) dummyData->setParent(this); } } + } else { + qWarning() << "qmlviewer cannot find file:" << fileName; + return; } canvas->setUrl(url); -- cgit v0.12 From 0ae3e10fecfe9f6241e8752bdd4deab8663988b7 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 20 Oct 2009 09:28:12 +1000 Subject: Add bool* argument to QmlExpression::value() to help debugger. --- src/declarative/qml/qmlexpression.cpp | 16 +++++++++++----- src/declarative/qml/qmlexpression.h | 2 +- src/declarative/qml/qmlexpression_p.h | 4 ++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 76ca2c1..e158621 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -275,7 +275,7 @@ void QmlExpressionPrivate::printException(QScriptEngine *scriptEngine) } } -QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) +QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUndefined) { #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer perfqt; @@ -312,6 +312,9 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QScriptValue svalue = data->expressionFunction.call(); + if (isUndefined) + *isUndefined = svalue.isUndefined(); + if (scriptEngine->hasUncaughtException()) printException(scriptEngine); @@ -352,7 +355,7 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) return rv; } -QVariant QmlExpressionPrivate::value(QObject *secondaryScope) +QVariant QmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) { Q_Q(QmlExpression); @@ -379,7 +382,7 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope) if (data->sse.isValid()) { rv = evalSSE(); } else { - rv = evalQtScript(secondaryScope); + rv = evalQtScript(secondaryScope, isUndefined); } ep->currentExpression = lastCurrentExpression; @@ -403,11 +406,14 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope) /*! Returns the value of the expression, or an invalid QVariant if the expression is invalid or has an error. + + \a isUndefined is set to true if the expression resulted in an + undefined value. */ -QVariant QmlExpression::value() +QVariant QmlExpression::value(bool *isUndefined) { Q_D(QmlExpression); - return d->value(); + return d->value(0, isUndefined); } /*! diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index b85e0a7..169d096 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -81,7 +81,7 @@ public: QObject *scopeObject() const; public Q_SLOTS: - QVariant value(); + QVariant value(bool *isUndefined = 0); Q_SIGNALS: virtual void valueChanged(); diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index d9bb27b..3ec8d1c 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -140,9 +140,9 @@ public: QmlExpressionData *data; - QVariant value(QObject *secondaryScope = 0); + QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); QVariant evalSSE(); - QVariant evalQtScript(QObject *secondaryScope); + QVariant evalQtScript(QObject *secondaryScope, bool *isUndefined = 0); void updateGuards(const QPODVector &properties); void clearGuards(); -- cgit v0.12 From 515cb0f40654e54384fd75c7042b9fa25d3df193 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 20 Oct 2009 09:54:57 +1000 Subject: Add EVAL_EXPRESSION so clients can evaluate an expression within the current object's context. --- src/declarative/debugger/qmldebug.cpp | 66 +++++++++++++++++++++++++++- src/declarative/debugger/qmldebug.h | 22 ++++++++++ src/declarative/qml/qmlenginedebug.cpp | 78 ++++++++++++++++++++++++---------- src/declarative/qml/qmlenginedebug_p.h | 1 + 4 files changed, 144 insertions(+), 23 deletions(-) diff --git a/src/declarative/debugger/qmldebug.cpp b/src/declarative/debugger/qmldebug.cpp index 1ef7503..75418e8 100644 --- a/src/declarative/debugger/qmldebug.cpp +++ b/src/declarative/debugger/qmldebug.cpp @@ -32,10 +32,12 @@ public: static void remove(QmlEngineDebug *, QmlDebugEnginesQuery *); static void remove(QmlEngineDebug *, QmlDebugRootContextQuery *); static void remove(QmlEngineDebug *, QmlDebugObjectQuery *); + static void remove(QmlEngineDebug *, QmlDebugExpressionQuery *); QHash enginesQuery; QHash rootContextQuery; QHash objectQuery; + QHash expressionQuery; QHash watched; }; @@ -81,6 +83,12 @@ void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugObjectQuery *q) p->objectQuery.remove(q->m_queryId); } +void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugExpressionQuery *q) +{ + QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c); + p->expressionQuery.remove(q->m_queryId); +} + Q_DECLARE_METATYPE(QmlDebugObjectReference); void QmlEngineDebugPrivate::decode(QDataStream &ds, QmlDebugObjectReference &o, bool simple) @@ -212,6 +220,19 @@ void QmlEngineDebugPrivate::message(const QByteArray &data) query->m_client = 0; query->setState(QmlDebugQuery::Completed); + } else if (type == "EVAL_EXPRESSION_R") { + int queryId; + QVariant result; + ds >> queryId >> result; + + QmlDebugExpressionQuery *query = expressionQuery.value(queryId); + if (!query) + return; + expressionQuery.remove(queryId); + + query->m_result = result; + query->m_client = 0; + query->setState(QmlDebugQuery::Completed); } else if (type == "WATCH_PROPERTY_R") { int queryId; bool ok; @@ -267,7 +288,6 @@ QmlDebugPropertyWatch *QmlEngineDebug::addWatch(const QmlDebugPropertyReference QmlDebugPropertyWatch *watch = new QmlDebugPropertyWatch(parent); if (d->client->isConnected()) { - //query->m_client = this; int queryId = d->getId(); watch->m_queryId = queryId; watch->m_objectDebugId = property.objectDebugId(); @@ -445,6 +465,29 @@ QmlDebugObjectQuery *QmlEngineDebug::queryObjectRecursive(const QmlDebugObjectRe return query; } +QmlDebugExpressionQuery *QmlEngineDebug::queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent) +{ + Q_D(QmlEngineDebug); + + QmlDebugExpressionQuery *query = new QmlDebugExpressionQuery(parent); + if (d->client->isConnected() && objectDebugId != -1) { + query->m_client = this; + query->m_expr = expr; + int queryId = d->getId(); + query->m_queryId = queryId; + d->expressionQuery.insert(queryId, query); + + QByteArray message; + QDataStream ds(&message, QIODevice::WriteOnly); + ds << QByteArray("EVAL_EXPRESSION") << queryId << objectDebugId << expr; + d->client->sendMessage(message); + } else { + query->m_state = QmlDebugQuery::Error; + } + + return query; +} + QmlDebugWatch::QmlDebugWatch(QObject *parent) : QObject(parent), m_state(Waiting), m_queryId(-1), m_objectDebugId(-1) { @@ -566,6 +609,27 @@ QmlDebugObjectReference QmlDebugObjectQuery::object() const return m_object; } +QmlDebugExpressionQuery::QmlDebugExpressionQuery(QObject *parent) +: QmlDebugQuery(parent), m_client(0), m_queryId(-1) +{ +} + +QmlDebugExpressionQuery::~QmlDebugExpressionQuery() +{ + if (m_client && m_queryId != -1) + QmlEngineDebugPrivate::remove(m_client, this); +} + +QString QmlDebugExpressionQuery::expression() const +{ + return m_expr; +} + +QVariant QmlDebugExpressionQuery::result() const +{ + return m_result; +} + QmlDebugEngineReference::QmlDebugEngineReference() : m_debugId(-1) { diff --git a/src/declarative/debugger/qmldebug.h b/src/declarative/debugger/qmldebug.h index 681ee08..153a10f 100644 --- a/src/declarative/debugger/qmldebug.h +++ b/src/declarative/debugger/qmldebug.h @@ -12,6 +12,7 @@ class QmlDebugObjectExpressionWatch; class QmlDebugEnginesQuery; class QmlDebugRootContextQuery; class QmlDebugObjectQuery; +class QmlDebugExpressionQuery; class QmlDebugPropertyReference; class QmlDebugContextReference; class QmlDebugObjectReference; @@ -44,6 +45,9 @@ public: QObject *parent = 0); QmlDebugObjectQuery *queryObjectRecursive(const QmlDebugObjectReference &, QObject *parent = 0); + QmlDebugExpressionQuery *queryExpressionResult(int objectDebugId, + const QString &expr, + QObject *parent = 0); private: Q_DECLARE_PRIVATE(QmlEngineDebug) @@ -287,4 +291,22 @@ private: }; +class Q_DECLARATIVE_EXPORT QmlDebugExpressionQuery : public QmlDebugQuery +{ +Q_OBJECT +public: + virtual ~QmlDebugExpressionQuery(); + QString expression() const; + QVariant result() const; +private: + friend class QmlEngineDebug; + friend class QmlEngineDebugPrivate; + QmlDebugExpressionQuery(QObject *); + QmlEngineDebug *m_client; + int m_queryId; + QString m_expr; + QVariant m_result; + +}; + #endif // QMLDEBUG_H diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index 1c7450a..bbe6f77 100644 --- a/src/declarative/qml/qmlenginedebug.cpp +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -184,6 +184,33 @@ void QmlEngineDebugServer::buildObjectList(QDataStream &message, } } +QVariant QmlEngineDebugServer::serializableVariant(const QVariant &value) +{ + QVariant v; + if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { + QObject *o = QmlMetaType::toQObject(value); + if (o) { + QString objectName = o->objectName(); + if (objectName.isEmpty()) + objectName = QLatin1String(""); + v = QString::fromUtf8(o->metaObject()->className()) + + QLatin1String(": ") + objectName; + } else { + v = QString::fromUtf8(value.typeName()); + } + if (v.isNull()) { + QString s = value.toString(); + if (s.isEmpty()) + s = QLatin1String(""); + v = s; + } + } else { + v = value; + } + + return v; +} + QmlEngineDebugServer::QmlObjectData QmlEngineDebugServer::objectData(QObject *object) { @@ -310,36 +337,43 @@ void QmlEngineDebugServer::messageReceived(const QByteArray &message) ds >> queryId; m_watch->removeWatch(queryId); + } else if (type == "EVAL_EXPRESSION") { + int queryId; + int objectId; + QString expr; + + ds >> queryId >> objectId >> expr; + + QObject *object = QmlDebugService::objectForId(objectId); + QmlContext *context = qmlContext(object); + QVariant result; + if (object && context) { + QmlExpression *exprObj = new QmlExpression(context, expr, object); + bool undefined = false; + QVariant value = exprObj->value(&undefined); + if (undefined) + result = QLatin1String(""); + else + result = serializableVariant(value); + delete exprObj; + } else { + result = QLatin1String(""); + } + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result; + + sendMessage(reply); } } void QmlEngineDebugServer::propertyChanged(int id, int objectId, const QByteArray &property, const QVariant &value) { QByteArray reply; - QVariant v; + QVariant v = serializableVariant(value); QDataStream rs(&reply, QIODevice::WriteOnly); - if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { - QObject *o = QmlMetaType::toQObject(value); - if (o) { - QString objectName = o->objectName(); - if (objectName.isEmpty()) - objectName = QLatin1String(""); - v = QString::fromUtf8(o->metaObject()->className()) + - QLatin1String(": ") + objectName; - } else { - v = QString::fromUtf8(value.typeName()); - } - if (v.isNull()) { - QString s = value.toString(); - if (s.isEmpty()) - s = QLatin1String(""); - v = s; - } - } else { - v = value; - } - rs << QByteArray("UPDATE_WATCH") << id << objectId << property << v; sendMessage(reply); diff --git a/src/declarative/qml/qmlenginedebug_p.h b/src/declarative/qml/qmlenginedebug_p.h index e2f903c..9ad198a 100644 --- a/src/declarative/qml/qmlenginedebug_p.h +++ b/src/declarative/qml/qmlenginedebug_p.h @@ -103,6 +103,7 @@ private: void buildObjectDump(QDataStream &, QObject *, bool); QmlObjectData objectData(QObject *); QmlObjectProperty propertyData(QObject *, int); + QVariant serializableVariant(const QVariant &value); static QList m_engines; QmlWatcher *m_watch; -- cgit v0.12 From 85fe2b6ece1e590199bcf7960c1a40e816e81105 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 20 Oct 2009 09:57:41 +1000 Subject: Add ExpressionQueryWidget and do some clean up. --- tools/qmldebugger/expressionquerywidget.cpp | 181 ++++++++++++++++++++++++++++ tools/qmldebugger/expressionquerywidget.h | 58 +++++++++ tools/qmldebugger/objectpropertiesview.cpp | 2 +- tools/qmldebugger/objecttree.cpp | 10 +- tools/qmldebugger/objecttree.h | 6 +- tools/qmldebugger/qmldebugger.cpp | 4 + tools/qmldebugger/qmldebugger.pri | 6 +- tools/qmldebugger/watchtable.cpp | 3 + 8 files changed, 259 insertions(+), 11 deletions(-) create mode 100644 tools/qmldebugger/expressionquerywidget.cpp create mode 100644 tools/qmldebugger/expressionquerywidget.h diff --git a/tools/qmldebugger/expressionquerywidget.cpp b/tools/qmldebugger/expressionquerywidget.cpp new file mode 100644 index 0000000..90ab8ee --- /dev/null +++ b/tools/qmldebugger/expressionquerywidget.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "expressionquerywidget.h" + +ExpressionQueryWidget::ExpressionQueryWidget(QmlEngineDebug *client, QWidget *parent) + : QWidget(parent), + m_style(Compact), + m_client(client), + m_query(0), + m_groupBox(0), + m_textEdit(new QTextEdit), + m_lineEdit(0) +{ + m_prompt = QLatin1String(">> "); + + m_groupBox = new QGroupBox; + QVBoxLayout *vbox = new QVBoxLayout(m_groupBox); + vbox->addWidget(m_textEdit); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(m_groupBox); + + updateTitle(); + + if (m_style == Compact) { + QHBoxLayout *hbox = new QHBoxLayout; + QPushButton *button = new QPushButton(tr("Execute")); + connect(button, SIGNAL(clicked()), SLOT(executeExpression())); + m_lineEdit = new QLineEdit; + connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(executeExpression())); + hbox->addWidget(new QLabel(tr("Expression:"))); + hbox->addWidget(m_lineEdit); + hbox->addWidget(button); + vbox->addLayout(hbox); + + m_textEdit->setReadOnly(true); + } else { + m_textEdit->installEventFilter(this); + } +} + +void ExpressionQueryWidget::updateTitle() +{ + if (m_currObject.debugId() < 0) { + m_groupBox->setTitle(tr("Expression queries")); + } else { + QString desc = QLatin1String("<") + + m_currObject.className() + QLatin1String(": ") + + (m_currObject.name().isEmpty() ? QLatin1String("") : m_currObject.name()) + + QLatin1String(">"); + m_groupBox->setTitle(tr("Expression queries (current context: %1)" + , "Selected object").arg(desc)); + } +} + +void ExpressionQueryWidget::appendPrompt() +{ + m_textEdit->moveCursor(QTextCursor::End); + + if (m_style == Compact) { + m_textEdit->insertPlainText("\n"); + } else { + m_textEdit->setTextColor(Qt::gray); + m_textEdit->append(m_prompt); + } +} + +void ExpressionQueryWidget::setCurrentObject(const QmlDebugObjectReference &obj) +{ + m_currObject = obj; + updateTitle(); +} + +void ExpressionQueryWidget::checkCurrentContext() +{ + m_textEdit->moveCursor(QTextCursor::End); + + if (m_currObject.debugId() != -1 && m_currObject.debugId() != m_objectAtLastFocus.debugId()) + showCurrentContext(); + m_objectAtLastFocus = m_currObject; +} + +void ExpressionQueryWidget::showCurrentContext() +{ + m_textEdit->moveCursor(QTextCursor::End); + m_textEdit->setTextColor(Qt::darkGreen); + m_textEdit->append(m_currObject.className() + + QLatin1String(": ") + + (m_currObject.name().isEmpty() ? QLatin1String("") : m_currObject.name())); + appendPrompt(); +} + +void ExpressionQueryWidget::executeExpression() +{ + if (m_style == Compact) + m_expr = m_lineEdit->text().trimmed(); + + if (!m_expr.trimmed().isEmpty() && m_currObject.debugId() != -1) { + checkCurrentContext(); + if (m_query) + delete m_query; + m_query = m_client->queryExpressionResult(m_currObject.debugId(), m_expr.trimmed(), this); + if (!m_query->isWaiting()) + showResult(); + else + QObject::connect(m_query, SIGNAL(stateChanged(State)), + this, SLOT(showResult())); + + if (m_lineEdit) + m_lineEdit->clear(); + } +} + +void ExpressionQueryWidget::showResult() +{ + if (m_query) { + m_textEdit->moveCursor(QTextCursor::End); + QString result = m_query->result().toString(); + if (result.isEmpty()) + result = QLatin1String(""); + + if (m_style == Compact) { + m_textEdit->setTextColor(Qt::black); + m_textEdit->setFontWeight(QFont::Bold); + m_textEdit->insertPlainText(m_expr + " : "); + m_textEdit->setFontWeight(QFont::Normal); + m_textEdit->insertPlainText(result); + } else { + m_textEdit->append(result); + } + appendPrompt(); + m_expr.clear(); + } +} + +bool ExpressionQueryWidget::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == m_textEdit) { + switch (event->type()) { + case QEvent::KeyPress: + { + QKeyEvent *keyEvent = static_cast(event); + int key = keyEvent->key(); + if (key == Qt::Key_Return || key == Qt::Key_Enter) { + executeExpression(); + return true; + } else if (key == Qt::Key_Backspace) { + // ensure m_expr doesn't contain backspace characters + QTextCursor cursor = m_textEdit->textCursor(); + bool atLastLine = !(cursor.block().next().isValid()); + if (!atLastLine) + return true; + if (cursor.columnNumber() <= m_prompt.count()) + return true; + cursor.deletePreviousChar(); + m_expr = cursor.block().text().mid(m_prompt.count()); + return true; + } else { + m_textEdit->moveCursor(QTextCursor::End); + m_textEdit->setTextColor(Qt::black); + m_expr += keyEvent->text(); + } + break; + } + case QEvent::FocusIn: + checkCurrentContext(); + m_textEdit->moveCursor(QTextCursor::End); + break; + default: + break; + } + } + return QWidget::eventFilter(obj, event); +} diff --git a/tools/qmldebugger/expressionquerywidget.h b/tools/qmldebugger/expressionquerywidget.h new file mode 100644 index 0000000..3ea95ac --- /dev/null +++ b/tools/qmldebugger/expressionquerywidget.h @@ -0,0 +1,58 @@ +#ifndef EXPRESSIONQUERYWIDGET_H +#define EXPRESSIONQUERYWIDGET_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QGroupBox; +class QTextEdit; +class QLineEdit; + +class ExpressionQueryWidget : public QWidget +{ + Q_OBJECT +public: + enum Style { + Compact, + Shell + }; + + ExpressionQueryWidget(QmlEngineDebug *client, QWidget *parent = 0); + +protected: + bool eventFilter(QObject *obj, QEvent *event); + +public slots: + void setCurrentObject(const QmlDebugObjectReference &obj); + +private slots: + void executeExpression(); + void showResult(); + +private: + void appendPrompt(); + void checkCurrentContext(); + void showCurrentContext(); + void updateTitle(); + + Style m_style; + + QmlEngineDebug *m_client; + QmlDebugExpressionQuery *m_query; + QGroupBox *m_groupBox; + QTextEdit *m_textEdit; + QLineEdit *m_lineEdit; + QString m_prompt; + QString m_expr; + + QmlDebugObjectReference m_currObject; + QmlDebugObjectReference m_objectAtLastFocus; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/tools/qmldebugger/objectpropertiesview.cpp b/tools/qmldebugger/objectpropertiesview.cpp index 864468c..4a2f97d 100644 --- a/tools/qmldebugger/objectpropertiesview.cpp +++ b/tools/qmldebugger/objectpropertiesview.cpp @@ -177,7 +177,7 @@ void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant & void ObjectPropertiesView::itemActivated(QTreeWidgetItem *i) { PropertiesViewItem *item = static_cast(i); - if (!item->property.name().isEmpty() && item->property.hasNotifySignal()) + if (!item->property.name().isEmpty()) emit activated(m_object, item->property); } diff --git a/tools/qmldebugger/objecttree.cpp b/tools/qmldebugger/objecttree.cpp index f68e7f1..0b92ceb 100644 --- a/tools/qmldebugger/objecttree.cpp +++ b/tools/qmldebugger/objecttree.cpp @@ -19,8 +19,8 @@ ObjectTree::ObjectTree(QmlEngineDebug *client, QWidget *parent) { setHeaderHidden(true); - connect(this, SIGNAL(itemClicked(QTreeWidgetItem *, int)), - this, SLOT(handleItemClicked(QTreeWidgetItem *))); + connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), + this, SLOT(currentItemChanged(QTreeWidgetItem *))); } void ObjectTree::reload(int objectDebugId) @@ -38,7 +38,7 @@ void ObjectTree::reload(int objectDebugId) this, SLOT(objectFetched())); } -void ObjectTree::selectObject(int debugId) +void ObjectTree::setCurrentObject(int debugId) { QTreeWidgetItem *item = findItemByObjectId(debugId); if (item) { @@ -57,14 +57,14 @@ void ObjectTree::objectFetched() m_query = 0; } -void ObjectTree::handleItemClicked(QTreeWidgetItem *item) +void ObjectTree::currentItemChanged(QTreeWidgetItem *item) { QmlDebugObjectReference obj = item->data(0, Qt::UserRole).value(); if (obj.debugId() < 0) { qWarning("QML Object Tree: bad object id"); return; } - emit objectSelected(obj); + emit currentObjectChanged(obj); } void ObjectTree::buildTree(const QmlDebugObjectReference &obj, QTreeWidgetItem *parent) diff --git a/tools/qmldebugger/objecttree.h b/tools/qmldebugger/objecttree.h index bba6c08..3c0a5c6 100644 --- a/tools/qmldebugger/objecttree.h +++ b/tools/qmldebugger/objecttree.h @@ -20,19 +20,19 @@ public: ObjectTree(QmlEngineDebug *client, QWidget *parent = 0); signals: - void objectSelected(const QmlDebugObjectReference &); + void currentObjectChanged(const QmlDebugObjectReference &); void expressionWatchRequested(const QmlDebugObjectReference &, const QString &); public slots: void reload(int objectDebugId); - void selectObject(int debugId); + void setCurrentObject(int debugId); protected: virtual void mousePressEvent(QMouseEvent *); private slots: void objectFetched(); - void handleItemClicked(QTreeWidgetItem *); + void currentItemChanged(QTreeWidgetItem *); private: QTreeWidgetItem *findItemByObjectId(int debugId) const; diff --git a/tools/qmldebugger/qmldebugger.cpp b/tools/qmldebugger/qmldebugger.cpp index 0f0fc03..e0a76b6 100644 --- a/tools/qmldebugger/qmldebugger.cpp +++ b/tools/qmldebugger/qmldebugger.cpp @@ -57,6 +57,10 @@ QmlDebugger::QmlDebugger(QWidget *parent) QObject::connect(&client, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError))); + + + m_tabs->setCurrentIndex(1); + connectToHost(); } void QmlDebugger::setHost(const QString &host) diff --git a/tools/qmldebugger/qmldebugger.pri b/tools/qmldebugger/qmldebugger.pri index ce36381..c49d334 100644 --- a/tools/qmldebugger/qmldebugger.pri +++ b/tools/qmldebugger/qmldebugger.pri @@ -7,7 +7,8 @@ HEADERS += $$PWD/qmldebugger.h \ $$PWD/watchtable.h \ $$PWD/engine.h \ $$PWD/objecttree.h \ - $$PWD/objectpropertiesview.h + $$PWD/objectpropertiesview.h \ + $$PWD/expressionquerywidget.h SOURCES += $$PWD/qmldebugger.cpp \ $$PWD/main.cpp \ @@ -15,7 +16,8 @@ SOURCES += $$PWD/qmldebugger.cpp \ $$PWD/watchtable.cpp \ $$PWD/engine.cpp \ $$PWD/objecttree.cpp \ - $$PWD/objectpropertiesview.cpp + $$PWD/objectpropertiesview.cpp \ + $$PWD/expressionquerywidget.cpp RESOURCES += $$PWD/qmldebugger.qrc diff --git a/tools/qmldebugger/watchtable.cpp b/tools/qmldebugger/watchtable.cpp index e4163dc..512bfb2 100644 --- a/tools/qmldebugger/watchtable.cpp +++ b/tools/qmldebugger/watchtable.cpp @@ -193,6 +193,9 @@ void WatchTableModel::addValue(int column, const QVariant &value) void WatchTableModel::togglePropertyWatch(const QmlDebugObjectReference &object, const QmlDebugPropertyReference &property) { + if (!property.hasNotifySignal()) + return; + QmlDebugWatch *watch = findWatch(object.debugId(), property.name()); if (watch) { // watch will be deleted in watchStateChanged() -- cgit v0.12 From 925366b08087f82b6b3d74c167946dd07e73b5c1 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Tue, 20 Oct 2009 15:29:51 +1000 Subject: typo QT-2335 --- src/declarative/qml/qmlsqldatabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/qml/qmlsqldatabase.cpp b/src/declarative/qml/qmlsqldatabase.cpp index 4a5983d..9e39ffc 100644 --- a/src/declarative/qml/qmlsqldatabase.cpp +++ b/src/declarative/qml/qmlsqldatabase.cpp @@ -340,7 +340,7 @@ static QScriptValue qmlsqldatabase_open(QScriptContext *context, QScriptEngine * QString basename = QmlEnginePrivate::get(engine)->offlineStoragePath + QLatin1String("/Databases/"); QDir().mkpath(basename); basename += dbid; - database.setDatabaseName(basename+QLatin1String(".sqllite")); + database.setDatabaseName(basename+QLatin1String(".sqlite")); QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat); ini.setValue(QLatin1String("Name"), dbname); ini.setValue(QLatin1String("Version"), dbversion); -- cgit v0.12 From 5b3e751f4c19ec05c72f212ff0ce672d982c490d Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Tue, 20 Oct 2009 15:33:32 +1000 Subject: doc now in globalobject.qdoc, not README QT-2335 --- examples/declarative/sql/README | 7 - examples/declarative/sql/hello.qml | 7 +- tools/qdoc3/qmlcodemarker.cpp | 1175 ++++++++++++++++++++++++++++++++++++ tools/qdoc3/qmlcodemarker.h | 96 +++ 4 files changed, 1277 insertions(+), 8 deletions(-) delete mode 100644 examples/declarative/sql/README create mode 100644 tools/qdoc3/qmlcodemarker.cpp create mode 100644 tools/qdoc3/qmlcodemarker.h diff --git a/examples/declarative/sql/README b/examples/declarative/sql/README deleted file mode 100644 index a7baab2..0000000 --- a/examples/declarative/sql/README +++ /dev/null @@ -1,7 +0,0 @@ -Simple demonstration of HTML5-compatible SQL database interface. -Adds another "hello, world" every time you run it. -Database is stored in: - - %APPDATA%/Nokia/Qt/QML/Databases/ (Windows) - - ~/.local/share/Nokia/Qt/QML/Databases/ (Unix) - - ~/Library/Application Support/Nokia/Qt/QML/Databases/ (Mac OS X) -No quota management. diff --git a/examples/declarative/sql/hello.qml b/examples/declarative/sql/hello.qml index 20ea611..dc3ca35 100644 --- a/examples/declarative/sql/hello.qml +++ b/examples/declarative/sql/hello.qml @@ -3,12 +3,17 @@ import Qt 4.6 Text { Script { function findGreetings() { - var db = openDatabase("QmlExampleDB", "", "The Example QML SQL!", 1000000); + var db = openDatabase("QmlExampleDB", "1.0", "The Example QML SQL!", 1000000); db.transaction( function(tx) { + // Create the database if it doesn't already exist tx.executeSql('CREATE TABLE IF NOT EXISTS Greeting(salutation TEXT, salutee TEXT)', []); + + // Add (another) greeting row tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ]); + + // Show all added greetings tx.executeSql('SELECT * FROM Greeting', [], function(tx, rs) { var r = "" diff --git a/tools/qdoc3/qmlcodemarker.cpp b/tools/qdoc3/qmlcodemarker.cpp new file mode 100644 index 0000000..1062f9c --- /dev/null +++ b/tools/qdoc3/qmlcodemarker.cpp @@ -0,0 +1,1175 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + cppcodemarker.cpp +*/ + +#include +#include "atom.h" +#include "cppcodemarker.h" +#include "node.h" +#include "text.h" +#include "tree.h" + +QT_BEGIN_NAMESPACE + +static int insertTagAround(QString &result, int pos, int len, const QString &tagName, + const QString &attributes = QString()) +{ + QString s; + //s.reserve(result.size() + tagName.size() * 2 + attributes.size() + 20); + s += result.midRef(0, pos); + s += QLatin1Char('<'); + s += tagName; + if (!attributes.isEmpty()) { + s += QLatin1Char(' '); + s += attributes; + } + s += QLatin1Char('>'); + s += result.midRef(pos, len); + s += QLatin1String("'); + s += result.midRef(pos + len); + int diff = s.length() - result.length(); + result = s; + return diff; +} + +/*! + The constructor does nothing. + */ +CppCodeMarker::CppCodeMarker() +{ + // nothing. +} + +/*! + The destructor does nothing. + */ +CppCodeMarker::~CppCodeMarker() +{ + // nothing. +} + +/*! + Returns true. + */ +bool CppCodeMarker::recognizeCode(const QString & /* code */) +{ + return true; +} + +/*! + Returns true if \a ext is any of a list of file extensions + for the C++ language. + */ +bool CppCodeMarker::recognizeExtension(const QString& ext) +{ + return ext == "c" || + ext == "c++" || + ext == "cc" || + ext == "cpp" || + ext == "cxx" || + ext == "ch" || + ext == "h" || + ext == "h++" || + ext == "hh" || + ext == "hpp" || + ext == "hxx"; +} + +/*! + Returns true if \a lang is either "C" or "Cpp". + */ +bool CppCodeMarker::recognizeLanguage(const QString &lang) +{ + return lang == "C" || lang == "Cpp"; +} + +/*! + Returns the \a node name, or "()" if \a node is a + Node::Function node. + */ +QString CppCodeMarker::plainName(const Node *node) +{ + QString name = node->name(); + if (node->type() == Node::Function) + name += "()"; + return name; +} + +QString CppCodeMarker::plainFullName(const Node *node, const Node *relative) +{ + if (node->name().isEmpty()) { + return "global"; + } + else { + QString fullName; + for (;;) { + fullName.prepend(plainName(node)); + if (node->parent() == relative || node->parent()->name().isEmpty()) + break; + fullName.prepend("::"); + node = node->parent(); + } + return fullName; + } +} + +QString CppCodeMarker::markedUpCode(const QString &code, + const Node *relative, + const QString &dirPath) +{ + return addMarkUp(protect(code), relative, dirPath); +} + +QString CppCodeMarker::markedUpSynopsis(const Node *node, + const Node * /* relative */, + SynopsisStyle style) +{ + const int MaxEnumValues = 6; + const FunctionNode *func; + const PropertyNode *property; + const VariableNode *variable; + const EnumNode *enume; + const TypedefNode *typedeff; + QString synopsis; + QString extra; + QString name; + + name = taggedNode(node); + if (style != Detailed) + name = linkTag(node, name); + name = "<@name>" + name + ""; + + if (style == Detailed && !node->parent()->name().isEmpty() && + node->type() != Node::Property) + name.prepend(taggedNode(node->parent()) + "::"); + + switch (node->type()) { + case Node::Namespace: + synopsis = "namespace " + name; + break; + case Node::Class: + synopsis = "class " + name; + break; + case Node::Function: + func = (const FunctionNode *) node; + if (style != SeparateList && !func->returnType().isEmpty()) + synopsis = typified(func->returnType()) + " "; + synopsis += name; + if (func->metaness() != FunctionNode::MacroWithoutParams) { + synopsis += " ("; + if (!func->parameters().isEmpty()) { + synopsis += " "; + QList::ConstIterator p = func->parameters().begin(); + while (p != func->parameters().end()) { + if (p != func->parameters().begin()) + synopsis += ", "; + synopsis += typified((*p).leftType()); + if (style != SeparateList && !(*p).name().isEmpty()) + synopsis += + " <@param>" + protect((*p).name()) + ""; + synopsis += protect((*p).rightType()); + if (style != SeparateList && !(*p).defaultValue().isEmpty()) + synopsis += " = " + protect((*p).defaultValue()); + ++p; + } + synopsis += " "; + } + synopsis += ")"; + } + if (func->isConst()) + synopsis += " const"; + + if (style == Summary || style == Accessors) { + if (func->virtualness() != FunctionNode::NonVirtual) + synopsis.prepend("virtual "); + if (func->virtualness() == FunctionNode::PureVirtual) + synopsis.append(" = 0"); + } + else if (style == SeparateList) { + if (!func->returnType().isEmpty() && func->returnType() != "void") + synopsis += " : " + typified(func->returnType()); + } + else { + QStringList bracketed; + if (func->isStatic()) { + bracketed += "static"; + } + else if (func->virtualness() != FunctionNode::NonVirtual) { + if (func->virtualness() == FunctionNode::PureVirtual) + bracketed += "pure"; + bracketed += "virtual"; + } + + if (func->access() == Node::Protected) { + bracketed += "protected"; + } + else if (func->access() == Node::Private) { + bracketed += "private"; + } + + if (func->metaness() == FunctionNode::Signal) { + bracketed += "signal"; + } + else if (func->metaness() == FunctionNode::Slot) { + bracketed += "slot"; + } + if (!bracketed.isEmpty()) + extra += " [" + bracketed.join(" ") + "]"; + } + break; + case Node::Enum: + enume = static_cast(node); + synopsis = "enum " + name; + if (style == Summary) { + synopsis += " { "; + + QStringList documentedItems = enume->doc().enumItemNames(); + if (documentedItems.isEmpty()) { + foreach (const EnumItem &item, enume->items()) + documentedItems << item.name(); + } + QStringList omitItems = enume->doc().omitEnumItemNames(); + foreach (const QString &item, omitItems) + documentedItems.removeAll(item); + + if (documentedItems.size() <= MaxEnumValues) { + for (int i = 0; i < documentedItems.size(); ++i) { + if (i != 0) + synopsis += ", "; + synopsis += documentedItems.at(i); + } + } + else { + for (int i = 0; i < documentedItems.size(); ++i) { + if (i < MaxEnumValues-2 || i == documentedItems.size()-1) { + if (i != 0) + synopsis += ", "; + synopsis += documentedItems.at(i); + } + else if (i == MaxEnumValues - 1) { + synopsis += ", ..."; + } + } + } + if (!documentedItems.isEmpty()) + synopsis += " "; + synopsis += "}"; + } + break; + case Node::Typedef: + typedeff = static_cast(node); + if (typedeff->associatedEnum()) { + synopsis = "flags " + name; + } + else { + synopsis = "typedef " + name; + } + break; + case Node::Property: + property = static_cast(node); + synopsis = name + " : " + typified(property->qualifiedDataType()); + break; + case Node::Variable: + variable = static_cast(node); + if (style == SeparateList) { + synopsis = name + " : " + typified(variable->dataType()); + } + else { + synopsis = typified(variable->leftType()) + " " + + name + protect(variable->rightType()); + } + break; + default: + synopsis = name; + } + + if (style == Summary) { + if (node->status() == Node::Preliminary) { + extra += " (preliminary)"; + } + else if (node->status() == Node::Deprecated) { + extra += " (deprecated)"; + } + else if (node->status() == Node::Obsolete) { + extra += " (obsolete)"; + } + } + + if (!extra.isEmpty()) { + extra.prepend("<@extra>"); + extra.append(""); + } + return synopsis + extra; +} + +#ifdef QDOC_QML +/*! + */ +QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) +{ + QString name = taggedQmlNode(node); + if (summary) { + name = linkTag(node,name); + } + name = "<@name>" + name + ""; + QString synopsis = name; + if (node->type() == Node::QmlProperty) { + const QmlPropertyNode* pn = static_cast(node); + synopsis += " : " + typified(pn->dataType()); + } + + QString extra; + if (summary) { + if (node->status() == Node::Preliminary) { + extra += " (preliminary)"; + } + else if (node->status() == Node::Deprecated) { + extra += " (deprecated)"; + } + else if (node->status() == Node::Obsolete) { + extra += " (obsolete)"; + } + } + + if (!extra.isEmpty()) { + extra.prepend("<@extra>"); + extra.append(""); + } + return synopsis + extra; +} +#endif + +QString CppCodeMarker::markedUpName(const Node *node) +{ + QString name = linkTag(node, taggedNode(node)); + if (node->type() == Node::Function) + name += "()"; + return name; +} + +QString CppCodeMarker::markedUpFullName(const Node *node, const Node *relative) +{ + if (node->name().isEmpty()) { + return "global"; + } + else { + QString fullName; + for (;;) { + fullName.prepend(markedUpName(node)); + if (node->parent() == relative || node->parent()->name().isEmpty()) + break; + fullName.prepend("<@op>::"); + node = node->parent(); + } + return fullName; + } +} + +QString CppCodeMarker::markedUpEnumValue(const QString &enumValue, + const Node *relative) +{ + const Node *node = relative->parent(); + QString fullName; + while (node->parent()) { + fullName.prepend(markedUpName(node)); + if (node->parent() == relative || node->parent()->name().isEmpty()) + break; + fullName.prepend("<@op>::"); + node = node->parent(); + } + if (!fullName.isEmpty()) + fullName.append("<@op>::"); + fullName.append(enumValue); + return fullName; +} + +QString CppCodeMarker::markedUpIncludes(const QStringList& includes) +{ + QString code; + + QStringList::ConstIterator inc = includes.begin(); + while (inc != includes.end()) { + code += "#include <<@headerfile>" + *inc + ">\n"; + ++inc; + } + return addMarkUp(code, 0, ""); +} + +QString CppCodeMarker::functionBeginRegExp(const QString& funcName) +{ + return "^" + QRegExp::escape(funcName) + "$"; + +} + +QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */) +{ + return "^\\}$"; +} + +#if 0 + FastSection privateReimpFuncs(classe, + "Private Reimplemented Functions", + "private reimplemented function", + "private reimplemented functions"); + FastSection protectedReimpFuncs(classe, + "Protected Reimplemented Functions", + "protected reimplemented function", + "protected reimplemented functions"); + FastSection publicReimpFuncs(classe, + "Public Reimplemented Functions", + "public reimplemented function", + "public reimplemented functions"); +#endif + +QList
CppCodeMarker::sections(const InnerNode *inner, + SynopsisStyle style, + Status status) +{ + QList
sections; + + if (inner->type() == Node::Class) { + const ClassNode *classe = static_cast(inner); + + if (style == Summary) { + FastSection privateFunctions(classe, + "Private Functions", + "private function", + "private functions"); + FastSection privateSlots(classe, "Private Slots", "private slot", "private slots"); + FastSection privateTypes(classe, "Private Types", "private type", "private types"); + FastSection protectedFunctions(classe, + "Protected Functions", + "protected function", + "protected functions"); + FastSection protectedSlots(classe, + "Protected Slots", + "protected slot", + "protected slots"); + FastSection protectedTypes(classe, + "Protected Types", + "protected type", + "protected types"); + FastSection protectedVariables(classe, + "Protected Variables", + "protected type", + "protected variables"); + FastSection publicFunctions(classe, + "Public Functions", + "public function", + "public functions"); + FastSection publicSignals(classe, "Signals", "signal", "signals"); + FastSection publicSlots(classe, "Public Slots", "public slot", "public slots"); + FastSection publicTypes(classe, "Public Types", "public type", "public types"); + FastSection publicVariables(classe, + "Public Variables", + "public type", + "public variables"); + FastSection properties(classe, "Properties", "property", "properties"); + FastSection relatedNonMembers(classe, + "Related Non-Members", + "related non-member", + "related non-members"); + FastSection staticPrivateMembers(classe, + "Static Private Members", + "static private member", + "static private members"); + FastSection staticProtectedMembers(classe, + "Static Protected Members", + "static protected member", + "static protected members"); + FastSection staticPublicMembers(classe, + "Static Public Members", + "static public member", + "static public members"); + FastSection macros(inner, "Macros", "macro", "macros"); + + NodeList::ConstIterator r = classe->relatedNodes().begin(); + while (r != classe->relatedNodes().end()) { + if ((*r)->type() == Node::Function) { + FunctionNode *func = static_cast(*r); + if (func->isMacro()) + insert(macros, *r, style, status); + else + insert(relatedNonMembers, *r, style, status); + } + else { + insert(relatedNonMembers, *r, style, status); + } + ++r; + } + + QStack stack; + stack.push(classe); + + while (!stack.isEmpty()) { + const ClassNode *ancestorClass = stack.pop(); + + NodeList::ConstIterator c = ancestorClass->childNodes().begin(); + while (c != ancestorClass->childNodes().end()) { + bool isSlot = false; + bool isSignal = false; + bool isStatic = false; + if ((*c)->type() == Node::Function) { + const FunctionNode *func = (const FunctionNode *) *c; + isSlot = (func->metaness() == FunctionNode::Slot); + isSignal = (func->metaness() == FunctionNode::Signal); + isStatic = func->isStatic(); + } + else if ((*c)->type() == Node::Variable) { + const VariableNode *var = static_cast(*c); + isStatic = var->isStatic(); + } + + switch ((*c)->access()) { + case Node::Public: + if (isSlot) { + insert(publicSlots, *c, style, status); + } + else if (isSignal) { + insert(publicSignals, *c, style, status); + } + else if (isStatic) { + if ((*c)->type() != Node::Variable + || !(*c)->doc().isEmpty()) + insert(staticPublicMembers,*c,style,status); + } + else if ((*c)->type() == Node::Property) { + insert(properties, *c, style, status); + } + else if ((*c)->type() == Node::Variable) { + if (!(*c)->doc().isEmpty()) + insert(publicVariables, *c, style, status); + } + else if ((*c)->type() == Node::Function) { + if (!insertReimpFunc(publicFunctions,*c,status)) + insert(publicFunctions, *c, style, status); + } + else { + insert(publicTypes, *c, style, status); + } + break; + case Node::Protected: + if (isSlot) { + insert(protectedSlots, *c, style, status); + } + else if (isStatic) { + if ((*c)->type() != Node::Variable + || !(*c)->doc().isEmpty()) + insert(staticProtectedMembers,*c,style,status); + } + else if ((*c)->type() == Node::Variable) { + if (!(*c)->doc().isEmpty()) + insert(protectedVariables,*c,style,status); + } + else if ((*c)->type() == Node::Function) { + if (!insertReimpFunc(protectedFunctions,*c,status)) + insert(protectedFunctions, *c, style, status); + } + else { + insert(protectedTypes, *c, style, status); + } + break; + case Node::Private: + if (isSlot) { + insert(privateSlots, *c, style, status); + } + else if (isStatic) { + if ((*c)->type() != Node::Variable + || !(*c)->doc().isEmpty()) + insert(staticPrivateMembers,*c,style,status); + } + else if ((*c)->type() == Node::Function) { + if (!insertReimpFunc(privateFunctions,*c,status)) + insert(privateFunctions, *c, style, status); + } + else { + insert(privateTypes,*c,style,status); + } + } + ++c; + } + + QList::ConstIterator r = + ancestorClass->baseClasses().begin(); + while (r != ancestorClass->baseClasses().end()) { + stack.prepend((*r).node); + ++r; + } + } + + append(sections, publicTypes); + append(sections, properties); + append(sections, publicFunctions); + append(sections, publicSlots); + append(sections, publicSignals); + append(sections, publicVariables); + append(sections, staticPublicMembers); + append(sections, protectedTypes); + append(sections, protectedFunctions); + append(sections, protectedSlots); + append(sections, protectedVariables); + append(sections, staticProtectedMembers); + append(sections, privateTypes); + append(sections, privateFunctions); + append(sections, privateSlots); + append(sections, staticPrivateMembers); + append(sections, relatedNonMembers); + append(sections, macros); + } + else if (style == Detailed) { + FastSection memberFunctions(classe,"Member Function Documentation"); + FastSection memberTypes(classe,"Member Type Documentation"); + FastSection memberVariables(classe,"Member Variable Documentation"); + FastSection properties(classe,"Property Documentation"); + FastSection relatedNonMembers(classe,"Related Non-Members"); + FastSection macros(classe,"Macro Documentation"); + + NodeList::ConstIterator r = classe->relatedNodes().begin(); + while (r != classe->relatedNodes().end()) { + if ((*r)->type() == Node::Function) { + FunctionNode *func = static_cast(*r); + if (func->isMacro()) + insert(macros, *r, style, status); + else + insert(relatedNonMembers, *r, style, status); + } + else { + insert(relatedNonMembers, *r, style, status); + } + ++r; + } + + NodeList::ConstIterator c = classe->childNodes().begin(); + while (c != classe->childNodes().end()) { + if ((*c)->type() == Node::Enum || + (*c)->type() == Node::Typedef) { + insert(memberTypes, *c, style, status); + } + else if ((*c)->type() == Node::Property) { + insert(properties, *c, style, status); + } + else if ((*c)->type() == Node::Variable) { + if (!(*c)->doc().isEmpty()) + insert(memberVariables, *c, style, status); + } + else if ((*c)->type() == Node::Function) { + FunctionNode *function = static_cast(*c); + if (!function->associatedProperty()) + insert(memberFunctions, function, style, status); + } + ++c; + } + + append(sections, memberTypes); + append(sections, properties); + append(sections, memberFunctions); + append(sections, memberVariables); + append(sections, relatedNonMembers); + append(sections, macros); + } + else { + FastSection all(classe); + + QStack stack; + stack.push(classe); + + while (!stack.isEmpty()) { + const ClassNode *ancestorClass = stack.pop(); + + NodeList::ConstIterator c = ancestorClass->childNodes().begin(); + while (c != ancestorClass->childNodes().end()) { + if ((*c)->access() != Node::Private && + (*c)->type() != Node::Property) + insert(all, *c, style, status); + ++c; + } + + QList::ConstIterator r = + ancestorClass->baseClasses().begin(); + while (r != ancestorClass->baseClasses().end()) { + stack.prepend((*r).node); + ++r; + } + } + append(sections, all); + } + } + else { + if (style == Summary || style == Detailed) { + FastSection namespaces(inner, + "Namespaces", + "namespace", + "namespaces"); + FastSection classes(inner, + "Classes", + "class", + "classes"); + FastSection types(inner, + style == Summary ? + "Types" : "Type Documentation", + "type", + "types"); + FastSection functions(inner, + style == Summary ? + "Functions" : "Function Documentation", + "function", + "functions"); + FastSection macros(inner, + style == Summary ? + "Macros" : "Macro Documentation", + "macro", + "macros"); + + NodeList nodeList = inner->childNodes(); + nodeList += inner->relatedNodes(); + + NodeList::ConstIterator n = nodeList.begin(); + while (n != nodeList.end()) { + switch ((*n)->type()) { + case Node::Namespace: + insert(namespaces, *n, style, status); + break; + case Node::Class: + insert(classes, *n, style, status); + break; + case Node::Enum: + case Node::Typedef: + insert(types, *n, style, status); + break; + case Node::Function: + { + FunctionNode *func = static_cast(*n); + if (func->isMacro()) + insert(macros, *n, style, status); + else + insert(functions, *n, style, status); + } + break; + default: + ; + } + ++n; + } + append(sections, namespaces); + append(sections, classes); + append(sections, types); + append(sections, functions); + append(sections, macros); + } + } + + return sections; +} + +const Node *CppCodeMarker::resolveTarget(const QString &target, + const Tree *tree, + const Node *relative) +{ + if (target.endsWith("()")) { + const FunctionNode *func; + QString funcName = target; + funcName.chop(2); + + QStringList path = funcName.split("::"); + if ((func = tree->findFunctionNode(path, + relative, + Tree::SearchBaseClasses)) + && func->metaness() != FunctionNode::MacroWithoutParams) + return func; + } + else if (target.contains("#")) { + // ### this doesn't belong here; get rid of TargetNode hack + int hashAt = target.indexOf("#"); + QString link = target.left(hashAt); + QString ref = target.mid(hashAt + 1); + const Node *node; + if (link.isEmpty()) { + node = relative; + } + else { + QStringList path(link); + node = tree->findNode(path, tree->root(), Tree::SearchBaseClasses); + } + if (node && node->isInnerNode()) { + const Atom *atom = node->doc().body().firstAtom(); + while (atom) { + if (atom->type() == Atom::Target && atom->string() == ref) { + Node *parentNode = const_cast(node); + return new TargetNode(static_cast(parentNode), + ref); + } + atom = atom->next(); + } + } + } + else { + QStringList path = target.split("::"); + const Node *node; + if ((node = tree->findNode(path, + relative, + Tree::SearchBaseClasses | + Tree::SearchEnumValues | + Tree::NonFunction))) + return node; + } + return 0; +} + +QString CppCodeMarker::addMarkUp(const QString& protectedCode, + const Node * /* relative */, + const QString& /* dirPath */) +{ + static QRegExp globalInclude("#include +<([^<>&]+)>"); + static QRegExp yHasTypeX("(?:^|\n *)([a-zA-Z_][a-zA-Z_0-9]*)" + "(?:<[^;{}]+>)?(?: *(?:\\*|&) *| +)" + "([a-zA-Z_][a-zA-Z_0-9]*)? *[,;()=]"); + static QRegExp xNewY("([a-zA-Z_][a-zA-Z_0-9]*) *= *new +([a-zA-Z_0-9]+)"); + static QRegExp xDotY("\\b([a-zA-Z_][a-zA-Z_0-9]*) *(?:\\.|->|,[ \n]*S(?:IGNAL|LOT)\\() *" + "([a-zA-Z_][a-zA-Z_0-9]*)(?= *\\()"); + static QRegExp xIsStaticZOfY("[\n:;{(=] *(([a-zA-Z_0-9]+)::([a-zA-Z_0-9]+))(?= *\\()"); + static QRegExp classX("[:,][ \n]*(?:p(?:ublic|r(?:otected|ivate))[ \n]+)?" + "([a-zA-Z_][a-zA-Z_0-9]*)"); + static QRegExp globalX("[\n{()=] *([a-zA-Z_][a-zA-Z_0-9]*)[ \n]*\\("); + static QRegExp multiLineComment("/(?:( )?\\*(?:[^*]+|\\*(?! /))*\\*\\1/)"); + multiLineComment.setMinimal(true); + static QRegExp singleLineComment("//(?!!)[^!\n]*"); + static QRegExp preprocessor("(?:^|\n)(#[ \t]*(?:include|if|elif|endif|error|pragma|define" + "|warning)(?:(?:\\\\\n|\\n#)[^\n]*)*)"); + static QRegExp literals(""(?:[^\\\\&]|\\\\[^\n]|&(?!quot;))*"" + "|'(?:[^\\\\]|\\\\(?:[^x0-9']|x[0-9a-f]{1,4}|[0-9]{1,3}))'"); + + QString result = protectedCode; + int pos; + + if (!hurryUp()) { + /* + Mark global includes. For example: + + #include <<@headerfile>QString + */ + pos = 0; + while ((pos = result.indexOf(globalInclude, pos)) != -1) + pos += globalInclude.matchedLength() + + insertTagAround(result, + globalInclude.pos(1), + globalInclude.cap(1).length(), + "@headerfile"); + + /* + Look for variable definitions and similar constructs, mark + the data type, and remember the type of the variable. + */ + QMap > typesForVariable; + pos = 0; + while ((pos = yHasTypeX.indexIn(result, pos)) != -1) { + QString x = yHasTypeX.cap(1); + QString y = yHasTypeX.cap(2); + + if (!y.isEmpty()) + typesForVariable[y].insert(x); + + /* + Without the minus one at the end, 'void member(Class + var)' would give 'member' as a variable of type 'void', + but would ignore 'Class var'. (### Is that true?) + */ + pos += yHasTypeX.matchedLength() + + insertTagAround(result, + yHasTypeX.pos(1), + x.length(), + "@type") - 1; + } + + /* + Do syntax highlighting of preprocessor directives. + */ + pos = 0; + while ((pos = preprocessor.indexIn(result, pos)) != -1) + pos += preprocessor.matchedLength() + + insertTagAround(result, + preprocessor.pos(1), + preprocessor.cap(1).length(), + "@preprocessor"); + + /* + Deal with string and character literals. + */ + pos = 0; + while ((pos = literals.indexIn(result, pos)) != -1) + pos += literals.matchedLength() + + insertTagAround(result, + pos, + literals.matchedLength(), + result.at(pos) == + QLatin1Char(' ') ? "@string" : "@char"); + + /* + Look for 'var = new Class'. + */ + pos = 0; + while ((pos = xNewY.indexIn(result, pos)) != -1) { + QString x = xNewY.cap(1); + QString y = xNewY.cap(2); + typesForVariable[x].insert(y); + + pos += xNewY.matchedLength() + insertTagAround(result, + xNewY.pos(2), + y.length(), + "@type"); + } + + /* + Insert some stuff that cannot harm. + */ + typesForVariable["qApp"].insert("QApplication"); + + /* + Add link to ': Class'. + */ + pos = 0; + while ((pos = classX.indexIn(result, pos)) != -1) + pos += classX.matchedLength() + + insertTagAround(result, + classX.pos(1), + classX.cap(1).length(), + "@type") - 1; + + /* + Find use of any of + + var.method() + var->method() + var, SIGNAL(method()) + var, SLOT(method()). + */ + pos = 0; + while ((pos = xDotY.indexIn(result, pos)) != -1) { + QString x = xDotY.cap(1); + QString y = xDotY.cap(2); + + QSet types = typesForVariable.value(x); + pos += xDotY.matchedLength() + + insertTagAround(result, + xDotY.pos(2), + xDotY.cap(2).length(), + "@func", + (types.count() == 1) ? "target=\"" + + protect(*types.begin() + "::" + y) + + "()\"" : QString()); + } + + /* + Add link to 'Class::method()'. + */ + pos = 0; + while ((pos = xIsStaticZOfY.indexIn(result, pos)) != -1) { + QString x = xIsStaticZOfY.cap(1); + QString z = xIsStaticZOfY.cap(3); + + pos += insertTagAround(result, + xIsStaticZOfY.pos(3), + z.length(), + "@func", + "target=\"" + protect(x) + "()\""); + pos += insertTagAround(result, + xIsStaticZOfY.pos(2), + xIsStaticZOfY.cap(2).length(), + "@type"); + pos += xIsStaticZOfY.matchedLength() - 1; + } + + /* + Add link to 'globalFunction()'. + */ + pos = 0; + while ((pos = globalX.indexIn(result, pos)) != -1) { + QString x = globalX.cap(1); + if (x != "QT_FORWARD_DECLARE_CLASS") { + pos += globalX.matchedLength() + + insertTagAround(result, + globalX.pos(1), + x.length(), + "@func", + "target=\"" + protect(x) + "()\"") - 1; + } + else + pos += globalX.matchedLength(); + } + } + + /* + Do syntax highlighting of comments. Also alter the code in a + minor way, so that we can include comments in documentation + comments. + */ + pos = 0; + while (pos != -1) { + int mlpos; + int slpos; + int len; + slpos = singleLineComment.indexIn(result, pos); + mlpos = multiLineComment.indexIn(result, pos); + + if (slpos == -1 && mlpos == -1) + break; + + if (slpos == -1) { + pos = mlpos; + len = multiLineComment.matchedLength(); + } + else if (mlpos == -1) { + pos = slpos; + len = singleLineComment.matchedLength(); + } + else { + if (slpos < mlpos) { + pos = slpos; + len = singleLineComment.matchedLength(); + } + else { + pos = mlpos; + len = multiLineComment.matchedLength(); + } + } + + if (result.at(pos + 1) == QLatin1Char(' ')) { + result.remove(pos + len - 2, 1); + result.remove(pos + 1, 1); + len -= 2; + + forever { + int endcodePos = result.indexOf("\\ endcode", pos); + if (endcodePos == -1 || endcodePos >= pos + len) + break; + result.remove(endcodePos + 1, 1); + len -= 1; + } + } + pos += len + insertTagAround(result, pos, len, "@comment"); + } + + return result; +} + +#ifdef QDOC_QML +/*! + This function is for documenting QML properties. It returns + the list of documentation sections for the children of the + \a qmlClassNode. + + Currently, it only handles QML property groups. + */ +QList
CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style) +{ + QList
sections; + if (qmlClassNode) { + if (style == Summary) { + FastSection qmlproperties(qmlClassNode, + "Properties", + "property", + "properties"); + FastSection qmlsignals(qmlClassNode, + "Signals", + "signal", + "signals"); + FastSection qmlmethods(qmlClassNode, + "Methods", + "method", + "methods"); + + NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); + while (c != qmlClassNode->childNodes().end()) { + if ((*c)->subType() == Node::QmlPropertyGroup) { + const QmlPropGroupNode* qpgn = static_cast(*c); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + insert(qmlproperties,*p,style,Okay); + } + ++p; + } + } + else if ((*c)->type() == Node::QmlSignal) { + insert(qmlsignals,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlMethod) { + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + append(sections,qmlproperties); + append(sections,qmlsignals); + append(sections,qmlmethods); + } + else if (style == Detailed) { + FastSection qmlproperties(qmlClassNode, "Property Documentation"); + FastSection qmlsignals(qmlClassNode,"Signal Documentation"); + FastSection qmlmethods(qmlClassNode,"Method Documentation"); + NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); + while (c != qmlClassNode->childNodes().end()) { + if ((*c)->subType() == Node::QmlPropertyGroup) { + insert(qmlproperties,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlSignal) { + insert(qmlsignals,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlMethod) { + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + append(sections,qmlproperties); + append(sections,qmlsignals); + append(sections,qmlmethods); + } + } + + return sections; +} +#endif + +QT_END_NAMESPACE diff --git a/tools/qdoc3/qmlcodemarker.h b/tools/qdoc3/qmlcodemarker.h new file mode 100644 index 0000000..8c83c04 --- /dev/null +++ b/tools/qdoc3/qmlcodemarker.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + cppcodemarker.h +*/ + +#ifndef CPPCODEMARKER_H +#define CPPCODEMARKER_H + +#include "codemarker.h" + +QT_BEGIN_NAMESPACE + +class CppCodeMarker : public CodeMarker +{ + public: + CppCodeMarker(); + ~CppCodeMarker(); + + bool recognizeCode(const QString& code); + bool recognizeExtension(const QString& ext); + bool recognizeLanguage(const QString& lang); + QString plainName(const Node *node); + QString plainFullName(const Node *node, const Node *relative); + QString markedUpCode(const QString& code, + const Node *relative, + const QString& dirPath); + QString markedUpSynopsis(const Node *node, + const Node *relative, + SynopsisStyle style); +#ifdef QDOC_QML + QString markedUpQmlItem(const Node *node, bool summary); +#endif + QString markedUpName(const Node *node); + QString markedUpFullName(const Node *node, const Node *relative); + QString markedUpEnumValue(const QString &enumValue, const Node *relative); + QString markedUpIncludes(const QStringList& includes); + QString functionBeginRegExp(const QString& funcName); + QString functionEndRegExp(const QString& funcName); + QList
sections(const InnerNode *innerNode, + SynopsisStyle style, + Status status); + QList
qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style); + const Node *resolveTarget(const QString& target, + const Tree *tree, + const Node *relative); + +private: + QString addMarkUp(const QString& protectedCode, + const Node *relative, + const QString& dirPath); +}; + +QT_END_NAMESPACE + +#endif -- cgit v0.12 From 110c58a20f3158143d83ebea4f2ece4f7925f913 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 21 Oct 2009 10:20:57 +1000 Subject: Give more info about whether a value is null and its value type. --- src/declarative/debugger/qmldebug.cpp | 15 ++++++-- src/declarative/debugger/qmldebug.h | 2 ++ src/declarative/qml/qmlenginedebug.cpp | 29 ++++++++------- src/declarative/qml/qmlenginedebug_p.h | 1 + tools/qmldebugger/expressionquerywidget.cpp | 55 +++++++++++++++++++++++------ tools/qmldebugger/expressionquerywidget.h | 4 +++ tools/qmldebugger/objectpropertiesview.cpp | 19 +++++----- 7 files changed, 89 insertions(+), 36 deletions(-) diff --git a/src/declarative/debugger/qmldebug.cpp b/src/declarative/debugger/qmldebug.cpp index 75418e8..2537ec0 100644 --- a/src/declarative/debugger/qmldebug.cpp +++ b/src/declarative/debugger/qmldebug.cpp @@ -117,6 +117,7 @@ void QmlEngineDebugPrivate::decode(QDataStream &ds, QmlDebugObjectReference &o, prop.m_name = data.name; prop.m_binding = data.binding; prop.m_hasNotifySignal = data.hasNotifySignal; + prop.m_valueTypeName = data.valueTypeName; if (data.type == QmlEngineDebugServer::QmlObjectProperty::Basic) prop.m_value = data.value; else if (data.type == QmlEngineDebugServer::QmlObjectProperty::Object) { @@ -124,7 +125,6 @@ void QmlEngineDebugPrivate::decode(QDataStream &ds, QmlDebugObjectReference &o, obj.m_debugId = prop.m_value.toInt(); prop.m_value = qVariantFromValue(obj); } - o.m_properties << prop; } @@ -812,13 +812,17 @@ QmlDebugPropertyReference::QmlDebugPropertyReference() } QmlDebugPropertyReference::QmlDebugPropertyReference(const QmlDebugPropertyReference &o) -: m_objectDebugId(o.m_objectDebugId), m_name(o.m_name), m_value(o.m_value), m_binding(o.m_binding), m_hasNotifySignal(o.m_hasNotifySignal) +: m_objectDebugId(o.m_objectDebugId), m_name(o.m_name), m_value(o.m_value), + m_valueTypeName(o.m_valueTypeName), m_binding(o.m_binding), + m_hasNotifySignal(o.m_hasNotifySignal) { } QmlDebugPropertyReference &QmlDebugPropertyReference::operator=(const QmlDebugPropertyReference &o) { - m_objectDebugId = o.m_objectDebugId; m_name = o.m_name; m_value = o.m_value; m_binding = o.m_binding; m_hasNotifySignal = o.m_hasNotifySignal; + m_objectDebugId = o.m_objectDebugId; m_name = o.m_name; m_value = o.m_value; + m_valueTypeName = o.m_valueTypeName; m_binding = o.m_binding; + m_hasNotifySignal = o.m_hasNotifySignal; return *this; } @@ -832,6 +836,11 @@ QString QmlDebugPropertyReference::name() const return m_name; } +QString QmlDebugPropertyReference::valueTypeName() const +{ + return m_valueTypeName; +} + QVariant QmlDebugPropertyReference::value() const { return m_value; diff --git a/src/declarative/debugger/qmldebug.h b/src/declarative/debugger/qmldebug.h index 153a10f..bd076ff 100644 --- a/src/declarative/debugger/qmldebug.h +++ b/src/declarative/debugger/qmldebug.h @@ -232,6 +232,7 @@ public: int objectDebugId() const; QString name() const; QVariant value() const; + QString valueTypeName() const; QString binding() const; bool hasNotifySignal() const; @@ -240,6 +241,7 @@ private: int m_objectDebugId; QString m_name; QVariant m_value; + QString m_valueTypeName; QString m_binding; bool m_hasNotifySignal; }; diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index bbe6f77..7178e6c 100644 --- a/src/declarative/qml/qmlenginedebug.cpp +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -80,7 +80,8 @@ QDataStream &operator>>(QDataStream &ds, QDataStream &operator<<(QDataStream &ds, const QmlEngineDebugServer::QmlObjectProperty &data) { - ds << (int)data.type << data.name << data.value << data.binding << data.hasNotifySignal; + ds << (int)data.type << data.name << data.value << data.valueTypeName + << data.binding << data.hasNotifySignal; return ds; } @@ -88,7 +89,8 @@ QDataStream &operator>>(QDataStream &ds, QmlEngineDebugServer::QmlObjectProperty &data) { int type; - ds >> type >> data.name >> data.value >> data.binding >> data.hasNotifySignal; + ds >> type >> data.name >> data.value >> data.valueTypeName + >> data.binding >> data.hasNotifySignal; data.type = (QmlEngineDebugServer::QmlObjectProperty::Type)type; return ds; } @@ -101,6 +103,7 @@ QmlEngineDebugServer::propertyData(QObject *obj, int propIdx) QMetaProperty prop = obj->metaObject()->property(propIdx); rv.type = QmlObjectProperty::Unknown; + rv.valueTypeName = QString::fromUtf8(prop.typeName()); rv.name = prop.name(); rv.hasNotifySignal = prop.hasNotifySignal(); QmlAbstractBinding *binding = QmlMetaProperty(obj, rv.name).binding(); @@ -116,6 +119,7 @@ QmlEngineDebugServer::propertyData(QObject *obj, int propIdx) QmlMetaType::isQmlList(prop.userType())) { rv.type = QmlObjectProperty::List; } + return rv; } @@ -149,7 +153,7 @@ void QmlEngineDebugServer::buildObjectList(QDataStream &message, int ctxtId = QmlDebugService::idForObject(ctxt); message << ctxtName << ctxtId; - + int count = 0; for (QSet::ConstIterator iter = p->childContexts.begin(); @@ -186,6 +190,12 @@ void QmlEngineDebugServer::buildObjectList(QDataStream &message, QVariant QmlEngineDebugServer::serializableVariant(const QVariant &value) { + if (value.type() < QVariant::UserType) + return value; + + if (!value.toString().isEmpty()) + return value.toString(); + QVariant v; if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { QObject *o = QmlMetaType::toQObject(value); @@ -195,19 +205,12 @@ QVariant QmlEngineDebugServer::serializableVariant(const QVariant &value) objectName = QLatin1String(""); v = QString::fromUtf8(o->metaObject()->className()) + QLatin1String(": ") + objectName; - } else { - v = QString::fromUtf8(value.typeName()); - } - if (v.isNull()) { - QString s = value.toString(); - if (s.isEmpty()) - s = QLatin1String(""); - v = s; } - } else { - v = value; } + if (v.isNull()) + v = QString::fromUtf8(value.typeName()); + return v; } diff --git a/src/declarative/qml/qmlenginedebug_p.h b/src/declarative/qml/qmlenginedebug_p.h index 9ad198a..075a711 100644 --- a/src/declarative/qml/qmlenginedebug_p.h +++ b/src/declarative/qml/qmlenginedebug_p.h @@ -85,6 +85,7 @@ public: Type type; QString name; QVariant value; + QString valueTypeName; QString binding; bool hasNotifySignal; }; diff --git a/tools/qmldebugger/expressionquerywidget.cpp b/tools/qmldebugger/expressionquerywidget.cpp index 90ab8ee..b29b465 100644 --- a/tools/qmldebugger/expressionquerywidget.cpp +++ b/tools/qmldebugger/expressionquerywidget.cpp @@ -16,7 +16,8 @@ ExpressionQueryWidget::ExpressionQueryWidget(QmlEngineDebug *client, QWidget *pa m_query(0), m_groupBox(0), m_textEdit(new QTextEdit), - m_lineEdit(0) + m_lineEdit(0), + m_button(0) { m_prompt = QLatin1String(">> "); @@ -31,16 +32,19 @@ ExpressionQueryWidget::ExpressionQueryWidget(QmlEngineDebug *client, QWidget *pa if (m_style == Compact) { QHBoxLayout *hbox = new QHBoxLayout; - QPushButton *button = new QPushButton(tr("Execute")); - connect(button, SIGNAL(clicked()), SLOT(executeExpression())); + m_button = new QPushButton(tr("Execute")); + m_button->setEnabled(false); + connect(m_button, SIGNAL(clicked()), SLOT(executeExpression())); m_lineEdit = new QLineEdit; connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(executeExpression())); + connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(lineEditTextChanged(QString))); hbox->addWidget(new QLabel(tr("Expression:"))); hbox->addWidget(m_lineEdit); - hbox->addWidget(button); + hbox->addWidget(m_button); vbox->addLayout(hbox); m_textEdit->setReadOnly(true); + m_lineEdit->installEventFilter(this); } else { m_textEdit->installEventFilter(this); } @@ -55,7 +59,7 @@ void ExpressionQueryWidget::updateTitle() + m_currObject.className() + QLatin1String(": ") + (m_currObject.name().isEmpty() ? QLatin1String("") : m_currObject.name()) + QLatin1String(">"); - m_groupBox->setTitle(tr("Expression queries (current context: %1)" + m_groupBox->setTitle(tr("Expression queries (using context for %1)" , "Selected object").arg(desc)); } } @@ -101,18 +105,20 @@ void ExpressionQueryWidget::executeExpression() { if (m_style == Compact) m_expr = m_lineEdit->text().trimmed(); + else + m_expr = m_expr.trimmed(); - if (!m_expr.trimmed().isEmpty() && m_currObject.debugId() != -1) { - checkCurrentContext(); + if (!m_expr.isEmpty() && m_currObject.debugId() != -1) { if (m_query) delete m_query; - m_query = m_client->queryExpressionResult(m_currObject.debugId(), m_expr.trimmed(), this); + m_query = m_client->queryExpressionResult(m_currObject.debugId(), m_expr, this); if (!m_query->isWaiting()) showResult(); else QObject::connect(m_query, SIGNAL(stateChanged(State)), this, SLOT(showResult())); + m_lastExpr = m_expr; if (m_lineEdit) m_lineEdit->clear(); } @@ -122,9 +128,11 @@ void ExpressionQueryWidget::showResult() { if (m_query) { m_textEdit->moveCursor(QTextCursor::End); - QString result = m_query->result().toString(); - if (result.isEmpty()) + QString result; + if (m_query->result().isNull()) result = QLatin1String(""); + else + result = m_query->result().toString(); if (m_style == Compact) { m_textEdit->setTextColor(Qt::black); @@ -140,6 +148,12 @@ void ExpressionQueryWidget::showResult() } } +void ExpressionQueryWidget::lineEditTextChanged(const QString &s) +{ + if (m_button) + m_button->setEnabled(!s.isEmpty()); +} + bool ExpressionQueryWidget::eventFilter(QObject *obj, QEvent *event) { if (obj == m_textEdit) { @@ -176,6 +190,27 @@ bool ExpressionQueryWidget::eventFilter(QObject *obj, QEvent *event) default: break; } + } else if (obj == m_lineEdit) { + switch (event->type()) { + case QEvent::KeyPress: + { + QKeyEvent *keyEvent = static_cast(event); + int key = keyEvent->key(); + if (key == Qt::Key_Up && m_lineEdit->text() != m_lastExpr) { + m_expr = m_lineEdit->text(); + if (!m_lastExpr.isEmpty()) + m_lineEdit->setText(m_lastExpr); + } else if (key == Qt::Key_Down) { + m_lineEdit->setText(m_expr); + } + break; + } + case QEvent::FocusIn: + checkCurrentContext(); + break; + default: + break; + } } return QWidget::eventFilter(obj, event); } diff --git a/tools/qmldebugger/expressionquerywidget.h b/tools/qmldebugger/expressionquerywidget.h index 3ea95ac..8db8f9f 100644 --- a/tools/qmldebugger/expressionquerywidget.h +++ b/tools/qmldebugger/expressionquerywidget.h @@ -10,6 +10,7 @@ QT_BEGIN_NAMESPACE class QGroupBox; class QTextEdit; class QLineEdit; +class QPushButton; class ExpressionQueryWidget : public QWidget { @@ -31,6 +32,7 @@ public slots: private slots: void executeExpression(); void showResult(); + void lineEditTextChanged(const QString &s); private: void appendPrompt(); @@ -45,8 +47,10 @@ private: QGroupBox *m_groupBox; QTextEdit *m_textEdit; QLineEdit *m_lineEdit; + QPushButton *m_button; QString m_prompt; QString m_expr; + QString m_lastExpr; QmlDebugObjectReference m_currObject; QmlDebugObjectReference m_objectAtLastFocus; diff --git a/tools/qmldebugger/objectpropertiesview.cpp b/tools/qmldebugger/objectpropertiesview.cpp index 4a2f97d..61afe3f 100644 --- a/tools/qmldebugger/objectpropertiesview.cpp +++ b/tools/qmldebugger/objectpropertiesview.cpp @@ -22,12 +22,12 @@ public: }; PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget) -: QTreeWidgetItem(widget) + : QTreeWidgetItem(widget) { } PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent) -: QTreeWidgetItem(parent) + : QTreeWidgetItem(parent) { } @@ -108,8 +108,10 @@ void ObjectPropertiesView::setObject(const QmlDebugObjectReference &object) item->setText(0, p.name()); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - if (!p.hasNotifySignal()) + if (!p.hasNotifySignal()) { item->setForeground(0, Qt::gray); + item->setForeground(1, Qt::gray); + } if (!p.binding().isEmpty()) { PropertiesViewItem *binding = new PropertiesViewItem(item); @@ -161,14 +163,11 @@ void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant & PropertiesViewItem *item = static_cast(m_tree->topLevelItem(i)); if (item->property.name() == name) { if (value.isNull()) { - item->setText(1, QLatin1String("null")); - item->setForeground(1, Qt::gray); + item->setText(1, QLatin1String("") + + QLatin1String(" : ") + + item->property.valueTypeName()); } else { - QString s = value.toString(); - if (s.isEmpty()) - s = QString::fromUtf8(value.typeName()); - item->setText(1, s); - item->setForeground(1, QBrush()); + item->setText(1, value.toString()); } } } -- cgit v0.12 From 1de91381a125c7d31b4aed7e97d57fb78df665a2 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Wed, 21 Oct 2009 10:48:44 +1000 Subject: better easing example --- examples/declarative/easing/easing.qml | 162 +++++++++++++++++---------------- 1 file changed, 84 insertions(+), 78 deletions(-) diff --git a/examples/declarative/easing/easing.qml b/examples/declarative/easing/easing.qml index 23d7b29..100d5d2 100644 --- a/examples/declarative/easing/easing.qml +++ b/examples/declarative/easing/easing.qml @@ -2,92 +2,98 @@ import Qt 4.6 Rectangle { id: window - width: 640 - height: layout.height - color: "white" + width: 600; height: 460; color: "#232323" ListModel { id: easingTypes - ListElement { type: "easeLinear" } - ListElement { type: "easeInQuad" } - ListElement { type: "easeOutQuad" } - ListElement { type: "easeInOutQuad" } - ListElement { type: "easeOutInQuad" } - ListElement { type: "easeInCubic" } - ListElement { type: "easeOutCubic" } - ListElement { type: "easeInOutCubic" } - ListElement { type: "easeOutInCubic" } - ListElement { type: "easeInQuart" } - ListElement { type: "easeOutQuart" } - ListElement { type: "easeInOutQuart" } - ListElement { type: "easeOutInQuart" } - ListElement { type: "easeInQuint" } - ListElement { type: "easeOutQuint" } - ListElement { type: "easeInOutQuint" } - ListElement { type: "easeOutInQuint" } - ListElement { type: "easeInSine" } - ListElement { type: "easeOutSine" } - ListElement { type: "easeInOutSine" } - ListElement { type: "easeOutInSine" } - ListElement { type: "easeInExpo" } - ListElement { type: "easeOutExpo" } - ListElement { type: "easeInOutExpo" } - ListElement { type: "easeOutInExpo" } - ListElement { type: "easeInCirc" } - ListElement { type: "easeOutCirc" } - ListElement { type: "easeInOutCirc" } - ListElement { type: "easeOutInCirc" } - ListElement { type: "easeInElastic" } - ListElement { type: "easeOutElastic" } - ListElement { type: "easeInOutElastic" } - ListElement { type: "easeOutInElastic" } - ListElement { type: "easeInBack" } - ListElement { type: "easeOutBack" } - ListElement { type: "easeInOutBack" } - ListElement { type: "easeOutInBack" } - ListElement { type: "easeOutBounce" } - ListElement { type: "easeInBounce" } - ListElement { type: "easeInOutBounce" } - ListElement { type: "easeOutInBounce" } + ListElement { type: "easeLinear"; ballColor: "DarkRed" } + ListElement { type: "easeInQuad"; ballColor: "IndianRed" } + ListElement { type: "easeOutQuad"; ballColor: "Salmon" } + ListElement { type: "easeInOutQuad"; ballColor: "Tomato" } + ListElement { type: "easeOutInQuad"; ballColor: "DarkOrange" } + ListElement { type: "easeInCubic"; ballColor: "Gold" } + ListElement { type: "easeOutCubic"; ballColor: "Yellow" } + ListElement { type: "easeInOutCubic"; ballColor: "PeachPuff" } + ListElement { type: "easeOutInCubic"; ballColor: "Thistle" } + ListElement { type: "easeInQuart"; ballColor: "Orchid" } + ListElement { type: "easeOutQuart"; ballColor: "Purple" } + ListElement { type: "easeInOutQuart"; ballColor: "SlateBlue" } + ListElement { type: "easeOutInQuart"; ballColor: "Chartreuse" } + ListElement { type: "easeInQuint"; ballColor: "LimeGreen" } + ListElement { type: "easeOutQuint"; ballColor: "SeaGreen" } + ListElement { type: "easeInOutQuint"; ballColor: "DarkGreen" } + ListElement { type: "easeOutInQuint"; ballColor: "Olive" } + ListElement { type: "easeInSine"; ballColor: "DarkSeaGreen" } + ListElement { type: "easeOutSine"; ballColor: "Teal" } + ListElement { type: "easeInOutSine"; ballColor: "Turquoise" } + ListElement { type: "easeOutInSine"; ballColor: "SteelBlue" } + ListElement { type: "easeInExpo"; ballColor: "SkyBlue" } + ListElement { type: "easeOutExpo"; ballColor: "RoyalBlue" } + ListElement { type: "easeInOutExpo"; ballColor: "MediumBlue" } + ListElement { type: "easeOutInExpo"; ballColor: "MidnightBlue" } + ListElement { type: "easeInCirc"; ballColor: "CornSilk" } + ListElement { type: "easeOutCirc"; ballColor: "Bisque" } + ListElement { type: "easeInOutCirc"; ballColor: "RosyBrown" } + ListElement { type: "easeOutInCirc"; ballColor: "SandyBrown" } + ListElement { type: "easeInElastic"; ballColor: "DarkGoldenRod" } + ListElement { type: "easeOutElastic"; ballColor: "Chocolate" } + ListElement { type: "easeInOutElastic"; ballColor: "SaddleBrown" } + ListElement { type: "easeOutInElastic"; ballColor: "Brown" } + ListElement { type: "easeInBack"; ballColor: "Maroon" } + ListElement { type: "easeOutBack"; ballColor: "LavenderBlush" } + ListElement { type: "easeInOutBack"; ballColor: "MistyRose" } + ListElement { type: "easeOutInBack"; ballColor: "Gainsboro" } + ListElement { type: "easeOutBounce"; ballColor: "Silver" } + ListElement { type: "easeInBounce"; ballColor: "DimGray" } + ListElement { type: "easeInOutBounce"; ballColor: "SlateGray" } + ListElement { type: "easeOutInBounce"; ballColor: "DarkSlateGray" } } - Column { - id: layout - anchors.left: window.left - anchors.right: window.right - Repeater { - model: easingTypes - Component { - Text { - text: type - height: 18 - font.italic: true - x: SequentialAnimation { - id: anim - NumberAnimation { - from: 0 - to: window.width / 2 - easing: type - duration: 1000 - } - PauseAnimation { - duration: 300 - } - NumberAnimation { - to: 0 - from: window.width / 2 - easing: type - duration: 1000 - } + Component { + id: delegate + + Item { + height: 42; width: window.width + Text { text: type; anchors.centerIn: parent; color: "White" } + Rectangle { + id: slot1; color: "#121212"; x: 10; height: 32; width: 32 + border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter + } + Rectangle { + id: slot2; color: "#121212"; x: window.width - 42; height: 32; width: 32 + border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter + } + Rectangle { + id: rect; x: 10; color: "#454545" + border.color: "White"; border.width: 2 + height: 32; width: 32; radius: 8; anchors.verticalCenter: parent.verticalCenter + + MouseRegion { + onClicked: if (rect.state == '') rect.state = "right"; else rect.state = '' + anchors.fill: parent + } + + states : State { + name: "right" + PropertyChanges { target: rect; x: window.width - 42; color: ballColor } + } + + transitions: Transition { + ParallelAnimation { + NumberAnimation { properties: "x"; easing: type; duration: 1000 } + ColorAnimation { properties: "color"; easing: type; duration: 1000 } } - children: [ - MouseRegion { - onClicked: { anim.running=true } - anchors.fill: parent - } - ] } } } } + + Flickable { + anchors.fill: parent; viewportHeight: layout.height + Column { + id: layout + anchors.left: window.left; anchors.right: window.right + Repeater { model: easingTypes; delegate: delegate } + } + } } -- cgit v0.12 From c2aa20e6eda3654022976db2b1abbf23f9abbcfb Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 21 Oct 2009 11:37:56 +1000 Subject: Move QmlFolderListModel to the loader example. --- examples/declarative/loader/loader.pro | 3 +- examples/declarative/loader/qmlfolderlistmodel.cpp | 413 +++++++++++++++++++++ examples/declarative/loader/qmlfolderlistmodel.h | 128 +++++++ src/declarative/extra/extra.pri | 2 - src/declarative/extra/qmlfolderlistmodel.cpp | 413 --------------------- src/declarative/extra/qmlfolderlistmodel.h | 128 ------- 6 files changed, 543 insertions(+), 544 deletions(-) create mode 100644 examples/declarative/loader/qmlfolderlistmodel.cpp create mode 100644 examples/declarative/loader/qmlfolderlistmodel.h delete mode 100644 src/declarative/extra/qmlfolderlistmodel.cpp delete mode 100644 src/declarative/extra/qmlfolderlistmodel.h diff --git a/examples/declarative/loader/loader.pro b/examples/declarative/loader/loader.pro index 9b03b8f..8c93210 100644 --- a/examples/declarative/loader/loader.pro +++ b/examples/declarative/loader/loader.pro @@ -1,4 +1,5 @@ -SOURCES = main.cpp +SOURCES = main.cpp qmlfolderlistmodel.cpp +HEADERS = qmlfolderlistmodel.h RESOURCES = loader.qrc QT += script declarative network diff --git a/examples/declarative/loader/qmlfolderlistmodel.cpp b/examples/declarative/loader/qmlfolderlistmodel.cpp new file mode 100644 index 0000000..0e5c275 --- /dev/null +++ b/examples/declarative/loader/qmlfolderlistmodel.cpp @@ -0,0 +1,413 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qobject_p.h" +#include +#include +#include "qmlfolderlistmodel.h" +#include + +QT_BEGIN_NAMESPACE + +class QmlFolderListModelPrivate : public QObjectPrivate +{ +public: + QmlFolderListModelPrivate() + : sortField(QmlFolderListModel::Name), sortReversed(false), count(0) { + nameFilters << QLatin1String("*"); + } + + void updateSorting() { + QDir::SortFlags flags = 0; + switch(sortField) { + case QmlFolderListModel::Unsorted: + flags |= QDir::Unsorted; + break; + case QmlFolderListModel::Name: + flags |= QDir::Name; + break; + case QmlFolderListModel::Time: + flags |= QDir::Time; + break; + case QmlFolderListModel::Size: + flags |= QDir::Size; + break; + case QmlFolderListModel::Type: + flags |= QDir::Type; + break; + } + + if (sortReversed) + flags |= QDir::Reversed; + + model.setSorting(flags); + } + + QDirModel model; + QUrl folder; + QStringList nameFilters; + QModelIndex folderIndex; + QmlFolderListModel::SortField sortField; + bool sortReversed; + int count; +}; + +/*! + \qmlclass FolderListModel + \brief The FolderListModel provides a model of the contents of a folder in a filesystem. + + FolderListModel provides access to the local filesystem. The \e folder property + specifies the folder to list. + + Qt uses "/" as a universal directory separator in the same way that "/" is + used as a path separator in URLs. If you always use "/" as a directory + separator, Qt will translate your paths to conform to the underlying + operating system. + + The roles available are: + \list + \o fileName + \o filePath + \endlist + + Additionally a file entry can be differentiated from a folder entry + via the \l isFolder() method. +*/ + +QmlFolderListModel::QmlFolderListModel(QObject *parent) + : QListModelInterface(*(new QmlFolderListModelPrivate), parent) +{ + Q_D(QmlFolderListModel); + d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot); + connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int)) + , this, SLOT(inserted(const QModelIndex&,int,int))); + connect(&d->model, SIGNAL(rowsRemoved(const QModelIndex&,int,int)) + , this, SLOT(removed(const QModelIndex&,int,int))); + connect(&d->model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)) + , this, SLOT(dataChanged(const QModelIndex&,const QModelIndex&))); + connect(&d->model, SIGNAL(modelReset()), this, SLOT(refresh())); + connect(&d->model, SIGNAL(layoutChanged()), this, SLOT(refresh())); +} + +QmlFolderListModel::~QmlFolderListModel() +{ +} + +QHash QmlFolderListModel::data(int index, const QList &roles) const +{ + Q_UNUSED(roles); + Q_D(const QmlFolderListModel); + QHash folderData; + QModelIndex modelIndex = d->model.index(index, 0, d->folderIndex); + if (modelIndex.isValid()) { + folderData[QDirModel::FileNameRole] = d->model.data(modelIndex, QDirModel::FileNameRole); + folderData[QDirModel::FilePathRole] = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString()); + } + + return folderData; +} + +int QmlFolderListModel::count() const +{ + Q_D(const QmlFolderListModel); + return d->count; +} + +QList QmlFolderListModel::roles() const +{ + QList r; + r << QDirModel::FileNameRole; + r << QDirModel::FilePathRole; + return r; +} + +QString QmlFolderListModel::toString(int role) const +{ + switch (role) { + case QDirModel::FileNameRole: + return QLatin1String("fileName"); + case QDirModel::FilePathRole: + return QLatin1String("filePath"); + } + + return QString(); +} + +/*! + \qmlproperty string FolderListModel::folder + + The \a folder property holds the folder the model is currently providing. + + It is a URL, but must be a file: or qrc: URL (or relative to such a URL). +*/ +QUrl QmlFolderListModel::folder() const +{ + Q_D(const QmlFolderListModel); + return d->folder; +} + +void QmlFolderListModel::setFolder(const QUrl &folder) +{ + Q_D(QmlFolderListModel); + if (folder == d->folder) + return; + QModelIndex index = d->model.index(folder.toLocalFile()); + if (index.isValid() && d->model.isDir(index)) { + d->folder = folder; + QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); + emit folderChanged(); + } +} + +QUrl QmlFolderListModel::parentFolder() const +{ + Q_D(const QmlFolderListModel); + int pos = d->folder.path().lastIndexOf(QLatin1Char('/')); + if (pos == -1) + return QUrl(); + QUrl r = d->folder; + r.setPath(d->folder.path().left(pos)); + return r; +} + +/*! + \qmlproperty list FolderListModel::nameFilters + + The \a nameFilters property contains a list of filename filters. + The filters may include the ? and * wildcards. + + The example below filters on PNG and JPEG files: + + \code + FolderListModel { + nameFilters: [ "*.png", "*.jpg" ] + } + \endcode +*/ +QStringList QmlFolderListModel::nameFilters() const +{ + Q_D(const QmlFolderListModel); + return d->nameFilters; +} + +void QmlFolderListModel::setNameFilters(const QStringList &filters) +{ + Q_D(QmlFolderListModel); + d->nameFilters = filters; + d->model.setNameFilters(d->nameFilters); +} + +void QmlFolderListModel::componentComplete() +{ + Q_D(QmlFolderListModel); + if (!d->folder.isValid() || !QDir().exists(d->folder.toLocalFile())) + setFolder(QUrl(QLatin1String("file://")+QDir::currentPath())); + + if (!d->folderIndex.isValid()) + QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); +} + +QmlFolderListModel::SortField QmlFolderListModel::sortField() const +{ + Q_D(const QmlFolderListModel); + return d->sortField; +} + +void QmlFolderListModel::setSortField(SortField field) +{ + Q_D(QmlFolderListModel); + if (field != d->sortField) { + d->sortField = field; + d->updateSorting(); + } +} + +bool QmlFolderListModel::sortReversed() const +{ + Q_D(const QmlFolderListModel); + return d->sortReversed; +} + +void QmlFolderListModel::setSortReversed(bool rev) +{ + Q_D(QmlFolderListModel); + if (rev != d->sortReversed) { + d->sortReversed = rev; + d->updateSorting(); + } +} + +/*! + \qmlmethod bool FolderListModel::isFolder(int index) + + Returns true if the entry \a index is a folder; otherwise + returns false. +*/ +bool QmlFolderListModel::isFolder(int index) const +{ + Q_D(const QmlFolderListModel); + if (index != -1) { + QModelIndex idx = d->model.index(index, 0, d->folderIndex); + if (idx.isValid()) + return d->model.isDir(idx); + } + return false; +} + +void QmlFolderListModel::refresh() +{ + Q_D(QmlFolderListModel); + d->folderIndex = QModelIndex(); + if (d->count) { + int tmpCount = d->count; + d->count = 0; + emit itemsRemoved(0, tmpCount); + } + d->folderIndex = d->model.index(d->folder.toLocalFile()); + d->count = d->model.rowCount(d->folderIndex); + if (d->count) { + emit itemsInserted(0, d->count); + } +} + +void QmlFolderListModel::inserted(const QModelIndex &index, int start, int end) +{ + Q_D(QmlFolderListModel); + if (index == d->folderIndex) { + d->count = d->model.rowCount(d->folderIndex); + emit itemsInserted(start, end - start + 1); + } +} + +void QmlFolderListModel::removed(const QModelIndex &index, int start, int end) +{ + Q_D(QmlFolderListModel); + if (index == d->folderIndex) { + d->count = d->model.rowCount(d->folderIndex); + emit itemsRemoved(start, end - start + 1); + } +} + +void QmlFolderListModel::dataChanged(const QModelIndex &start, const QModelIndex &end) +{ + Q_D(QmlFolderListModel); + qDebug() << "data changed"; + if (start.parent() == d->folderIndex) + emit itemsChanged(start.row(), end.row() - start.row() + 1, roles()); +} + +/*! + \qmlproperty bool FolderListModel::showDirs + + If true (the default), directories are included in the model. + + Note that the nameFilters are ignored for directories. +*/ +bool QmlFolderListModel::showDirs() const +{ + Q_D(const QmlFolderListModel); + return d->model.filter() & QDir::AllDirs; +} + +void QmlFolderListModel::setShowDirs(bool on) +{ + Q_D(QmlFolderListModel); + if (!(d->model.filter() & QDir::AllDirs) == !on) + return; + if (on) + d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives); + else + d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives)); +} + +/*! + \qmlproperty bool FolderListModel::showDotAndDotDot + + If true, the "." and ".." directories are included in the model. + + The default is false. +*/ +bool QmlFolderListModel::showDotAndDotDot() const +{ + Q_D(const QmlFolderListModel); + return !(d->model.filter() & QDir::NoDotAndDotDot); +} + +void QmlFolderListModel::setShowDotAndDotDot(bool on) +{ + Q_D(QmlFolderListModel); + if (!(d->model.filter() & QDir::NoDotAndDotDot) == on) + return; + if (on) + d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot); + else + d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot); +} + +/*! + \qmlproperty bool FolderListModel::showOnlyReadable + + If true, only readable files and directories are shown. + + The default is false. +*/ +bool QmlFolderListModel::showOnlyReadable() const +{ + Q_D(const QmlFolderListModel); + return d->model.filter() & QDir::Readable; +} + +void QmlFolderListModel::setShowOnlyReadable(bool on) +{ + Q_D(QmlFolderListModel); + if (!(d->model.filter() & QDir::Readable) == !on) + return; + if (on) + d->model.setFilter(d->model.filter() | QDir::Readable); + else + d->model.setFilter(d->model.filter() & ~QDir::Readable); +} + + +QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,FolderListModel,QmlFolderListModel) + +QT_END_NAMESPACE + diff --git a/examples/declarative/loader/qmlfolderlistmodel.h b/examples/declarative/loader/qmlfolderlistmodel.h new file mode 100644 index 0000000..66e600b --- /dev/null +++ b/examples/declarative/loader/qmlfolderlistmodel.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLFOLDERLISTMODEL_H +#define QMLFOLDERLISTMODEL_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlContext; +class QModelIndex; + +class QmlFolderListModelPrivate; +class Q_DECLARATIVE_EXPORT QmlFolderListModel : public QListModelInterface, public QmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QmlParserStatus) + + Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged) + Q_PROPERTY(QUrl parentFolder READ parentFolder NOTIFY folderChanged) + Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters) + Q_PROPERTY(SortField sortField READ sortField WRITE setSortField) + Q_PROPERTY(bool sortReversed READ sortReversed WRITE setSortReversed) + Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs) + Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot) + Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable) + +public: + QmlFolderListModel(QObject *parent = 0); + ~QmlFolderListModel(); + + virtual QHash data(int index, const QList &roles = (QList())) const; + virtual int count() const; + virtual QList roles() const; + virtual QString toString(int role) const; + + QUrl folder() const; + void setFolder(const QUrl &folder); + + QUrl parentFolder() const; + + QStringList nameFilters() const; + void setNameFilters(const QStringList &filters); + + virtual void componentComplete(); + + Q_INVOKABLE bool isFolder(int index) const; + + enum SortField { Unsorted, Name, Time, Size, Type }; + SortField sortField() const; + void setSortField(SortField field); + Q_ENUMS(SortField) + + bool sortReversed() const; + void setSortReversed(bool rev); + + bool showDirs() const; + void setShowDirs(bool); + bool showDotAndDotDot() const; + void setShowDotAndDotDot(bool); + bool showOnlyReadable() const; + void setShowOnlyReadable(bool); + +Q_SIGNALS: + void folderChanged(); + +private Q_SLOTS: + void refresh(); + void inserted(const QModelIndex &index, int start, int end); + void removed(const QModelIndex &index, int start, int end); + void dataChanged(const QModelIndex &start, const QModelIndex &end); + +private: + Q_DECLARE_PRIVATE(QmlFolderListModel) + Q_DISABLE_COPY(QmlFolderListModel) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QmlFolderListModel) + +QT_END_HEADER + +#endif // QMLFOLDERLISTMODEL_H diff --git a/src/declarative/extra/extra.pri b/src/declarative/extra/extra.pri index 6730550..726f099 100644 --- a/src/declarative/extra/extra.pri +++ b/src/declarative/extra/extra.pri @@ -3,7 +3,6 @@ SOURCES += \ extra/qmlnumberformatter.cpp \ extra/qmldatetimeformatter.cpp \ extra/qfxintegermodel.cpp \ - extra/qmlfolderlistmodel.cpp \ extra/qfxanimatedimageitem.cpp \ extra/qfxparticles.cpp \ extra/qmlbehavior.cpp \ @@ -15,7 +14,6 @@ HEADERS += \ extra/qmlnumberformatter.h \ extra/qmldatetimeformatter.h \ extra/qfxintegermodel.h \ - extra/qmlfolderlistmodel.h \ extra/qfxanimatedimageitem.h \ extra/qfxanimatedimageitem_p.h \ extra/qfxparticles.h \ diff --git a/src/declarative/extra/qmlfolderlistmodel.cpp b/src/declarative/extra/qmlfolderlistmodel.cpp deleted file mode 100644 index 0e5c275..0000000 --- a/src/declarative/extra/qmlfolderlistmodel.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "private/qobject_p.h" -#include -#include -#include "qmlfolderlistmodel.h" -#include - -QT_BEGIN_NAMESPACE - -class QmlFolderListModelPrivate : public QObjectPrivate -{ -public: - QmlFolderListModelPrivate() - : sortField(QmlFolderListModel::Name), sortReversed(false), count(0) { - nameFilters << QLatin1String("*"); - } - - void updateSorting() { - QDir::SortFlags flags = 0; - switch(sortField) { - case QmlFolderListModel::Unsorted: - flags |= QDir::Unsorted; - break; - case QmlFolderListModel::Name: - flags |= QDir::Name; - break; - case QmlFolderListModel::Time: - flags |= QDir::Time; - break; - case QmlFolderListModel::Size: - flags |= QDir::Size; - break; - case QmlFolderListModel::Type: - flags |= QDir::Type; - break; - } - - if (sortReversed) - flags |= QDir::Reversed; - - model.setSorting(flags); - } - - QDirModel model; - QUrl folder; - QStringList nameFilters; - QModelIndex folderIndex; - QmlFolderListModel::SortField sortField; - bool sortReversed; - int count; -}; - -/*! - \qmlclass FolderListModel - \brief The FolderListModel provides a model of the contents of a folder in a filesystem. - - FolderListModel provides access to the local filesystem. The \e folder property - specifies the folder to list. - - Qt uses "/" as a universal directory separator in the same way that "/" is - used as a path separator in URLs. If you always use "/" as a directory - separator, Qt will translate your paths to conform to the underlying - operating system. - - The roles available are: - \list - \o fileName - \o filePath - \endlist - - Additionally a file entry can be differentiated from a folder entry - via the \l isFolder() method. -*/ - -QmlFolderListModel::QmlFolderListModel(QObject *parent) - : QListModelInterface(*(new QmlFolderListModelPrivate), parent) -{ - Q_D(QmlFolderListModel); - d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot); - connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int)) - , this, SLOT(inserted(const QModelIndex&,int,int))); - connect(&d->model, SIGNAL(rowsRemoved(const QModelIndex&,int,int)) - , this, SLOT(removed(const QModelIndex&,int,int))); - connect(&d->model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)) - , this, SLOT(dataChanged(const QModelIndex&,const QModelIndex&))); - connect(&d->model, SIGNAL(modelReset()), this, SLOT(refresh())); - connect(&d->model, SIGNAL(layoutChanged()), this, SLOT(refresh())); -} - -QmlFolderListModel::~QmlFolderListModel() -{ -} - -QHash QmlFolderListModel::data(int index, const QList &roles) const -{ - Q_UNUSED(roles); - Q_D(const QmlFolderListModel); - QHash folderData; - QModelIndex modelIndex = d->model.index(index, 0, d->folderIndex); - if (modelIndex.isValid()) { - folderData[QDirModel::FileNameRole] = d->model.data(modelIndex, QDirModel::FileNameRole); - folderData[QDirModel::FilePathRole] = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString()); - } - - return folderData; -} - -int QmlFolderListModel::count() const -{ - Q_D(const QmlFolderListModel); - return d->count; -} - -QList QmlFolderListModel::roles() const -{ - QList r; - r << QDirModel::FileNameRole; - r << QDirModel::FilePathRole; - return r; -} - -QString QmlFolderListModel::toString(int role) const -{ - switch (role) { - case QDirModel::FileNameRole: - return QLatin1String("fileName"); - case QDirModel::FilePathRole: - return QLatin1String("filePath"); - } - - return QString(); -} - -/*! - \qmlproperty string FolderListModel::folder - - The \a folder property holds the folder the model is currently providing. - - It is a URL, but must be a file: or qrc: URL (or relative to such a URL). -*/ -QUrl QmlFolderListModel::folder() const -{ - Q_D(const QmlFolderListModel); - return d->folder; -} - -void QmlFolderListModel::setFolder(const QUrl &folder) -{ - Q_D(QmlFolderListModel); - if (folder == d->folder) - return; - QModelIndex index = d->model.index(folder.toLocalFile()); - if (index.isValid() && d->model.isDir(index)) { - d->folder = folder; - QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); - emit folderChanged(); - } -} - -QUrl QmlFolderListModel::parentFolder() const -{ - Q_D(const QmlFolderListModel); - int pos = d->folder.path().lastIndexOf(QLatin1Char('/')); - if (pos == -1) - return QUrl(); - QUrl r = d->folder; - r.setPath(d->folder.path().left(pos)); - return r; -} - -/*! - \qmlproperty list FolderListModel::nameFilters - - The \a nameFilters property contains a list of filename filters. - The filters may include the ? and * wildcards. - - The example below filters on PNG and JPEG files: - - \code - FolderListModel { - nameFilters: [ "*.png", "*.jpg" ] - } - \endcode -*/ -QStringList QmlFolderListModel::nameFilters() const -{ - Q_D(const QmlFolderListModel); - return d->nameFilters; -} - -void QmlFolderListModel::setNameFilters(const QStringList &filters) -{ - Q_D(QmlFolderListModel); - d->nameFilters = filters; - d->model.setNameFilters(d->nameFilters); -} - -void QmlFolderListModel::componentComplete() -{ - Q_D(QmlFolderListModel); - if (!d->folder.isValid() || !QDir().exists(d->folder.toLocalFile())) - setFolder(QUrl(QLatin1String("file://")+QDir::currentPath())); - - if (!d->folderIndex.isValid()) - QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); -} - -QmlFolderListModel::SortField QmlFolderListModel::sortField() const -{ - Q_D(const QmlFolderListModel); - return d->sortField; -} - -void QmlFolderListModel::setSortField(SortField field) -{ - Q_D(QmlFolderListModel); - if (field != d->sortField) { - d->sortField = field; - d->updateSorting(); - } -} - -bool QmlFolderListModel::sortReversed() const -{ - Q_D(const QmlFolderListModel); - return d->sortReversed; -} - -void QmlFolderListModel::setSortReversed(bool rev) -{ - Q_D(QmlFolderListModel); - if (rev != d->sortReversed) { - d->sortReversed = rev; - d->updateSorting(); - } -} - -/*! - \qmlmethod bool FolderListModel::isFolder(int index) - - Returns true if the entry \a index is a folder; otherwise - returns false. -*/ -bool QmlFolderListModel::isFolder(int index) const -{ - Q_D(const QmlFolderListModel); - if (index != -1) { - QModelIndex idx = d->model.index(index, 0, d->folderIndex); - if (idx.isValid()) - return d->model.isDir(idx); - } - return false; -} - -void QmlFolderListModel::refresh() -{ - Q_D(QmlFolderListModel); - d->folderIndex = QModelIndex(); - if (d->count) { - int tmpCount = d->count; - d->count = 0; - emit itemsRemoved(0, tmpCount); - } - d->folderIndex = d->model.index(d->folder.toLocalFile()); - d->count = d->model.rowCount(d->folderIndex); - if (d->count) { - emit itemsInserted(0, d->count); - } -} - -void QmlFolderListModel::inserted(const QModelIndex &index, int start, int end) -{ - Q_D(QmlFolderListModel); - if (index == d->folderIndex) { - d->count = d->model.rowCount(d->folderIndex); - emit itemsInserted(start, end - start + 1); - } -} - -void QmlFolderListModel::removed(const QModelIndex &index, int start, int end) -{ - Q_D(QmlFolderListModel); - if (index == d->folderIndex) { - d->count = d->model.rowCount(d->folderIndex); - emit itemsRemoved(start, end - start + 1); - } -} - -void QmlFolderListModel::dataChanged(const QModelIndex &start, const QModelIndex &end) -{ - Q_D(QmlFolderListModel); - qDebug() << "data changed"; - if (start.parent() == d->folderIndex) - emit itemsChanged(start.row(), end.row() - start.row() + 1, roles()); -} - -/*! - \qmlproperty bool FolderListModel::showDirs - - If true (the default), directories are included in the model. - - Note that the nameFilters are ignored for directories. -*/ -bool QmlFolderListModel::showDirs() const -{ - Q_D(const QmlFolderListModel); - return d->model.filter() & QDir::AllDirs; -} - -void QmlFolderListModel::setShowDirs(bool on) -{ - Q_D(QmlFolderListModel); - if (!(d->model.filter() & QDir::AllDirs) == !on) - return; - if (on) - d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives); - else - d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives)); -} - -/*! - \qmlproperty bool FolderListModel::showDotAndDotDot - - If true, the "." and ".." directories are included in the model. - - The default is false. -*/ -bool QmlFolderListModel::showDotAndDotDot() const -{ - Q_D(const QmlFolderListModel); - return !(d->model.filter() & QDir::NoDotAndDotDot); -} - -void QmlFolderListModel::setShowDotAndDotDot(bool on) -{ - Q_D(QmlFolderListModel); - if (!(d->model.filter() & QDir::NoDotAndDotDot) == on) - return; - if (on) - d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot); - else - d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot); -} - -/*! - \qmlproperty bool FolderListModel::showOnlyReadable - - If true, only readable files and directories are shown. - - The default is false. -*/ -bool QmlFolderListModel::showOnlyReadable() const -{ - Q_D(const QmlFolderListModel); - return d->model.filter() & QDir::Readable; -} - -void QmlFolderListModel::setShowOnlyReadable(bool on) -{ - Q_D(QmlFolderListModel); - if (!(d->model.filter() & QDir::Readable) == !on) - return; - if (on) - d->model.setFilter(d->model.filter() | QDir::Readable); - else - d->model.setFilter(d->model.filter() & ~QDir::Readable); -} - - -QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,FolderListModel,QmlFolderListModel) - -QT_END_NAMESPACE - diff --git a/src/declarative/extra/qmlfolderlistmodel.h b/src/declarative/extra/qmlfolderlistmodel.h deleted file mode 100644 index 66e600b..0000000 --- a/src/declarative/extra/qmlfolderlistmodel.h +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QMLFOLDERLISTMODEL_H -#define QMLFOLDERLISTMODEL_H - -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QmlContext; -class QModelIndex; - -class QmlFolderListModelPrivate; -class Q_DECLARATIVE_EXPORT QmlFolderListModel : public QListModelInterface, public QmlParserStatus -{ - Q_OBJECT - Q_INTERFACES(QmlParserStatus) - - Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged) - Q_PROPERTY(QUrl parentFolder READ parentFolder NOTIFY folderChanged) - Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters) - Q_PROPERTY(SortField sortField READ sortField WRITE setSortField) - Q_PROPERTY(bool sortReversed READ sortReversed WRITE setSortReversed) - Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs) - Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot) - Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable) - -public: - QmlFolderListModel(QObject *parent = 0); - ~QmlFolderListModel(); - - virtual QHash data(int index, const QList &roles = (QList())) const; - virtual int count() const; - virtual QList roles() const; - virtual QString toString(int role) const; - - QUrl folder() const; - void setFolder(const QUrl &folder); - - QUrl parentFolder() const; - - QStringList nameFilters() const; - void setNameFilters(const QStringList &filters); - - virtual void componentComplete(); - - Q_INVOKABLE bool isFolder(int index) const; - - enum SortField { Unsorted, Name, Time, Size, Type }; - SortField sortField() const; - void setSortField(SortField field); - Q_ENUMS(SortField) - - bool sortReversed() const; - void setSortReversed(bool rev); - - bool showDirs() const; - void setShowDirs(bool); - bool showDotAndDotDot() const; - void setShowDotAndDotDot(bool); - bool showOnlyReadable() const; - void setShowOnlyReadable(bool); - -Q_SIGNALS: - void folderChanged(); - -private Q_SLOTS: - void refresh(); - void inserted(const QModelIndex &index, int start, int end); - void removed(const QModelIndex &index, int start, int end); - void dataChanged(const QModelIndex &start, const QModelIndex &end); - -private: - Q_DECLARE_PRIVATE(QmlFolderListModel) - Q_DISABLE_COPY(QmlFolderListModel) -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QmlFolderListModel) - -QT_END_HEADER - -#endif // QMLFOLDERLISTMODEL_H -- cgit v0.12 From b54b0357f59fd398db07161fd8320b306220c104 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 21 Oct 2009 11:39:17 +1000 Subject: Doc. --- src/declarative/fx/qfxlistview.cpp | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index 4fb0ec1..2ea1cb7 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -864,6 +864,52 @@ QFxListView::~QFxListView() } /*! + \qmlattachedproperty bool ListView::isCurrentItem + This attched property is true if this delegate is the current item; otherwise false. + + It is attached to each instance of the delegate. + + This property may be used to adjust the appearance of the current item, for example: + + \snippet doc/src/snippets/declarative/listview/highlight.qml 0 +*/ + +/*! + \qmlattachedproperty ListView ListView::view + This attached property holds the view that manages this delegate instance. + + It is attached to each instance of the delegate. +*/ + +/*! + \qmlattachedproperty string ListView::prevSection + This attached property holds the section of the previous element. + + It is attached to each instance of the delegate. + + The section is evaluated using the \l {ListView::sectionExpression}{sectionExpression} property. +*/ + +/*! + \qmlattachedproperty string ListView::section + This attached property holds the section of this element. + + It is attached to each instance of the delegate. + + The section is evaluated using the \l {ListView::sectionExpression}{sectionExpression} property. +*/ + +/*! + \qmlattachedproperty bool ListView::delayRemove + This attached property holds whether the delegate may be destroyed. + + It is attached to each instance of the delegate. + + It is sometimes necessary to delay the destruction of an item + until an animation completes. +*/ + +/*! \qmlproperty model ListView::model This property holds the model providing data for the list. -- cgit v0.12 From db6a53356aa72e59fcbc631c5cde77c14d51acc1 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 21 Oct 2009 11:40:50 +1000 Subject: Docs. --- doc/src/declarative/qmlmodels.qdoc | 45 +++++++++++++++++++--- .../snippets/declarative/listview/highlight.qml | 12 ++++++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/doc/src/declarative/qmlmodels.qdoc b/doc/src/declarative/qmlmodels.qdoc index 6ebb734..45df29b 100644 --- a/doc/src/declarative/qmlmodels.qdoc +++ b/doc/src/declarative/qmlmodels.qdoc @@ -50,12 +50,18 @@ creates an instance for each item in the model. Models may be static, or have items modified, inserted, removed or moved dynamically. Data is provided to the delegate via named data roles which the -delegate may bind to. A special \e index role containing the -index of the item in the model is also available. Models that do -not have named roles will have the data provided via the \e modelData -role. The \e modelData role is also provided for Models that have -only one role. In this case the \e modelData role contains the same -data as the named role. +delegate may bind to. The roles are exposed as properties of the +\model property, though this property is set as a default property +of the delegate so, unless there is a naming clash with a +property in the delegate, the roles are usually accessed unqualified. + +A special \e index role containing the index of the item in the model +is also available. + +Models that do not have named roles will have the data provided via +the \e modelData role. The \e modelData role is also provided for +Models that have only one role. In this case the \e modelData role +contains the same data as the named role. There are a number of QML elements that operate using data models: @@ -189,4 +195,31 @@ ListView { An Object Instance specifies a model with a single Object element. The properties of the object are provided as roles. +The example below creates a list with one item, showing the color of the +\e myText text. Note the use of the \e model property to specify the model +data rather than the \e color property of the Text element in the delegate. + +\code +Rectangle { + Text { + id: myText + text: "Hello" + color: "#dd44ee" + } + + Component { + id: myDelegate + Text { + text: model.color + } + } + ListView { + anchors.fill: parent + anchors.topMargin: 30 + model: myText + delegate: myDelegate + } +} +\endcode + */ diff --git a/doc/src/snippets/declarative/listview/highlight.qml b/doc/src/snippets/declarative/listview/highlight.qml index 2234ee7..7970ede 100644 --- a/doc/src/snippets/declarative/listview/highlight.qml +++ b/doc/src/snippets/declarative/listview/highlight.qml @@ -20,6 +20,18 @@ Rectangle { Text { text: 'Name: ' + name } Text { text: 'Number: ' + number } } + // Use the ListView.isCurrentItem attached property to + // indent the item if it is the current item. + states: [ + State { + name: "Current" + when: wrapper.ListView.isCurrentItem + PropertyChanges { target: wrapper; x: 10 } + } + ] + transitions: [ + Transition { NumberAnimation { properties: "x"; duration: 200 } } + ] } } //! [0] -- cgit v0.12 From 2f1f614aec6011a60102f2ca45980fb9b62a2e2c Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 21 Oct 2009 09:16:48 +1000 Subject: Add missing Q_OBJECT macros. --- src/declarative/util/qmlanimation_p.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index 4f6edb7..22c4e2d 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -92,6 +92,7 @@ private: //performs an action of type QAbstractAnimationAction class QActionAnimation : public QAbstractAnimation { + Q_OBJECT public: QActionAnimation(QObject *parent = 0) : QAbstractAnimation(parent), animAction(0), policy(KeepWhenStopped) {} QActionAnimation(QAbstractAnimationAction *action, QObject *parent = 0) @@ -126,6 +127,7 @@ private: //animates QmlTimeLineValue (assumes start and end values will be reals or compatible) class QmlTimeLineValueAnimator : public QVariantAnimation { + Q_OBJECT public: QmlTimeLineValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), fromSourced(0), policy(KeepWhenStopped) {} void setAnimValue(QmlTimeLineValue *value, DeletionPolicy p) -- cgit v0.12 From 4b36e00eba66eab873d3fe15aa3ceedd5dd18ae0 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 21 Oct 2009 09:17:18 +1000 Subject: Revert "Additional temporary fix for animation bug." This reverts commit 04eae20d3b86cc61ab3b3bdded74caa370a84c43. --- src/corelib/animation/qabstractanimation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 8d34a98..f23ad3c 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -228,7 +228,11 @@ void QUnifiedTimer::updateAnimationsTime() void QUnifiedTimer::restartAnimationTimer() { - if (!animationTimer.isActive()) { + if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) { + int closestTimeToFinish = closestPauseAnimationTimeToFinish(); + animationTimer.start(closestTimeToFinish, this); + isPauseTimerActive = true; + } else if (!animationTimer.isActive() || isPauseTimerActive) { animationTimer.start(timingInterval, this); isPauseTimerActive = false; } -- cgit v0.12 From b8c939903b8afc0abe38ab2e315a5bda32221aae Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 21 Oct 2009 09:29:13 +1000 Subject: Manually apply proper animation fixes. --- src/corelib/animation/qabstractanimation.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index f23ad3c..0d5f278 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -278,11 +278,11 @@ void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopL void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) { - unregisterRunningAnimation(animation); - if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer) return; + unregisterRunningAnimation(animation); + int idx = animations.indexOf(animation); if (idx != -1) { animations.removeAt(idx); @@ -318,6 +318,7 @@ void QUnifiedTimer::unregisterRunningAnimation(QAbstractAnimation *animation) runningPauseAnimations.removeOne(animation); else runningLeafAnimations--; + Q_ASSERT(runningLeafAnimations >= 0); } int QUnifiedTimer::closestPauseAnimationTimeToFinish() @@ -328,9 +329,9 @@ int QUnifiedTimer::closestPauseAnimationTimeToFinish() int timeToFinish; if (animation->direction() == QAbstractAnimation::Forward) - timeToFinish = animation->duration() - QAbstractAnimationPrivate::get(animation)->currentTime; + timeToFinish = animation->duration() - animation->currentTime(); else - timeToFinish = QAbstractAnimationPrivate::get(animation)->totalCurrentTime; + timeToFinish = animation->currentTime(); if (timeToFinish < closestTimeToFinish) closestTimeToFinish = timeToFinish; @@ -648,13 +649,13 @@ int QAbstractAnimation::currentLoop() const */ int QAbstractAnimation::totalDuration() const { - Q_D(const QAbstractAnimation); - if (d->loopCount < 0) - return -1; int dura = duration(); - if (dura == -1) + if (dura <= 0) + return dura; + int loopcount = loopCount(); + if (loopcount < 0) return -1; - return dura * d->loopCount; + return dura * loopcount; } /*! @@ -685,7 +686,7 @@ void QAbstractAnimation::setCurrentTime(int msecs) // Calculate new time and loop. int dura = duration(); - int totalDura = (d->loopCount < 0 || dura == -1) ? -1 : dura * d->loopCount; + int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount); if (totalDura != -1) msecs = qMin(totalDura, msecs); d->totalCurrentTime = msecs; -- cgit v0.12 From 2c70994c3b9b0839ef5d489e6dfcaaf6c4ed6b4d Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 21 Oct 2009 10:57:02 +1000 Subject: Rename QBindableMap to QmlPropertyMap. Task-number: QT-2316 --- src/declarative/extra/extra.pri | 2 - src/declarative/extra/qbindablemap.cpp | 182 ------------------- src/declarative/extra/qbindablemap.h | 86 --------- src/declarative/util/qmlpropertymap.cpp | 198 +++++++++++++++++++++ src/declarative/util/qmlpropertymap.h | 83 +++++++++ src/declarative/util/util.pri | 6 +- .../auto/declarative/qbindablemap/qbindablemap.pro | 3 - .../declarative/qbindablemap/tst_qbindablemap.cpp | 77 -------- .../declarative/qmlpropertymap/qmlpropertymap.pro | 3 + .../qmlpropertymap/tst_qmlpropertymap.cpp | 77 ++++++++ 10 files changed, 365 insertions(+), 352 deletions(-) delete mode 100644 src/declarative/extra/qbindablemap.cpp delete mode 100644 src/declarative/extra/qbindablemap.h create mode 100644 src/declarative/util/qmlpropertymap.cpp create mode 100644 src/declarative/util/qmlpropertymap.h delete mode 100644 tests/auto/declarative/qbindablemap/qbindablemap.pro delete mode 100644 tests/auto/declarative/qbindablemap/tst_qbindablemap.cpp create mode 100644 tests/auto/declarative/qmlpropertymap/qmlpropertymap.pro create mode 100644 tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp diff --git a/src/declarative/extra/extra.pri b/src/declarative/extra/extra.pri index 726f099..502504a 100644 --- a/src/declarative/extra/extra.pri +++ b/src/declarative/extra/extra.pri @@ -6,7 +6,6 @@ SOURCES += \ extra/qfxanimatedimageitem.cpp \ extra/qfxparticles.cpp \ extra/qmlbehavior.cpp \ - extra/qbindablemap.cpp \ extra/qmlfontloader.cpp HEADERS += \ @@ -18,7 +17,6 @@ HEADERS += \ extra/qfxanimatedimageitem_p.h \ extra/qfxparticles.h \ extra/qmlbehavior.h \ - extra/qbindablemap.h \ extra/qmlfontloader.h contains(QT_CONFIG, xmlpatterns) { diff --git a/src/declarative/extra/qbindablemap.cpp b/src/declarative/extra/qbindablemap.cpp deleted file mode 100644 index 5254e2a..0000000 --- a/src/declarative/extra/qbindablemap.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qbindablemap.h" -#include -#include - -QT_BEGIN_NAMESPACE - -//QBindableMapMetaObject lets us listen for changes coming from QML -//so we can emit the changed signal. -class QBindableMapMetaObject : public QmlOpenMetaObject -{ -public: - QBindableMapMetaObject(QBindableMap *obj) : QmlOpenMetaObject(obj) - { - map = obj; - } - -protected: - virtual void propertyWrite(int index) - { - map->emitChanged(QString::fromUtf8(name(index))); - } - -private: - QBindableMap *map; -}; - -/*! - \class QBindableMap - \brief The QBindableMap class allows you to set key-value pairs that can be used in bindings. - - QBindableMap provides a convenient way to expose domain data to the UI layer. - The following example shows how you might declare data in C++ and then - access it in QML. - - Setup in C++: - \code - //create our data - QBindableMap ownerData; - ownerData.setValue("name", QVariant(QString("John Smith"))); - ownerData.setValue("phone", QVariant(QString("555-5555"))); - - //expose it to the UI layer - QmlContext *ctxt = view->bindContext(); - ctxt->setProperty("owner", &data); - \endcode - - Then, in QML: - \code - Text { text: owner.name } - Text { text: owner.phone } - \endcode - - The binding is dynamic - whenever a key's value is updated, anything bound to that - key will be updated as well. - - To detect value changes made in the UI layer you can connect to the changed() signal. - However, note that changed() is \b NOT emitted when changes are made by calling setValue() - or clearValue() - it is only emitted when a value is updated from QML. -*/ - -// is there a more efficient way to store/return keys? -// (or should we just provide an iterator or something else instead?) -// can we provide a way to clear keys? -// do we want to make any claims regarding key ordering? -// should we have signals for insertion and and deletion -- becoming more model like -// should we emit change for our own changes as well? -// Bug or Feature?: values can be created in QML (owner.somethingElse = "Hello") will create somethingElse property. (need to verify if this is actually the case) -// Bug or Feature?: all values are read-write (there are no read-only values) - -/*! - Constructs a bindable map with parent object \a parent. -*/ -QBindableMap::QBindableMap(QObject *parent) -: QObject(parent) -{ - m_mo = new QBindableMapMetaObject(this); -} - -/*! - Destroys the bindable map. -*/ -QBindableMap::~QBindableMap() -{ -} - -/*! - Clears the value (if any) associated with \a key. -*/ -void QBindableMap::clearValue(const QString &key) -{ - //m_keys.remove(); //### - m_mo->setValue(key.toUtf8(), QVariant()); - //emit changed(key); -} - -/*! - Returns the value associated with \a key. - - If no value has been set for this key (or if the value has been cleared), - an invalid QVariant is returned. -*/ -QVariant QBindableMap::value(const QString &key) const -{ - return m_mo->value(key.toUtf8()); -} - -/*! - Sets the value associated with \a key to \a value. - - If the key doesn't exist, it is automatically created. -*/ -void QBindableMap::setValue(const QString &key, QVariant value) -{ - if (!m_keys.contains(key)) - m_keys.append(key); - m_mo->setValue(key.toUtf8(), value); - //emit changed(key); -} - -/*! - Returns the list of keys. - - Keys that have been cleared will still appear in this list, even though their - associated values are invalid QVariants. -*/ -QStringList QBindableMap::keys() const -{ - return m_keys; -} - -/*! - \fn void QBindableMap::changed(const QString &key) - This signal is emitted whenever one of the values in the map is changed. \a key - is the key corresponding to the value that was changed. - */ - -void QBindableMap::emitChanged(const QString &key) -{ - emit changed(key); -} -QT_END_NAMESPACE diff --git a/src/declarative/extra/qbindablemap.h b/src/declarative/extra/qbindablemap.h deleted file mode 100644 index aa1908e..0000000 --- a/src/declarative/extra/qbindablemap.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QBINDABLEMAP_H -#define QBINDABLEMAP_H - -#include -#include -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QBindableMapMetaObject; -class Q_DECLARATIVE_EXPORT QBindableMap : public QObject -{ - Q_OBJECT -public: - QBindableMap(QObject *parent = 0); - virtual ~QBindableMap(); - - QVariant value(const QString &key) const; - void setValue(const QString &key, QVariant value); - void clearValue(const QString &key); - - Q_INVOKABLE QStringList keys() const; - -Q_SIGNALS: - void changed(const QString &key); - -private: - Q_DISABLE_COPY(QBindableMap) - void emitChanged(const QString &key); - QBindableMapMetaObject *m_mo; - QStringList m_keys; - friend class QBindableMapMetaObject; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif diff --git a/src/declarative/util/qmlpropertymap.cpp b/src/declarative/util/qmlpropertymap.cpp new file mode 100644 index 0000000..e23eebf --- /dev/null +++ b/src/declarative/util/qmlpropertymap.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlpropertymap.h" +#include +#include + +QT_BEGIN_NAMESPACE + +//QBindableMapMetaObject lets us listen for changes coming from QML +//so we can emit the changed signal. +class QmlPropertyMapMetaObject : public QmlOpenMetaObject +{ +public: + QmlPropertyMapMetaObject(QmlPropertyMap *obj, QmlPropertyMapPrivate *objPriv); + +protected: + virtual void propertyWrite(int index); + +private: + QmlPropertyMap *map; + QmlPropertyMapPrivate *priv; +}; + +class QmlPropertyMapPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlPropertyMap) +public: + QmlPropertyMapMetaObject *mo; + QStringList keys; + void emitChanged(const QString &key); +}; + +void QmlPropertyMapPrivate::emitChanged(const QString &key) +{ + Q_Q(QmlPropertyMap); + emit q->changed(key); +} + +QmlPropertyMapMetaObject::QmlPropertyMapMetaObject(QmlPropertyMap *obj, QmlPropertyMapPrivate *objPriv) : QmlOpenMetaObject(obj) +{ + map = obj; + priv = objPriv; +} + +void QmlPropertyMapMetaObject::propertyWrite(int index) +{ + priv->emitChanged(QString::fromUtf8(name(index))); +} + +/*! + \class QBindableMap + \brief The QBindableMap class allows you to set key-value pairs that can be used in bindings. + + QBindableMap provides a convenient way to expose domain data to the UI layer. + The following example shows how you might declare data in C++ and then + access it in QML. + + Setup in C++: + \code + //create our data + QBindableMap ownerData; + ownerData.setValue("name", QVariant(QString("John Smith"))); + ownerData.setValue("phone", QVariant(QString("555-5555"))); + + //expose it to the UI layer + QmlContext *ctxt = view->bindContext(); + ctxt->setProperty("owner", &data); + \endcode + + Then, in QML: + \code + Text { text: owner.name } + Text { text: owner.phone } + \endcode + + The binding is dynamic - whenever a key's value is updated, anything bound to that + key will be updated as well. + + To detect value changes made in the UI layer you can connect to the changed() signal. + However, note that changed() is \b NOT emitted when changes are made by calling setValue() + or clearValue() - it is only emitted when a value is updated from QML. +*/ + +// is there a more efficient way to store/return keys? +// (or should we just provide an iterator or something else instead?) +// can we provide a way to clear keys? +// do we want to make any claims regarding key ordering? +// should we have signals for insertion and and deletion -- becoming more model like + +/*! + Constructs a bindable map with parent object \a parent. +*/ +QmlPropertyMap::QmlPropertyMap(QObject *parent) +: QObject(*(new QmlPropertyMapPrivate), parent) +{ + Q_D(QmlPropertyMap); + d->mo = new QmlPropertyMapMetaObject(this, d); +} + +/*! + Destroys the bindable map. +*/ +QmlPropertyMap::~QmlPropertyMap() +{ +} + +/*! + Clears the value (if any) associated with \a key. +*/ +void QmlPropertyMap::clearValue(const QString &key) +{ + Q_D(QmlPropertyMap); + d->mo->setValue(key.toUtf8(), QVariant()); +} + +/*! + Returns the value associated with \a key. + + If no value has been set for this key (or if the value has been cleared), + an invalid QVariant is returned. +*/ +QVariant QmlPropertyMap::value(const QString &key) const +{ + Q_D(const QmlPropertyMap); + return d->mo->value(key.toUtf8()); +} + +/*! + Sets the value associated with \a key to \a value. + + If the key doesn't exist, it is automatically created. +*/ +void QmlPropertyMap::setValue(const QString &key, const QVariant &value) +{ + Q_D(QmlPropertyMap); + if (!d->keys.contains(key)) + d->keys.append(key); + d->mo->setValue(key.toUtf8(), value); +} + +/*! + Returns the list of keys. + + Keys that have been cleared will still appear in this list, even though their + associated values are invalid QVariants. +*/ +QStringList QmlPropertyMap::keys() const +{ + Q_D(const QmlPropertyMap); + return d->keys; +} + +/*! + \fn void QBindableMap::changed(const QString &key) + This signal is emitted whenever one of the values in the map is changed. \a key + is the key corresponding to the value that was changed. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/util/qmlpropertymap.h b/src/declarative/util/qmlpropertymap.h new file mode 100644 index 0000000..295f4b7 --- /dev/null +++ b/src/declarative/util/qmlpropertymap.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPROPERTYMAP_H +#define QMLPROPERTYMAP_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlPropertyMapPrivate; +class Q_DECLARATIVE_EXPORT QmlPropertyMap : public QObject +{ + Q_OBJECT +public: + QmlPropertyMap(QObject *parent = 0); + virtual ~QmlPropertyMap(); + + QVariant value(const QString &key) const; + void setValue(const QString &key, const QVariant &value); + void clearValue(const QString &key); + + Q_INVOKABLE QStringList keys() const; + +Q_SIGNALS: + void changed(const QString &key); + +private: + Q_DECLARE_PRIVATE(QmlPropertyMap) + Q_DISABLE_COPY(QmlPropertyMap) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index ec9967c..01ad898 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -19,7 +19,8 @@ SOURCES += \ util/qmlopenmetaobject.cpp \ util/qmltimeline.cpp \ util/qmltimer.cpp \ - util/qmlbind.cpp + util/qmlbind.cpp \ + util/qmlpropertymap.cpp HEADERS += \ util/qmlview.h \ @@ -46,4 +47,5 @@ HEADERS += \ util/qmlnullablevalue_p.h \ util/qmltimeline_p.h \ util/qmltimer.h \ - util/qmlbind.h + util/qmlbind.h \ + util/qmlpropertymap.h diff --git a/tests/auto/declarative/qbindablemap/qbindablemap.pro b/tests/auto/declarative/qbindablemap/qbindablemap.pro deleted file mode 100644 index b042405..0000000 --- a/tests/auto/declarative/qbindablemap/qbindablemap.pro +++ /dev/null @@ -1,3 +0,0 @@ -load(qttest_p4) -contains(QT_CONFIG,declarative): QT += declarative -SOURCES += tst_qbindablemap.cpp diff --git a/tests/auto/declarative/qbindablemap/tst_qbindablemap.cpp b/tests/auto/declarative/qbindablemap/tst_qbindablemap.cpp deleted file mode 100644 index c1b31c2..0000000 --- a/tests/auto/declarative/qbindablemap/tst_qbindablemap.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -class tst_QBindableMap : public QObject -{ - Q_OBJECT -public: - tst_QBindableMap() {} - -private slots: - void insert(); - void clear(); - void changed(); -}; - -void tst_QBindableMap::insert() -{ - QBindableMap map; - map.setValue(QLatin1String("key1"),100); - map.setValue(QLatin1String("key2"),200); - QVERIFY(map.keys().count() == 2); - - QCOMPARE(map.value(QLatin1String("key1")), QVariant(100)); - QCOMPARE(map.value(QLatin1String("key2")), QVariant(200)); - - map.setValue(QLatin1String("key1"),"Hello World"); - QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); -} - -void tst_QBindableMap::clear() -{ - QBindableMap map; - map.setValue(QLatin1String("key1"),100); - QVERIFY(map.keys().count() == 1); - - QCOMPARE(map.value(QLatin1String("key1")), QVariant(100)); - - map.clearValue(QLatin1String("key1")); - QVERIFY(map.keys().count() == 1); - QCOMPARE(map.value(QLatin1String("key1")), QVariant()); -} - -void tst_QBindableMap::changed() -{ - QBindableMap map; - QSignalSpy spy(&map, SIGNAL(changed(const QString&))); - map.setValue(QLatin1String("key1"),100); - map.setValue(QLatin1String("key2"),200); - QCOMPARE(spy.count(), 0); - - map.clearValue(QLatin1String("key1")); - QCOMPARE(spy.count(), 0); - - //make changes in QML - QmlEngine engine; - QmlContext *ctxt = engine.rootContext(); - ctxt->setContextProperty(QLatin1String("testdata"), &map); - QmlComponent component(&engine, "import Qt 4.6\nText { text: { testdata.key1 = 'Hello World'; 'X' } }", - QUrl("file://")); - QVERIFY(component.isReady()); - QFxText *txt = qobject_cast(component.create()); - QVERIFY(txt); - QCOMPARE(txt->text(), QString('X')); - QCOMPARE(spy.count(), 1); - QList arguments = spy.takeFirst(); - QCOMPARE(arguments.at(0).toString(),QLatin1String("key1")); - QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); -} - -QTEST_MAIN(tst_QBindableMap) - -#include "tst_qbindablemap.moc" diff --git a/tests/auto/declarative/qmlpropertymap/qmlpropertymap.pro b/tests/auto/declarative/qmlpropertymap/qmlpropertymap.pro new file mode 100644 index 0000000..94f138f --- /dev/null +++ b/tests/auto/declarative/qmlpropertymap/qmlpropertymap.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_qmlpropertymap.cpp diff --git a/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp b/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp new file mode 100644 index 0000000..a923234 --- /dev/null +++ b/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include +#include + +class tst_QmlPropertyMap : public QObject +{ + Q_OBJECT +public: + tst_QmlPropertyMap() {} + +private slots: + void insert(); + void clear(); + void changed(); +}; + +void tst_QmlPropertyMap::insert() +{ + QmlPropertyMap map; + map.setValue(QLatin1String("key1"),100); + map.setValue(QLatin1String("key2"),200); + QVERIFY(map.keys().count() == 2); + + QCOMPARE(map.value(QLatin1String("key1")), QVariant(100)); + QCOMPARE(map.value(QLatin1String("key2")), QVariant(200)); + + map.setValue(QLatin1String("key1"),"Hello World"); + QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); +} + +void tst_QmlPropertyMap::clear() +{ + QmlPropertyMap map; + map.setValue(QLatin1String("key1"),100); + QVERIFY(map.keys().count() == 1); + + QCOMPARE(map.value(QLatin1String("key1")), QVariant(100)); + + map.clearValue(QLatin1String("key1")); + QVERIFY(map.keys().count() == 1); + QCOMPARE(map.value(QLatin1String("key1")), QVariant()); +} + +void tst_QmlPropertyMap::changed() +{ + QmlPropertyMap map; + QSignalSpy spy(&map, SIGNAL(changed(const QString&))); + map.setValue(QLatin1String("key1"),100); + map.setValue(QLatin1String("key2"),200); + QCOMPARE(spy.count(), 0); + + map.clearValue(QLatin1String("key1")); + QCOMPARE(spy.count(), 0); + + //make changes in QML + QmlEngine engine; + QmlContext *ctxt = engine.rootContext(); + ctxt->setContextProperty(QLatin1String("testdata"), &map); + QmlComponent component(&engine, "import Qt 4.6\nText { text: { testdata.key1 = 'Hello World'; 'X' } }", + QUrl("file://")); + QVERIFY(component.isReady()); + QFxText *txt = qobject_cast(component.create()); + QVERIFY(txt); + QCOMPARE(txt->text(), QString('X')); + QCOMPARE(spy.count(), 1); + QList arguments = spy.takeFirst(); + QCOMPARE(arguments.at(0).toString(),QLatin1String("key1")); + QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); +} + +QTEST_MAIN(tst_QmlPropertyMap) + +#include "tst_qmlpropertymap.moc" -- cgit v0.12 From ee086ea4fd9baa3df94909dd9f5884578c1eaeb7 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 21 Oct 2009 11:50:01 +1000 Subject: Prepend element name for detailed attached property docs. --- tools/qdoc3/cppcodemarker.cpp | 4 ++++ tools/qdoc3/node.h | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/qdoc3/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp index 3bee3d9..30ea251 100644 --- a/tools/qdoc3/cppcodemarker.cpp +++ b/tools/qdoc3/cppcodemarker.cpp @@ -353,6 +353,10 @@ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) QString name = taggedQmlNode(node); if (summary) { name = linkTag(node,name); + } else if (node->type() == Node::QmlProperty) { + const QmlPropertyNode* pn = static_cast(node); + if (pn->isAttached()) + name.prepend(pn->element() + QLatin1Char('.')); } name = "<@name>" + name + ""; QString synopsis = name; diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h index c6f860f..6b19f60 100644 --- a/tools/qdoc3/node.h +++ b/tools/qdoc3/node.h @@ -376,7 +376,7 @@ class QmlPropGroupNode : public FakeNode bool attached); virtual ~QmlPropGroupNode() { } - const QString& element() const { return name(); } + const QString& element() const { return parent()->name(); } void setDefault() { isdefault = true; } bool isDefault() const { return isdefault; } bool isAttached() const { return att; } @@ -405,7 +405,7 @@ class QmlPropertyNode : public LeafNode bool isDesignable() const { return fromTrool(des,false); } bool isAttached() const { return att; } - const QString& element() const { return parent()->name(); } + const QString& element() const { return static_cast(parent())->element(); } private: enum Trool { Trool_True, Trool_False, Trool_Default }; -- cgit v0.12 From be94259250bc84705d71a66f7c114472097c9b4d Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 21 Oct 2009 11:53:06 +1000 Subject: Doc --- doc/src/declarative/propertybinding.qdoc | 2 +- doc/src/declarative/qtbinding.qdoc | 236 +++++++++++++++++++------------ 2 files changed, 146 insertions(+), 92 deletions(-) diff --git a/doc/src/declarative/propertybinding.qdoc b/doc/src/declarative/propertybinding.qdoc index 50cbf2d..2b8a58c 100644 --- a/doc/src/declarative/propertybinding.qdoc +++ b/doc/src/declarative/propertybinding.qdoc @@ -97,6 +97,6 @@ The implicit binding syntax shown previously is easy to use and works perfectly of bindings. In some advanced cases, it is necessary to create bindings explicitly using the \l Binding element. -One such example is included in the \l {Passing Data Between C++ and QML} documentation. +XXX - need an example */ diff --git a/doc/src/declarative/qtbinding.qdoc b/doc/src/declarative/qtbinding.qdoc index 1831cf8..86acf9f 100644 --- a/doc/src/declarative/qtbinding.qdoc +++ b/doc/src/declarative/qtbinding.qdoc @@ -44,10 +44,16 @@ \target qtbinding \title Using QML in C++ Applications +\tableofcontents + The QML API is split into three main classes - QmlEngine, QmlComponent and QmlContext. QmlEngine provides the environment in which QML is run, QmlComponent encapsulates \l {QML Documents}, and QmlContext allows applications to expose data to QML component instances. +QML also includes a convenience API, QmlView, for applications that simply want to embed QML +components into a new QGraphicsView. QmlView covers up many of the details discussed below. +While QmlView is mainly intended for rapid prototyping it can have uses in production applications. + \section1 Basic Usage Every application requires at least one QmlEngine. A QmlEngine allows the configuration of @@ -76,134 +82,182 @@ QML components are instantiated in a QmlContext. A context allows the applicati to the QML component instance. A single QmlContext can be used to instantiate all the objects used by an application, or several QmlContext can be created for more fine grained control over the data exposed to each instance. If a context is not passed to the QmlComponent::create() -method, the QmlEngine's \l {QmlEngine::rootContext()}{root context} is used. +method, the QmlEngine's \l {QmlEngine::rootContext()}{root context} is used. Data exposed through +the root context is available to all object instances. -To expose data to a QML component instance, applications set \l {QmlContext::setContextProperty()}{context properties} which are then accessible by name from QML \l {Property Binding}s and -\l {ECMAScript Blocks}. +\section1 Simple Data -\section1 Network Components +To expose data to a QML component instance, applications set \l {QmlContext::setContextProperty()} +{context properties} which are then accessible by name from QML \l {Property Binding}s and +\l {ECMAScript Blocks}. The following example shows how to expose a background color to a QML +file. -If the URL passed to QmlComponent is a network resource, or if the QML document references a -network resource, the QmlComponent has to fetch the network data before it is able to create -objects. In this case, the QmlComponent will have a \l {QmlComponent::Loading}{Loading} -\l {QmlComponent::status()}{status}. An application will have to wait until the component -is \l {QmlComponent::Ready}{Ready} before calling \l {QmlComponent::create()}. - -The following example shows how to load a QML file from a network resource. After creating -the QmlComponent, it tests whether the component is loading. If it is, it connects to the -QmlComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method -directly. This test is necessary, even for URLs that are known to be remote, just in case -the component has been cached and is ready immediately. +\table +\row +\o +\code +// main.cpp +QmlContext *windowContext = new QmlContext(engine->rootContext()); +windowContext->setContextProperty("backgroundColor", + QColor(Qt::lightsteelblue)); +QmlComponent component(&engine, "main.qml"); +QObject *window = component.create(windowContext); +\endcode +\o \code -MyApplication::MyApplication() -{ - // ... - component = new QmlComponent(engine, QUrl("http://www.example.com/main.qml")); - if (component->isLoading()) - QObject::connect(component, SIGNAL(statusChanged(QmlComponent::Status)), - this, SLOT(continueLoading())); - else - continueLoading(); -} +// main.qml +import Qt 4.6 -void MyApplication::continueLoading() -{ - if (component->isError()) { - qWarning() << component->errors(); - } else { - QObject *myObject = component->create(); +Rectangle { + color: backgroundColor + + Text { + anchors.centerIn: parent + text: "Hello Light Steel Blue World!" } } \endcode +\endtable -\section1 TODO -\list -\o QmlEngine and QmlComponent -\o QmlContext and data -\o QBindableMap -\o QAbstractItemModel Data models -\o QmlView -\endlist - -*/ +Context properties work just like normal properties in QML bindings - if the \c backgroundColor +context property in the previous example was changed to red, the component object instances would +all be automatically updated. -/* -\section1 Overview +QmlContexts form a tree - each QmlContext except for the root context has a parent. Child +QmlContexts effectively inherit the context properties present in their parents. This gives +applications more freedom in partitioning the data exposed to different QML object instances. +If a QmlContext sets a context property that is also set in one of its parents, the new context +property shadows that in the parent. In The following example, the \c background context property +in \c {Context 1} shadows the \c background context property in the root context. -The QML mechanisms of data binding can also be used to bind Qt C++ objects. +\image qml-context-tree.png -The data binding framework is based on Qt's property system (see the Qt documentation for more details on this system). If a binding is meant to be dynamic (where changes in one object are reflected in another object), \c NOTIFY must be specified for the property being tracked. If \c NOTIFY is not specified, any binding to that property will be an 'intialization' binding (the tracking object will be updated only once with the initial value of the tracked object). +\section2 Structured Data -Relevant items can also be bound to the contents of a Qt model. -For example, ListView can make use of data from a QAbstractItemModel-derived model. +Context properties can also be used to expose structured and writable data to QML objects. In +addition to all the types already supported by QVariant, QObject derived types can be assigned to +context properties. QObject context properties allow the data exposed to be more structured, and +allow QML to set values. -\section1 Passing Data Between C++ and QML +The following example creates a \c CustomPalette object, and sets it as the \c palette context +property. -Data binding provides one method of data transfer between C++ and QML. - -For example, lets say you want to implement a slider in QML that changes the screen brightness of the device it is running on. You would start by declaring a brightness property on your QObject-derived class: \code -class MyScreen : public QObject +class CustomPalette : public QObject { - Q_OBJECT +Q_OBJECT +Q_PROPERTY(QColor background READ background WRITE setBackground NOTIFY backgroundChanged) +Q_PROPERTY(QColor text READ text WRITE setText NOTIFY text) public: - MyScreen(QObject *parent=0); - - Q_PROPERTY(int brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged); - int brightness() const; - void setBrightness(int b); - ... - -signals: - void brightnessChanged(); + CustomPalette() : m_background(Qt::white), m_text(Qt::black) {} + + QColor background() const { return m_background; } + void setBackground(const QColor &c) { + if (c != m_background) { + m_background = c; + emit backgroundChanged(); + } + } + QColor text() const { return m_text; } + void setText(const QColor &c) { + if (c != m_text) { + m_text = c; + emit textChanged(); + } + } private: - int m_brightness; + QColor m_background; + QColor m_text; }; -int brightness() const +int main(int argc, char **argv) { - return m_brightness; -} + // ... -void setBrightness(int b) -{ - if (b != m_brightness) { - m_brightness = b; - emit brightnessChanged(); + QmlContext *windowContext = new QmlContext(engine->rootContext()); + windowContext->setContextProperty("palette", new CustomPalette); - //set device brightness - ... - } + QmlComponent component(&engine, "main.qml"); + QObject *window = component.create(windowContext); } \endcode -\note One important thing to keep in mind is that the changed signal should only be emitted when there is a real change ( \c b \c != \c m_brightness ), or you may get an infinite loop. +The QML that follows references the palette object, and its properties, to set the appropriate +background and text colors. When the window is clicked, the palette's text color is changed, and +the window text will update accordingly. -Next, make an instance of this class visible to the QML bind engine: \code -QmlView *view = new QmlView; -view->setUrl("MyUI.qml"); - -MyScreen *screen = new MyScreen; -QmlContext *ctxt = view->rootContext(); -ctxt->setContextProperty("screen", screen); +// main.qml +import Qt 4.6 + +Rectangle { + width: 240 + height: 320 + color: palette.background + + Text { + anchors.centerIn: parent + color: palette.text + text: "Hello Colorful World!" + } -view->execute(); + MouseRegion { + anchors.fill: parent + onClicked: { + palette.text = "blue"; + } + } +} \endcode +\endtable -\note Bindings must be made after setUrl() but before execute(). +To detect when a C++ property value - in this case the \c CustomPalette's \c text property - +changes, the property must have a corresponding NOTIFY signal. The NOTIFY signal specifies a signal +that is emitted whenever the property changes value. Implementers should take care to only emit the +signal if the value \e changes to prevent loops from occuring. Accessing a property from a +binding that does not have a NOTIFY signal will cause QML to issue a warning at runtime. -Finally, in QML you can make the appropriate bindings, so in \c "MyUI.qml": +\section2 Dynamic Structured Data -\code -Slider { value: screen.brightness } -Binding { target: screen; property: "brightness"; value: slider.value } -\endcode +If an application is too dynamic to structure data as compile-time QObject types, dynamically +structured data can be constructed at runtime using the QBindableMap class. -The \l QBindableMap class provides a convenient way to make data visible to the bind engine. +\section1 Network Components + +If the URL passed to QmlComponent is a network resource, or if the QML document references a +network resource, the QmlComponent has to fetch the network data before it is able to create +objects. In this case, the QmlComponent will have a \l {QmlComponent::Loading}{Loading} +\l {QmlComponent::status()}{status}. An application will have to wait until the component +is \l {QmlComponent::Ready}{Ready} before calling \l {QmlComponent::create()}. + +The following example shows how to load a QML file from a network resource. After creating +the QmlComponent, it tests whether the component is loading. If it is, it connects to the +QmlComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method +directly. This test is necessary, even for URLs that are known to be remote, just in case +the component has been cached and is ready immediately. -C++ \l {qmlmodels}{Data Models} may also be provided to QML. +\code +MyApplication::MyApplication() +{ + // ... + component = new QmlComponent(engine, QUrl("http://www.example.com/main.qml")); + if (component->isLoading()) + QObject::connect(component, SIGNAL(statusChanged(QmlComponent::Status)), + this, SLOT(continueLoading())); + else + continueLoading(); +} +void MyApplication::continueLoading() +{ + if (component->isError()) { + qWarning() << component->errors(); + } else { + QObject *myObject = component->create(); + } +} +\endcode */ + -- cgit v0.12 From e624ddad35939517b6efbd35ee3112f6cac62ae4 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 21 Oct 2009 12:27:07 +1000 Subject: Doc --- doc/src/declarative/qtbinding.qdoc | 2 +- src/declarative/util/qmlpropertymap.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/src/declarative/qtbinding.qdoc b/doc/src/declarative/qtbinding.qdoc index 86acf9f..18685ac 100644 --- a/doc/src/declarative/qtbinding.qdoc +++ b/doc/src/declarative/qtbinding.qdoc @@ -222,7 +222,7 @@ binding that does not have a NOTIFY signal will cause QML to issue a warning at \section2 Dynamic Structured Data If an application is too dynamic to structure data as compile-time QObject types, dynamically -structured data can be constructed at runtime using the QBindableMap class. +structured data can be constructed at runtime using the QmlPropertyMap class. \section1 Network Components diff --git a/src/declarative/util/qmlpropertymap.cpp b/src/declarative/util/qmlpropertymap.cpp index e23eebf..0a92a8b 100644 --- a/src/declarative/util/qmlpropertymap.cpp +++ b/src/declarative/util/qmlpropertymap.cpp @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE -//QBindableMapMetaObject lets us listen for changes coming from QML +//QmlPropertyMapMetaObject lets us listen for changes coming from QML //so we can emit the changed signal. class QmlPropertyMapMetaObject : public QmlOpenMetaObject { @@ -87,17 +87,17 @@ void QmlPropertyMapMetaObject::propertyWrite(int index) } /*! - \class QBindableMap - \brief The QBindableMap class allows you to set key-value pairs that can be used in bindings. + \class QmlPropertyMap + \brief The QmlPropertyMap class allows you to set key-value pairs that can be used in bindings. - QBindableMap provides a convenient way to expose domain data to the UI layer. + QmlPropertyMap provides a convenient way to expose domain data to the UI layer. The following example shows how you might declare data in C++ and then access it in QML. Setup in C++: \code //create our data - QBindableMap ownerData; + QmlPropertyMap ownerData; ownerData.setValue("name", QVariant(QString("John Smith"))); ownerData.setValue("phone", QVariant(QString("555-5555"))); @@ -190,7 +190,7 @@ QStringList QmlPropertyMap::keys() const } /*! - \fn void QBindableMap::changed(const QString &key) + \fn void QmlPropertyMap::changed(const QString &key) This signal is emitted whenever one of the values in the map is changed. \a key is the key corresponding to the value that was changed. */ -- cgit v0.12 From 2b469742848c6cb26daab9d5c72e512473dede2b Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 21 Oct 2009 12:37:19 +1000 Subject: Doc --- doc/src/declarative/qmlformat.qdoc | 350 --------------------------------- doc/src/declarative/qtdeclarative.qdoc | 11 +- 2 files changed, 3 insertions(+), 358 deletions(-) delete mode 100644 doc/src/declarative/qmlformat.qdoc diff --git a/doc/src/declarative/qmlformat.qdoc b/doc/src/declarative/qmlformat.qdoc deleted file mode 100644 index 72bbe40..0000000 --- a/doc/src/declarative/qmlformat.qdoc +++ /dev/null @@ -1,350 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! -\page qmlformat.html -\title QML Format Reference - -\tableofcontents - -\section1 Overview - -QML is an extension to \l {http://www.ecma-international.org/publications/standards/Ecma-262.htm} -{ECMAScript}. QML adds a mechanism for declaratively building a tree of objects, improved -integration between ECMAScript and Qt's existing QObject based type system, and support for -transparently maintained property value bindings between ECMAScript expressions and QObject -properties. - -Much of a QML file consists of valid ECMAScript \e {Statement}s. Except where constraints imposed -by ECMAScript, C++ or QObject prevented it, the syntactic extensions introduced by QML are designed -to look similar and fit well with existing ECMAScript syntax and concepts. - -\section1 QML engine - -The \l {QmlEngine}{QML engine} executes a \l {QmlComponent}{QML document} in a -\l {QmlContext}{QML context} to produce a \l {QObject}{QML object}. A single QML -document may be executed in one or many contexts to produce many QML objects. A single -QML document may be executed many times in the same context to produce many QML objects. - -The QML engine provides the environment in which QML documents, contexts and objects -exist. It must exist before any of these structures can be created. If the engine is removed, -existing documents, contexts and objects are invalidated, but not destroyed. An invalid - -\list -\i \e {QML document} can no longer be used to create QML objects. -\i \e {QML context} can no longer host QML objects, new context properties cannot be added -and existing context properties cannot be modified. -\i \e {QML object} will no longer evaluate bindings or scripts. -\endlist - -A QML document is a block of QML source code. QML documents generally correspond to files stored -on a disk or network resource, but can be constructed directly from text data. Syntactically a QML -document is self contained; QML does \bold {not} have a preprocessor that modifies the document -before presentation to the compiler. Type references within a QML document are resolved based -exclusively on the import statements present in the document. - -A simple QML document looks like this: - -\table -\row -\o -\code -import Qt 4.6 - -Rectangle { - id: myRect - width: 100; height: 100 - color: background -} -\endcode -\endtable - -To instantiate a QML object, a QML document is executed in a QML context. QML contexts are used by -programmers to pass data to a QML document. QML documents may include property bindings or -ECMAScript blocks that can contain variable references that need to be resolved. Each property -binding and ECMAScript block has an associated QML context that is used to resolve these references -that is determined by the QML context in which the document is executed. The example document above -contains one variable reference, \c background. - -Each QML context defines a scope for variable resolution and each may define local, named context -properties. A QML context may also have a \l {QmlContext::addDefaultObject()}{default object}, -which is an object whose properties are searched \e after the context properties when resolving a -variable name. QML contexts form a tree, starting from a root context that is provided by the QML -engine. When resolving variable references, the QML contexts are searched starting from the -QML objects containing context upwards towards the root context. - -Consider the following QML context tree. If the example QML document is executed in \c Context1, -the \c background variable will resolve to \c Context1's context property. If the document is -executed in \c Context2, the \c background variable will resolve to the root context's context -property. - -\image qml-context-tree.png - -While QML contexts can be created explicitly by the programmer to pass data into QML objects, -the QML engine also creates a new implicit QML context for every object it instantiates. -Property bindings and ECMAScript blocks in the document are associated with this QML engine -created context. Object ids that are defined in the document are added as context properties, and -their value is set to reference the appropriate object, and the instantiated QML object is set as -the context's default object. The following diagram shows the result of executing a simple QML -document. - -\image qml-context-object.png - -The blue rectangle in the diagram represents a property binding. Associated with each property -binding is the QML context to which it belongs, the object property to which it is bound and a -\e {scope object}. The scope object is usually, but not always, the object to which the bound -property belongs. The context properties, context default objects and the scope object are all -involved when resolving a variable name in a binding. The following pseudo code describes the -algorithm used: - -\table -\row -\o -\code -if (scopeObject.hasProperty(name)) - return scopeObject.property(name) - -foreach (context in contextChain) { - if (context.hasContextProperty(name) - return context.contextProperty(name) - - if (context.defaultObject.hasProperty(name)) - return context.defaultObject.property(name) -} -\endcode -\endtable - -QML supports two categories of types: \e builtin types and \e composite types. Builtin types are -those written in C++ and registered with the QML engine. Builtin types form the most basic -building blocks of QML. Composite types are constructed by composing other builtin or composite -types, property bindings and ECMAScript blocks together into a brand new type using the QML -language. Using a composite type is identical to using a builtin type. - -For example, Qt 4.6 includes a builtin type called \c Image that shows a bitmap image. The -\c Image type has \c width and \c height properties that control the size of the displayed image. -A simple composite type, that will be called \c SquareImage can be built that adds a \c size -property that sets both the width and the height. - -\table -\row -\o -\code -import Qt 4.6 -Image { - property int size - width: size - height: size -} -\endcode -\endtable - -To the QML engine, a composite type is just another QML document. When a composite type is -used the engine instantiates it just as it would any other document - by creating a new implicit -QML context and the object tree described by the document. The diagram below shows the -\c SquareImage composite type used from within another QML document. When instantiated, the -\c SquareImage object is created in its own QML context. Any property bindings specified in the -\c SquareImage composite type document are associated with this context. Property bindings created -in the outer document, however, are associated with its context, even those that are applied to the -created \c SquareImage object. That is, the \c size, \c source, \c width and \c height property -bindings all share a common \e {scope object}, but are owned by two different QML contexts. The -difference in containing context results in the \c Root variable resolving differently in the -different property bindings. - -\image qml-context.png - -\section1 Syntax - -\section2 Encoding - -QML files are always encoded in UTF-8 format. - -\section2 Commenting - -The commenting rules in QML are the same as for ECMAScript. Both \e {MultiLineComment} blocks and \e {SingleLineComment}'s are supported. - -\section2 QML Document - -\section3 Syntax - -\e {QMLDocument} \bold {:} - -\quotation -\e {QMLImportList} \sub {opt} \e {QMLObjectDefinition} -\endquotation - -\e {QMLImportList} \bold {:} -\quotation -\e {QMLImportStatement} \e {QMLImportList} \sub {opt} -\endquotation - -\e {QMLImportStatement} \bold {:} - -\quotation -\bold {import} \e {StringLiteral} - -\bold {import} \e {StringLiteral} \e {QMLVersionNumber} - -\bold {import} \e {QMLNamespaceName} \e {QMLVersionNumber} - -\bold {import} \e {StringLiteral} \bold {as} \e {QMLNamespacePrefix} - -\bold {import} \e {StringLiteral} \e {QMLVersionNumber} \bold {as} \e {QMLNamespacePrefix} - -\bold {import} \e {QMLNamespaceName} \e {QMLVersionNumber} \bold {as} \e {QMLNamespacePrefix} -\endquotation - -\e {QMLNamespaceName} \bold {:} -\quotation -\e {QMLQualifiedId} -\endquotation - -\e {QMLVersionNumber} \bold {:} -\quotation -\e {DecimalLiteral} \bold {but not} with \e {ExponentPart} -\endquotation - -\section3 Semantics - -The \e {QMLImportList} is used to statically resolve type references used within the enclosing -QML document. - -An import statement is used to bring a set of types into scope for a QML document. - -\section2 Object Definition - -\section3 Syntax - -\e {QMLObjectDefinition} \bold {:} -\quotation -\e {QMLQualifiedId} \bold {\{} \e {QMLObjectMemberList} \bold {\}} -\endquotation - -\e {QMLObjectMemberList} \bold {:} -\quotation -\e {QMLObjectMember} \e {QMLObjectMemberList} \sub {opt} -\endquotation - -\e {QMLObjectMember} \bold {:} -\quotation -\e {QMLMemberAssignment} - -\e {QMLObjectDefinition} - -\e {QMLObjectExtensionDefinition} -\endquotation - -\e {QMLMemberAssignmentList} \bold {:} -\quotation -\e {QMLMemberAssignment} \e {QMLMemberAssignmentList} \sub {opt} -\endquotation - -\e {QMLMemberAssignment} \bold {:} -\quotation - -\e {QMLQualifiedId} \bold {:} \e {Literal} \bold {but not} \e {NullLiteral} - -\e {QMLQualifiedId} \bold {:} \e {QMLObjectDefinition} - -\e {QMLQualifiedId} \bold {:} \e {QMLObjectDefinitionArray} - -\e {QMLQualifiedId} \bold {:} \e {QMLBindingExpression} - -\e {QMLQualifiedId} \bold {\{} \e {QMLMemberAssignmentList} \bold {\}} - -\endquotation - -\section3 Semantics - -\section2 Object Extension - -\section3 Syntax - -\e {QMLObjectExtensionDefinition} \bold {:} -\quotation -\e {QMLObjectPropertyDefinition} - -\e {QMLObjectSignalDefinition} - -\e {QMLObjectMethodDefinition} -\endquotation - -\e {QMLObjectPropertyDefinition} \bold {:} -\quotation -\bold {property} \e {QmlObjectPropertyType} \e {QMLMemberIdentifier} - -\bold {default} \bold {property} \e {QmlObjectPropertyType} \e {QMLMemberIdentifier} - -\bold {property} \e {QmlObjectPropertyType} \e {QMLMemberIdentifier} \bold {:} \e {Literal} \bold {but not} \e {NullLiteral} - -\bold {property} \e {QmlObjectPropertyType} \e {QMLMemberIdentifier} \bold {:} \e {QmlBindingExpression} - -\bold {default} \bold {property} \e {QmlObjectPropertyType} \e {QMLMemberIdentifier} \bold {:} \e {Literal} \bold {but not} \e {NullLiteral} - -\bold {default} \bold {property} \e {QmlObjectPropertyType} \e {QMLMemberIdentifier} \bold {:} \e {QmlBindingExpression} -\endquotation - -\e {QMLObjectPropertyType} \bold {:: one of} -\quotation -\bold {int} \bold {bool} \bold {double} \bold {real} \bold {string} \bold {url} \bold {color} \bold {date} \bold {var} \bold {variant} \bold {alias} -\endquotation - -\e {QMLObjectSignalDefinition} \bold {:} -\quotation -\bold {signal} \e {QMLMemberIdentifier} - -\bold {signal} \e {QMLMemberIdentifier} \bold {(} QMLMemberTypedParameterList \bold {)} -\endquotation - -\e {QMLObjectMethodDefinition} \bold {:} -\quotation -\e {FunctionDeclaration} \bold {but not} \e {Identifier} \sub {opt} -\endquotation -\section3 Semantics - -\section2 Binding Expression - -\section3 Syntax - -\e {QMLBindingExpression} \bold {:} - -\section3 Semantics - -*/ diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc index ebf7880..e01b02d 100644 --- a/doc/src/declarative/qtdeclarative.qdoc +++ b/doc/src/declarative/qtdeclarative.qdoc @@ -93,20 +93,15 @@ completely new applications. QML is fully \l {Extending QML}{extensible from C+ \o \l {Extending types from QML} \endlist -\section1 QML Reference: +\section1 Reference: \list -\o \l {QML Format Reference} \o \l {QML Elements} -\endlist - -\section1 C++ Reference: -\list \o \l {Extending QML} -\o \l {qtbinding}{QML/C++ Data Binding} \endlist \section1 Deprecated - +\list \o \l {tutorials-declarative-contacts.html}{Tutorial: 'Introduction to QML'} +\endlist */ -- cgit v0.12 From 4aa8830c0f5ea4f2337a87ea9f467f687ad9ff77 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Wed, 21 Oct 2009 13:13:30 +1000 Subject: better property-animation example --- examples/declarative/animation/animation.qml | 63 ------------- examples/declarative/animation/easing.qml | 99 +++++++++++++++++++++ .../declarative/animation/images/face-laugh.png | Bin 0 -> 16132 bytes .../declarative/animation/images/face-smile.png | Bin 0 -> 15408 bytes examples/declarative/animation/images/shadow.png | Bin 0 -> 425 bytes .../declarative/animation/property-animation.qml | 64 +++++++++++++ examples/declarative/easing/easing.qml | 99 --------------------- 7 files changed, 163 insertions(+), 162 deletions(-) delete mode 100644 examples/declarative/animation/animation.qml create mode 100644 examples/declarative/animation/easing.qml create mode 100644 examples/declarative/animation/images/face-laugh.png create mode 100644 examples/declarative/animation/images/face-smile.png create mode 100644 examples/declarative/animation/images/shadow.png create mode 100644 examples/declarative/animation/property-animation.qml delete mode 100644 examples/declarative/easing/easing.qml diff --git a/examples/declarative/animation/animation.qml b/examples/declarative/animation/animation.qml deleted file mode 100644 index 31c75e1..0000000 --- a/examples/declarative/animation/animation.qml +++ /dev/null @@ -1,63 +0,0 @@ -import Qt 4.6 - -Rectangle { - width: 400 - height: 200 - color: "white" - - Rectangle { - width: 40 - height: 40 - y: 80 - color: "#FF0000" - radius: 10 - - // Animate the x property. Setting repeat to true makes the - // animation repeat indefinitely, otherwise it would only run once. - x: SequentialAnimation { - running: true - repeat: true - - // Move from 0 to 360 in 500ms, using the easeInOutQuad easing function - NumberAnimation { - from: 0 - to: 360 - easing: "easeInOutQuad" - duration: 500 - } - - // Then pause for 200ms - PauseAnimation { - duration: 200 - } - - // Then move back to 0 in 2 seconds, using the easeInOutElastic easing function - NumberAnimation { - from: 360 - to: 0 - easing: "easeInOutElastic" - duration: 2000 - } - } - - // Alternate color between red and green - color: SequentialAnimation { - running: true - repeat: true - - ColorAnimation { - property: "color" - from: "#FF0000" - to: "#00FF00" - duration: 5000 - } - - ColorAnimation { - property: "color" - from: "#00FF00" - to: "#FF0000" - duration: 5000 - } - } - } -} diff --git a/examples/declarative/animation/easing.qml b/examples/declarative/animation/easing.qml new file mode 100644 index 0000000..100d5d2 --- /dev/null +++ b/examples/declarative/animation/easing.qml @@ -0,0 +1,99 @@ +import Qt 4.6 + +Rectangle { + id: window + width: 600; height: 460; color: "#232323" + + ListModel { + id: easingTypes + ListElement { type: "easeLinear"; ballColor: "DarkRed" } + ListElement { type: "easeInQuad"; ballColor: "IndianRed" } + ListElement { type: "easeOutQuad"; ballColor: "Salmon" } + ListElement { type: "easeInOutQuad"; ballColor: "Tomato" } + ListElement { type: "easeOutInQuad"; ballColor: "DarkOrange" } + ListElement { type: "easeInCubic"; ballColor: "Gold" } + ListElement { type: "easeOutCubic"; ballColor: "Yellow" } + ListElement { type: "easeInOutCubic"; ballColor: "PeachPuff" } + ListElement { type: "easeOutInCubic"; ballColor: "Thistle" } + ListElement { type: "easeInQuart"; ballColor: "Orchid" } + ListElement { type: "easeOutQuart"; ballColor: "Purple" } + ListElement { type: "easeInOutQuart"; ballColor: "SlateBlue" } + ListElement { type: "easeOutInQuart"; ballColor: "Chartreuse" } + ListElement { type: "easeInQuint"; ballColor: "LimeGreen" } + ListElement { type: "easeOutQuint"; ballColor: "SeaGreen" } + ListElement { type: "easeInOutQuint"; ballColor: "DarkGreen" } + ListElement { type: "easeOutInQuint"; ballColor: "Olive" } + ListElement { type: "easeInSine"; ballColor: "DarkSeaGreen" } + ListElement { type: "easeOutSine"; ballColor: "Teal" } + ListElement { type: "easeInOutSine"; ballColor: "Turquoise" } + ListElement { type: "easeOutInSine"; ballColor: "SteelBlue" } + ListElement { type: "easeInExpo"; ballColor: "SkyBlue" } + ListElement { type: "easeOutExpo"; ballColor: "RoyalBlue" } + ListElement { type: "easeInOutExpo"; ballColor: "MediumBlue" } + ListElement { type: "easeOutInExpo"; ballColor: "MidnightBlue" } + ListElement { type: "easeInCirc"; ballColor: "CornSilk" } + ListElement { type: "easeOutCirc"; ballColor: "Bisque" } + ListElement { type: "easeInOutCirc"; ballColor: "RosyBrown" } + ListElement { type: "easeOutInCirc"; ballColor: "SandyBrown" } + ListElement { type: "easeInElastic"; ballColor: "DarkGoldenRod" } + ListElement { type: "easeOutElastic"; ballColor: "Chocolate" } + ListElement { type: "easeInOutElastic"; ballColor: "SaddleBrown" } + ListElement { type: "easeOutInElastic"; ballColor: "Brown" } + ListElement { type: "easeInBack"; ballColor: "Maroon" } + ListElement { type: "easeOutBack"; ballColor: "LavenderBlush" } + ListElement { type: "easeInOutBack"; ballColor: "MistyRose" } + ListElement { type: "easeOutInBack"; ballColor: "Gainsboro" } + ListElement { type: "easeOutBounce"; ballColor: "Silver" } + ListElement { type: "easeInBounce"; ballColor: "DimGray" } + ListElement { type: "easeInOutBounce"; ballColor: "SlateGray" } + ListElement { type: "easeOutInBounce"; ballColor: "DarkSlateGray" } + } + + Component { + id: delegate + + Item { + height: 42; width: window.width + Text { text: type; anchors.centerIn: parent; color: "White" } + Rectangle { + id: slot1; color: "#121212"; x: 10; height: 32; width: 32 + border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter + } + Rectangle { + id: slot2; color: "#121212"; x: window.width - 42; height: 32; width: 32 + border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter + } + Rectangle { + id: rect; x: 10; color: "#454545" + border.color: "White"; border.width: 2 + height: 32; width: 32; radius: 8; anchors.verticalCenter: parent.verticalCenter + + MouseRegion { + onClicked: if (rect.state == '') rect.state = "right"; else rect.state = '' + anchors.fill: parent + } + + states : State { + name: "right" + PropertyChanges { target: rect; x: window.width - 42; color: ballColor } + } + + transitions: Transition { + ParallelAnimation { + NumberAnimation { properties: "x"; easing: type; duration: 1000 } + ColorAnimation { properties: "color"; easing: type; duration: 1000 } + } + } + } + } + } + + Flickable { + anchors.fill: parent; viewportHeight: layout.height + Column { + id: layout + anchors.left: window.left; anchors.right: window.right + Repeater { model: easingTypes; delegate: delegate } + } + } +} diff --git a/examples/declarative/animation/images/face-laugh.png b/examples/declarative/animation/images/face-laugh.png new file mode 100644 index 0000000..7a22b07 Binary files /dev/null and b/examples/declarative/animation/images/face-laugh.png differ diff --git a/examples/declarative/animation/images/face-smile.png b/examples/declarative/animation/images/face-smile.png new file mode 100644 index 0000000..3d66d72 Binary files /dev/null and b/examples/declarative/animation/images/face-smile.png differ diff --git a/examples/declarative/animation/images/shadow.png b/examples/declarative/animation/images/shadow.png new file mode 100644 index 0000000..8270565 Binary files /dev/null and b/examples/declarative/animation/images/shadow.png differ diff --git a/examples/declarative/animation/property-animation.qml b/examples/declarative/animation/property-animation.qml new file mode 100644 index 0000000..4e0f6f4 --- /dev/null +++ b/examples/declarative/animation/property-animation.qml @@ -0,0 +1,64 @@ +import Qt 4.6 + +Item { + id: window + width: 320; height: 480 + + // Let's draw the sky... + Rectangle { + anchors { left: parent.left; top: parent.top; right: parent.right; bottom: parent.verticalCenter } + gradient: Gradient { + GradientStop { position: 0.0; color: "DeepSkyBlue" } + GradientStop { position: 1.0; color: "LightSkyBlue" } + } + } + + // ...and the ground. + Rectangle { + anchors { left: parent.left; top: parent.verticalCenter; right: parent.right; bottom: parent.bottom } + gradient: Gradient { + GradientStop { position: 0.0; color: "ForestGreen" } + GradientStop { position: 1.0; color: "DarkGreen" } + } + } + + // The shadow for the smiley face + Image { + anchors.horizontalCenter: parent.horizontalCenter + source: "images/shadow.png"; y: smiley.minHeight + 58 + transformOrigin: "Center" + + // The scale property depends on the y position of the smiley face. + scale: smiley.y * 0.5 / (smiley.minHeight - smiley.maxHeight) + } + + Image { + id: smiley + property int maxHeight: window.height / 3 + property int minHeight: 2 * window.height / 3 + + anchors.horizontalCenter: parent.horizontalCenter + source: "images/face-smile.png"; y: minHeight + + // Animate the y property. Setting repeat to true makes the + // animation repeat indefinitely, otherwise it would only run once. + y: SequentialAnimation { + running: true; repeat: true + + // Move from minHeight to maxHeight in 300ms, using the easeOutExpo easing function + NumberAnimation { + from: smiley.minHeight; to: smiley.maxHeight + easing: "easeOutExpo"; duration: 300 + } + + // Then move back to minHeight in 1 second, using the easeOutBounce easing function + NumberAnimation { + from: smiley.maxHeight; to: smiley.minHeight + easing: "easeOutBounce"; duration: 1000 + } + + // Then pause for 500ms + PauseAnimation { duration: 500 } + } + } +} diff --git a/examples/declarative/easing/easing.qml b/examples/declarative/easing/easing.qml deleted file mode 100644 index 100d5d2..0000000 --- a/examples/declarative/easing/easing.qml +++ /dev/null @@ -1,99 +0,0 @@ -import Qt 4.6 - -Rectangle { - id: window - width: 600; height: 460; color: "#232323" - - ListModel { - id: easingTypes - ListElement { type: "easeLinear"; ballColor: "DarkRed" } - ListElement { type: "easeInQuad"; ballColor: "IndianRed" } - ListElement { type: "easeOutQuad"; ballColor: "Salmon" } - ListElement { type: "easeInOutQuad"; ballColor: "Tomato" } - ListElement { type: "easeOutInQuad"; ballColor: "DarkOrange" } - ListElement { type: "easeInCubic"; ballColor: "Gold" } - ListElement { type: "easeOutCubic"; ballColor: "Yellow" } - ListElement { type: "easeInOutCubic"; ballColor: "PeachPuff" } - ListElement { type: "easeOutInCubic"; ballColor: "Thistle" } - ListElement { type: "easeInQuart"; ballColor: "Orchid" } - ListElement { type: "easeOutQuart"; ballColor: "Purple" } - ListElement { type: "easeInOutQuart"; ballColor: "SlateBlue" } - ListElement { type: "easeOutInQuart"; ballColor: "Chartreuse" } - ListElement { type: "easeInQuint"; ballColor: "LimeGreen" } - ListElement { type: "easeOutQuint"; ballColor: "SeaGreen" } - ListElement { type: "easeInOutQuint"; ballColor: "DarkGreen" } - ListElement { type: "easeOutInQuint"; ballColor: "Olive" } - ListElement { type: "easeInSine"; ballColor: "DarkSeaGreen" } - ListElement { type: "easeOutSine"; ballColor: "Teal" } - ListElement { type: "easeInOutSine"; ballColor: "Turquoise" } - ListElement { type: "easeOutInSine"; ballColor: "SteelBlue" } - ListElement { type: "easeInExpo"; ballColor: "SkyBlue" } - ListElement { type: "easeOutExpo"; ballColor: "RoyalBlue" } - ListElement { type: "easeInOutExpo"; ballColor: "MediumBlue" } - ListElement { type: "easeOutInExpo"; ballColor: "MidnightBlue" } - ListElement { type: "easeInCirc"; ballColor: "CornSilk" } - ListElement { type: "easeOutCirc"; ballColor: "Bisque" } - ListElement { type: "easeInOutCirc"; ballColor: "RosyBrown" } - ListElement { type: "easeOutInCirc"; ballColor: "SandyBrown" } - ListElement { type: "easeInElastic"; ballColor: "DarkGoldenRod" } - ListElement { type: "easeOutElastic"; ballColor: "Chocolate" } - ListElement { type: "easeInOutElastic"; ballColor: "SaddleBrown" } - ListElement { type: "easeOutInElastic"; ballColor: "Brown" } - ListElement { type: "easeInBack"; ballColor: "Maroon" } - ListElement { type: "easeOutBack"; ballColor: "LavenderBlush" } - ListElement { type: "easeInOutBack"; ballColor: "MistyRose" } - ListElement { type: "easeOutInBack"; ballColor: "Gainsboro" } - ListElement { type: "easeOutBounce"; ballColor: "Silver" } - ListElement { type: "easeInBounce"; ballColor: "DimGray" } - ListElement { type: "easeInOutBounce"; ballColor: "SlateGray" } - ListElement { type: "easeOutInBounce"; ballColor: "DarkSlateGray" } - } - - Component { - id: delegate - - Item { - height: 42; width: window.width - Text { text: type; anchors.centerIn: parent; color: "White" } - Rectangle { - id: slot1; color: "#121212"; x: 10; height: 32; width: 32 - border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter - } - Rectangle { - id: slot2; color: "#121212"; x: window.width - 42; height: 32; width: 32 - border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter - } - Rectangle { - id: rect; x: 10; color: "#454545" - border.color: "White"; border.width: 2 - height: 32; width: 32; radius: 8; anchors.verticalCenter: parent.verticalCenter - - MouseRegion { - onClicked: if (rect.state == '') rect.state = "right"; else rect.state = '' - anchors.fill: parent - } - - states : State { - name: "right" - PropertyChanges { target: rect; x: window.width - 42; color: ballColor } - } - - transitions: Transition { - ParallelAnimation { - NumberAnimation { properties: "x"; easing: type; duration: 1000 } - ColorAnimation { properties: "color"; easing: type; duration: 1000 } - } - } - } - } - } - - Flickable { - anchors.fill: parent; viewportHeight: layout.height - Column { - id: layout - anchors.left: window.left; anchors.right: window.right - Repeater { model: easingTypes; delegate: delegate } - } - } -} -- cgit v0.12 From 5e328ec98175d4b1b5873e415f1cb858675f97a4 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Wed, 21 Oct 2009 13:14:19 +1000 Subject: delete unused file --- examples/declarative/animation/images/face-laugh.png | Bin 16132 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/declarative/animation/images/face-laugh.png diff --git a/examples/declarative/animation/images/face-laugh.png b/examples/declarative/animation/images/face-laugh.png deleted file mode 100644 index 7a22b07..0000000 Binary files a/examples/declarative/animation/images/face-laugh.png and /dev/null differ -- cgit v0.12 From 8214235eac6a3ca5dbe18558aea29c613a07b34f Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Wed, 21 Oct 2009 13:17:13 +1000 Subject: fix easing example --- examples/declarative/animation/easing.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/declarative/animation/easing.qml b/examples/declarative/animation/easing.qml index 100d5d2..9e0a0d6 100644 --- a/examples/declarative/animation/easing.qml +++ b/examples/declarative/animation/easing.qml @@ -56,15 +56,15 @@ Rectangle { height: 42; width: window.width Text { text: type; anchors.centerIn: parent; color: "White" } Rectangle { - id: slot1; color: "#121212"; x: 10; height: 32; width: 32 + id: slot1; color: "#121212"; x: 30; height: 32; width: 32 border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter } Rectangle { - id: slot2; color: "#121212"; x: window.width - 42; height: 32; width: 32 + id: slot2; color: "#121212"; x: window.width - 62; height: 32; width: 32 border.color: "#343434"; border.width: 1; radius: 8; anchors.verticalCenter: parent.verticalCenter } Rectangle { - id: rect; x: 10; color: "#454545" + id: rect; x: 30; color: "#454545" border.color: "White"; border.width: 2 height: 32; width: 32; radius: 8; anchors.verticalCenter: parent.verticalCenter @@ -75,7 +75,7 @@ Rectangle { states : State { name: "right" - PropertyChanges { target: rect; x: window.width - 42; color: ballColor } + PropertyChanges { target: rect; x: window.width - 62; color: ballColor } } transitions: Transition { -- cgit v0.12 From 96317e0ce99e732e220907e0adc3214bd754e8d4 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 21 Oct 2009 13:30:52 +1000 Subject: Remove dead code --- src/declarative/qml/qmlengine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 528e8c9..b9dca83 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -158,7 +158,6 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); - //scriptEngine.globalObject().setScriptClass(new QmlGlobalScriptClass(&scriptEngine)); globalClass = new QmlGlobalScriptClass(&scriptEngine); } -- cgit v0.12 From 9cf03f5afce1f46566bc3712fc7c567e990193ca Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 21 Oct 2009 13:52:11 +1000 Subject: Add simple sound support --- src/declarative/qml/qmlengine.cpp | 32 ++++++++++++++++++++++++++++++++ src/declarative/qml/qmlengine_p.h | 2 ++ 2 files changed, 34 insertions(+) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index b9dca83..1d98265 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -76,6 +76,7 @@ #include #include #include +#include #include #include "private/qmlcomponentjs_p.h" #include "private/qmlmetaproperty_p.h" @@ -153,6 +154,9 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) qtObject.setProperty(QLatin1String("darker"), scriptEngine.newFunction(QmlEnginePrivate::darker, 1)); qtObject.setProperty(QLatin1String("tint"), scriptEngine.newFunction(QmlEnginePrivate::tint, 2)); + //misc methods + qtObject.setProperty(QLatin1String("playSound"), scriptEngine.newFunction(QmlEnginePrivate::playSound, 1)); + scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), scriptEngine.newFunction(QmlEnginePrivate::createQmlObject, 1)); scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), @@ -835,6 +839,34 @@ QScriptValue QmlEnginePrivate::darker(QScriptContext *ctxt, QScriptEngine *engin return qScriptValueFromValue(engine, qVariantFromValue(color)); } +QScriptValue QmlEnginePrivate::playSound(QScriptContext *ctxt, QScriptEngine *engine) +{ + if (ctxt->argumentCount() < 1) + return engine->undefinedValue(); + + QUrl url(ctxt->argument(0).toString()); + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + if (url.isRelative()) { + QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == enginePriv->contextClass); + + QmlContext *context = enginePriv->contextClass->contextFromValue(scopeNode); + if (!context) + return engine->undefinedValue(); + + url = context->resolvedUrl(url); + } + + if (url.scheme() == QLatin1String("file")) { + + QSound::play(url.toLocalFile()); + + } + return engine->undefinedValue(); +} + /*! This function allows tinting one color with another. diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index a85ac55..07ac928 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -259,6 +259,8 @@ public: static QScriptValue darker(QScriptContext*, QScriptEngine*); static QScriptValue tint(QScriptContext*, QScriptEngine*); + static QScriptValue playSound(QScriptContext*, QScriptEngine*); + static QScriptEngine *getScriptEngine(QmlEngine *e) { return &e->d_func()->scriptEngine; } static QmlEngine *getEngine(QScriptEngine *e) { return static_cast(e)->p->q_func(); } static QmlEnginePrivate *get(QmlEngine *e) { return e->d_func(); } -- cgit v0.12 From 43a14672531040abd285d3004d27c3f1c95a699b Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 21 Oct 2009 13:56:12 +1000 Subject: Doc --- src/declarative/qml/qmlengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 1d98265..3cd66aa 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -650,7 +650,7 @@ QScriptValue QmlEnginePrivate::createComponent(QScriptContext *ctxt, Example (where targetItem is the id of an existing QML item): \code - newObject = createQmlObject('Rectangle {color: "red"; width: 20; height: 20}', + newObject = createQmlObject('import Qt 4.6; Rectangle {color: "red"; width: 20; height: 20}', targetItem, "dynamicSnippet1"); \endcode -- cgit v0.12 From 2b7c33da538e1fd596c679a089c1949cc8651103 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Wed, 21 Oct 2009 14:43:22 +1000 Subject: add color-animation example --- examples/declarative/animation/color-animation.qml | 72 +++++++++++++++++++++ examples/declarative/animation/images/moon.png | Bin 0 -> 2433 bytes examples/declarative/animation/images/star.png | Bin 0 -> 349 bytes examples/declarative/animation/images/sun.png | Bin 0 -> 8153 bytes 4 files changed, 72 insertions(+) create mode 100644 examples/declarative/animation/color-animation.qml create mode 100644 examples/declarative/animation/images/moon.png create mode 100644 examples/declarative/animation/images/star.png create mode 100644 examples/declarative/animation/images/sun.png diff --git a/examples/declarative/animation/color-animation.qml b/examples/declarative/animation/color-animation.qml new file mode 100644 index 0000000..04ec0bf --- /dev/null +++ b/examples/declarative/animation/color-animation.qml @@ -0,0 +1,72 @@ +import Qt 4.6 + +Item { + id: window + width: 640; height: 480 + + // Let's draw the sky... + Rectangle { + anchors { left: parent.left; top: parent.top; right: parent.right; bottom: parent.verticalCenter } + gradient: Gradient { + GradientStop { + position: 0.0 + color: SequentialAnimation { + running: true; repeat: true + ColorAnimation { from: "DeepSkyBlue"; to: "#141450"; duration: 5000 } + ColorAnimation { from: "#141450"; to: "DeepSkyBlue"; duration: 5000 } + } + } + GradientStop { + position: 1.0 + color: SequentialAnimation { + running: true; repeat: true + ColorAnimation { from: "SkyBlue"; to: "#437284"; duration: 5000 } + ColorAnimation { from: "#437284"; to: "SkyBlue"; duration: 5000 } + } + } + } + Particles { + anchors.fill:parent; source: "images/star.png"; angleDeviation: 360; velocity: 0 + velocityDeviation: 0; count: parent.width / 10; fadeInDuration: 2800 + opacity: SequentialAnimation { + running: true; repeat: true + NumberAnimation { from: 0; to: 1; duration: 5000 } + NumberAnimation { from: 1; to: 0; duration: 5000 } + } + } + } + + Item { + id: space + width: parent.width; height: 2 * parent.height + transformOrigin: "Center" + rotation: SequentialAnimation { + running: true; repeat: true + NumberAnimation { from: 0; to: 360; duration: 10000 } + } + Image { + source: "images/sun.png"; y: 10; anchors.horizontalCenter: parent.horizontalCenter + transformOrigin: "Center"; rotation: -space.rotation + } + Image { + source: "images/moon.png"; y: parent.height - 74; anchors.horizontalCenter: parent.horizontalCenter + transformOrigin: "Center"; rotation: -space.rotation + } + } + + // ...and the ground. + Rectangle { + anchors { left: parent.left; top: parent.verticalCenter; right: parent.right; bottom: parent.bottom } + gradient: Gradient { + GradientStop { + position: 0.0 + color: SequentialAnimation { + running: true; repeat: true + ColorAnimation { from: "ForestGreen"; to: "#001600"; duration: 5000 } + ColorAnimation { from: "#001600"; to: "ForestGreen"; duration: 5000 } + } + } + GradientStop { position: 1.0; color: "DarkGreen" } + } + } +} diff --git a/examples/declarative/animation/images/moon.png b/examples/declarative/animation/images/moon.png new file mode 100644 index 0000000..9407b2b Binary files /dev/null and b/examples/declarative/animation/images/moon.png differ diff --git a/examples/declarative/animation/images/star.png b/examples/declarative/animation/images/star.png new file mode 100644 index 0000000..27ef924 Binary files /dev/null and b/examples/declarative/animation/images/star.png differ diff --git a/examples/declarative/animation/images/sun.png b/examples/declarative/animation/images/sun.png new file mode 100644 index 0000000..7713ca5 Binary files /dev/null and b/examples/declarative/animation/images/sun.png differ -- cgit v0.12 From 1208d2800d4810a472262d8e04f0cf3a59a3efdb Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 21 Oct 2009 14:57:07 +1000 Subject: Give QmlPropertyMap a more complete API. --- src/declarative/util/qmlopenmetaobject.cpp | 8 ++ src/declarative/util/qmlopenmetaobject.h | 1 + src/declarative/util/qmlpropertymap.cpp | 105 ++++++++++++++++++--- src/declarative/util/qmlpropertymap.h | 14 ++- .../qmlpropertymap/tst_qmlpropertymap.cpp | 51 ++++++++-- 5 files changed, 152 insertions(+), 27 deletions(-) diff --git a/src/declarative/util/qmlopenmetaobject.cpp b/src/declarative/util/qmlopenmetaobject.cpp index 7305362..11648f6 100644 --- a/src/declarative/util/qmlopenmetaobject.cpp +++ b/src/declarative/util/qmlopenmetaobject.cpp @@ -136,6 +136,14 @@ QVariant QmlOpenMetaObject::value(const QByteArray &name) const return d->data.at(*iter); } +QVariant &QmlOpenMetaObject::operator[](const QByteArray &name) +{ + QHash::ConstIterator iter = d->names.find(name); + Q_ASSERT(iter != d->names.end()); + + return d->data[*iter]; +} + void QmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) { QHash::ConstIterator iter = d->names.find(name); diff --git a/src/declarative/util/qmlopenmetaobject.h b/src/declarative/util/qmlopenmetaobject.h index f65660d..be0490d 100644 --- a/src/declarative/util/qmlopenmetaobject.h +++ b/src/declarative/util/qmlopenmetaobject.h @@ -64,6 +64,7 @@ public: void setValue(const QByteArray &, const QVariant &); QVariant value(int) const; void setValue(int, const QVariant &); + QVariant &operator[](const QByteArray &); int count() const; QByteArray name(int) const; diff --git a/src/declarative/util/qmlpropertymap.cpp b/src/declarative/util/qmlpropertymap.cpp index 0a92a8b..a587af3 100644 --- a/src/declarative/util/qmlpropertymap.cpp +++ b/src/declarative/util/qmlpropertymap.cpp @@ -72,7 +72,7 @@ public: void QmlPropertyMapPrivate::emitChanged(const QString &key) { Q_Q(QmlPropertyMap); - emit q->changed(key); + emit q->valueChanged(key); } QmlPropertyMapMetaObject::QmlPropertyMapMetaObject(QmlPropertyMap *obj, QmlPropertyMapPrivate *objPriv) : QmlOpenMetaObject(obj) @@ -98,8 +98,8 @@ void QmlPropertyMapMetaObject::propertyWrite(int index) \code //create our data QmlPropertyMap ownerData; - ownerData.setValue("name", QVariant(QString("John Smith"))); - ownerData.setValue("phone", QVariant(QString("555-5555"))); + ownerData.insert("name", QVariant(QString("John Smith"))); + ownerData.insert("phone", QVariant(QString("555-5555"))); //expose it to the UI layer QmlContext *ctxt = view->bindContext(); @@ -115,16 +115,13 @@ void QmlPropertyMapMetaObject::propertyWrite(int index) The binding is dynamic - whenever a key's value is updated, anything bound to that key will be updated as well. - To detect value changes made in the UI layer you can connect to the changed() signal. - However, note that changed() is \b NOT emitted when changes are made by calling setValue() - or clearValue() - it is only emitted when a value is updated from QML. -*/ + To detect value changes made in the UI layer you can connect to the valueChanged() signal. + However, note that valueChanged() is \b NOT emitted when changes are made by calling insert() + or clear() - it is only emitted when a value is updated from QML. -// is there a more efficient way to store/return keys? -// (or should we just provide an iterator or something else instead?) -// can we provide a way to clear keys? -// do we want to make any claims regarding key ordering? -// should we have signals for insertion and and deletion -- becoming more model like + \note It is not possible to remove keys from the map; once a key has been added, you can only + modify or clear its associated value. +*/ /*! Constructs a bindable map with parent object \a parent. @@ -146,7 +143,7 @@ QmlPropertyMap::~QmlPropertyMap() /*! Clears the value (if any) associated with \a key. */ -void QmlPropertyMap::clearValue(const QString &key) +void QmlPropertyMap::clear(const QString &key) { Q_D(QmlPropertyMap); d->mo->setValue(key.toUtf8(), QVariant()); @@ -169,7 +166,7 @@ QVariant QmlPropertyMap::value(const QString &key) const If the key doesn't exist, it is automatically created. */ -void QmlPropertyMap::setValue(const QString &key, const QVariant &value) +void QmlPropertyMap::insert(const QString &key, const QVariant &value) { Q_D(QmlPropertyMap); if (!d->keys.contains(key)) @@ -190,7 +187,85 @@ QStringList QmlPropertyMap::keys() const } /*! - \fn void QmlPropertyMap::changed(const QString &key) + \overload + + Same as size(). +*/ +int QmlPropertyMap::count() const +{ + Q_D(const QmlPropertyMap); + return d->keys.count(); +} + +/*! + Returns the number of keys in the map. + + \sa isEmpty(), count() +*/ +int QmlPropertyMap::size() const +{ + Q_D(const QmlPropertyMap); + return d->keys.size(); +} + +/*! + Returns true if the map contains no keys; otherwise returns + false. + + \sa size() +*/ +bool QmlPropertyMap::isEmpty() const +{ + Q_D(const QmlPropertyMap); + return d->keys.isEmpty(); +} + +/*! + Returns true if the map contains \a key. + + \sa size() +*/ +bool QmlPropertyMap::contains(const QString &key) const +{ + Q_D(const QmlPropertyMap); + return d->keys.contains(key); +} + +/*! + Returns the value associated with the key \a key as a modifiable + reference. + + If the map contains no item with key \a key, the function inserts + an invalid QVariant into the map with key \a key, and + returns a reference to it. + + \sa insert(), value() +*/ +QVariant &QmlPropertyMap::operator[](const QString &key) +{ + //### optimize + Q_D(QmlPropertyMap); + QByteArray utf8key = key.toUtf8(); + if (!d->keys.contains(key)) { + d->keys.append(key); + d->mo->setValue(utf8key, QVariant()); //force creation -- needed below + } + + return (*(d->mo))[utf8key]; +} + +/*! + \overload + + Same as value(). +*/ +const QVariant QmlPropertyMap::operator[](const QString &key) const +{ + return value(key); +} + +/*! + \fn void QmlPropertyMap::valueChanged(const QString &key) This signal is emitted whenever one of the values in the map is changed. \a key is the key corresponding to the value that was changed. */ diff --git a/src/declarative/util/qmlpropertymap.h b/src/declarative/util/qmlpropertymap.h index 295f4b7..24b4395 100644 --- a/src/declarative/util/qmlpropertymap.h +++ b/src/declarative/util/qmlpropertymap.h @@ -63,13 +63,21 @@ public: virtual ~QmlPropertyMap(); QVariant value(const QString &key) const; - void setValue(const QString &key, const QVariant &value); - void clearValue(const QString &key); + void insert(const QString &key, const QVariant &value); + void clear(const QString &key); Q_INVOKABLE QStringList keys() const; + int count() const; + int size() const; + bool isEmpty() const; + bool contains(const QString &key) const; + + QVariant &operator[](const QString &key); + const QVariant operator[](const QString &key) const; + Q_SIGNALS: - void changed(const QString &key); + void valueChanged(const QString &key); private: Q_DECLARE_PRIVATE(QmlPropertyMap) diff --git a/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp b/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp index a923234..7d3cc43 100644 --- a/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp +++ b/tests/auto/declarative/qmlpropertymap/tst_qmlpropertymap.cpp @@ -14,33 +14,49 @@ public: private slots: void insert(); + void operatorInsert(); void clear(); void changed(); + void count(); }; void tst_QmlPropertyMap::insert() { QmlPropertyMap map; - map.setValue(QLatin1String("key1"),100); - map.setValue(QLatin1String("key2"),200); + map.insert(QLatin1String("key1"),100); + map.insert(QLatin1String("key2"),200); QVERIFY(map.keys().count() == 2); QCOMPARE(map.value(QLatin1String("key1")), QVariant(100)); QCOMPARE(map.value(QLatin1String("key2")), QVariant(200)); - map.setValue(QLatin1String("key1"),"Hello World"); + map.insert(QLatin1String("key1"),"Hello World"); + QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); +} + +void tst_QmlPropertyMap::operatorInsert() +{ + QmlPropertyMap map; + map[QLatin1String("key1")] = 100; + map[QLatin1String("key2")] = 200; + QVERIFY(map.keys().count() == 2); + + QCOMPARE(map.value(QLatin1String("key1")), QVariant(100)); + QCOMPARE(map.value(QLatin1String("key2")), QVariant(200)); + + map[QLatin1String("key1")] = "Hello World"; QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); } void tst_QmlPropertyMap::clear() { QmlPropertyMap map; - map.setValue(QLatin1String("key1"),100); + map.insert(QLatin1String("key1"),100); QVERIFY(map.keys().count() == 1); QCOMPARE(map.value(QLatin1String("key1")), QVariant(100)); - map.clearValue(QLatin1String("key1")); + map.clear(QLatin1String("key1")); QVERIFY(map.keys().count() == 1); QCOMPARE(map.value(QLatin1String("key1")), QVariant()); } @@ -48,12 +64,12 @@ void tst_QmlPropertyMap::clear() void tst_QmlPropertyMap::changed() { QmlPropertyMap map; - QSignalSpy spy(&map, SIGNAL(changed(const QString&))); - map.setValue(QLatin1String("key1"),100); - map.setValue(QLatin1String("key2"),200); + QSignalSpy spy(&map, SIGNAL(valueChanged(const QString&))); + map.insert(QLatin1String("key1"),100); + map.insert(QLatin1String("key2"),200); QCOMPARE(spy.count(), 0); - map.clearValue(QLatin1String("key1")); + map.clear(QLatin1String("key1")); QCOMPARE(spy.count(), 0); //make changes in QML @@ -72,6 +88,23 @@ void tst_QmlPropertyMap::changed() QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); } +void tst_QmlPropertyMap::count() +{ + QmlPropertyMap map; + QCOMPARE(map.isEmpty(), true); + map.insert(QLatin1String("key1"),100); + map.insert(QLatin1String("key2"),200); + QCOMPARE(map.count(), 2); + QCOMPARE(map.isEmpty(), false); + + map.insert(QLatin1String("key3"),"Hello World"); + QCOMPARE(map.count(), 3); + + //clearing doesn't remove the key + map.clear(QLatin1String("key3")); + QCOMPARE(map.count(), 3); +} + QTEST_MAIN(tst_QmlPropertyMap) #include "tst_qmlpropertymap.moc" -- cgit v0.12 From 841745b64fe608e9066d11e082ec0666a2a5eaa8 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Wed, 21 Oct 2009 15:31:08 +1000 Subject: small fixes to color-animation example --- examples/declarative/animation/color-animation.qml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/declarative/animation/color-animation.qml b/examples/declarative/animation/color-animation.qml index 04ec0bf..ec3f90f 100644 --- a/examples/declarative/animation/color-animation.qml +++ b/examples/declarative/animation/color-animation.qml @@ -12,8 +12,8 @@ Item { position: 0.0 color: SequentialAnimation { running: true; repeat: true - ColorAnimation { from: "DeepSkyBlue"; to: "#141450"; duration: 5000 } - ColorAnimation { from: "#141450"; to: "DeepSkyBlue"; duration: 5000 } + ColorAnimation { from: "DeepSkyBlue"; to: "#0E1533"; duration: 5000 } + ColorAnimation { from: "#0E1533"; to: "DeepSkyBlue"; duration: 5000 } } } GradientStop { @@ -26,7 +26,7 @@ Item { } } Particles { - anchors.fill:parent; source: "images/star.png"; angleDeviation: 360; velocity: 0 + anchors.fill: parent; source: "images/star.png"; angleDeviation: 360; velocity: 0 velocityDeviation: 0; count: parent.width / 10; fadeInDuration: 2800 opacity: SequentialAnimation { running: true; repeat: true @@ -36,8 +36,8 @@ Item { } } + // the sun and the moon Item { - id: space width: parent.width; height: 2 * parent.height transformOrigin: "Center" rotation: SequentialAnimation { @@ -46,11 +46,11 @@ Item { } Image { source: "images/sun.png"; y: 10; anchors.horizontalCenter: parent.horizontalCenter - transformOrigin: "Center"; rotation: -space.rotation + transformOrigin: "Center"; rotation: -3 * parent.rotation } Image { source: "images/moon.png"; y: parent.height - 74; anchors.horizontalCenter: parent.horizontalCenter - transformOrigin: "Center"; rotation: -space.rotation + transformOrigin: "Center"; rotation: -parent.rotation } } -- cgit v0.12 From c1a241652c587e6da92bf853608aed37938e1e48 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 21 Oct 2009 15:33:54 +1000 Subject: Fix breakout type resolution Didn't seem to resolve an empty URL correctly. Task-number:QT-2339 --- src/declarative/qml/qmlengine.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 3cd66aa..7fe8ca2 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -680,6 +680,8 @@ QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngi QUrl url; if(ctxt->argumentCount() > 2) url = QUrl(ctxt->argument(2).toString()); + else + url = QUrl(QLatin1String("DynamicQML")); QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1)); QmlContext *qmlCtxt = qmlContext(parentArg); url = qmlCtxt->resolvedUrl(url); -- cgit v0.12 From b49f57e4a2071f3b825d3e60b05c5914f16bd297 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 21 Oct 2009 15:38:00 +1000 Subject: Tweak scoping qmlContext() now returns the outer, not the inner context. The VME MetaObject now saves the context used to run function bodies --- src/declarative/qml/qmlengine.cpp | 33 ++++++++++++++++++++++++-------- src/declarative/qml/qmlengine_p.h | 1 + src/declarative/qml/qmlvmemetaobject.cpp | 3 +-- src/declarative/qml/qmlvmemetaobject_p.h | 1 + 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 1d98265..7c0edf7 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -404,7 +404,12 @@ QmlContext *QmlEngine::contextForObject(const QObject *object) QmlDeclarativeData *data = static_cast(priv->declarativeData); - return data?data->context:0; + if (!data) + return 0; + else if (data->outerContext) + return data->outerContext; + else + return data->context; } /*! @@ -568,6 +573,17 @@ QScriptValue QmlEnginePrivate::qmlScriptObject(QObject* object, } /*! + Returns the QmlContext for the executing QScript \a ctxt. +*/ +QmlContext *QmlEnginePrivate::getContext(QScriptContext *ctxt) +{ + QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass); + return contextClass->contextFromValue(scopeNode); +} + +/*! This function is intended for use inside QML only. In C++ just create a component object as usual. @@ -629,7 +645,7 @@ QScriptValue QmlEnginePrivate::createComponent(QScriptContext *ctxt, static_cast(engine)->p; QmlEngine* activeEngine = activeEnginePriv->q_func(); - QmlContext* context = activeEnginePriv->currentExpression->context(); + QmlContext* context = activeEnginePriv->getContext(ctxt); if(ctxt->argumentCount() != 1) { c = new QmlComponentJS(activeEngine); }else{ @@ -682,7 +698,12 @@ QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngi url = QUrl(ctxt->argument(2).toString()); QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1)); QmlContext *qmlCtxt = qmlContext(parentArg); - url = qmlCtxt->resolvedUrl(url); + if (url.isEmpty()) { + url = qmlCtxt->resolvedUrl(QUrl(QLatin1String(""))); + } else { + url = qmlCtxt->resolvedUrl(url); + } + QmlComponent component(activeEngine, qml.toUtf8(), url); if(component.isError()) { QList errors = component.errors(); @@ -848,11 +869,7 @@ QScriptValue QmlEnginePrivate::playSound(QScriptContext *ctxt, QScriptEngine *en QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); if (url.isRelative()) { - QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3); - Q_ASSERT(scopeNode.isValid()); - Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == enginePriv->contextClass); - - QmlContext *context = enginePriv->contextClass->contextFromValue(scopeNode); + QmlContext *context = enginePriv->getContext(ctxt); if (!context) return engine->undefinedValue(); diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 07ac928..a74854d 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -265,6 +265,7 @@ public: static QmlEngine *getEngine(QScriptEngine *e) { return static_cast(e)->p->q_func(); } static QmlEnginePrivate *get(QmlEngine *e) { return e->d_func(); } static QmlEnginePrivate *get(QScriptEngine *e) { return static_cast(e)->p; } + QmlContext *getContext(QScriptContext *); }; diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index e5acc51..62a2a6b 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -55,7 +55,7 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, const QMetaObject *other, const QmlVMEMetaData *meta, QmlRefCount *rc) -: object(obj), ref(rc), metaData(meta), parent(0) +: object(obj), ref(rc), ctxt(qmlContext(obj)), metaData(meta), parent(0) { if (ref) ref->addref(); @@ -251,7 +251,6 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) (const QChar *)(((const char*)metaData) + data->bodyOffset); QString code = QString::fromRawData(body, data->bodyLength); - QmlContext *ctxt = qmlContext(object); if (0 == (metaData->methodData() + id)->parameterCount) { QmlExpression expr(ctxt, code, object); diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index d376f4c..de46853 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -112,6 +112,7 @@ protected: private: QObject *object; QmlRefCount *ref; + QGuard ctxt; const QmlVMEMetaData *metaData; int propOffset; -- cgit v0.12 From ee26a42414a41ba0bcf2a0304e944e88ce5e3a4f Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 21 Oct 2009 15:48:37 +1000 Subject: Fix loader on Symbian. --- examples/declarative/loader/loader.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/declarative/loader/loader.pro b/examples/declarative/loader/loader.pro index 9b03b8f..806a362 100644 --- a/examples/declarative/loader/loader.pro +++ b/examples/declarative/loader/loader.pro @@ -12,7 +12,7 @@ symbian { # TARGET.UID3 = include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) TARGET.EPOCHEAPSIZE = 100000 20000000 - HEADERS += $$QT_SOURCE_TREE/examples/network/ftp/sym_iap_util.h + HEADERS += $$QT_SOURCE_TREE/examples/network/qftp/sym_iap_util.h LIBS += -lesock -lconnmon -linsock TARGET.CAPABILITY = NetworkServices } -- cgit v0.12 From 9570e6ada20e34a1427a151118a3c0e510423a2d Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 22 Oct 2009 10:00:44 +1000 Subject: Remove folderlistmodel's use of QObject private data --- examples/declarative/loader/qmlfolderlistmodel.cpp | 37 ++++------------------ examples/declarative/loader/qmlfolderlistmodel.h | 14 ++------ 2 files changed, 8 insertions(+), 43 deletions(-) diff --git a/examples/declarative/loader/qmlfolderlistmodel.cpp b/examples/declarative/loader/qmlfolderlistmodel.cpp index 0e5c275..4de0edf 100644 --- a/examples/declarative/loader/qmlfolderlistmodel.cpp +++ b/examples/declarative/loader/qmlfolderlistmodel.cpp @@ -39,15 +39,12 @@ ** ****************************************************************************/ -#include "private/qobject_p.h" -#include -#include #include "qmlfolderlistmodel.h" +#include +#include #include -QT_BEGIN_NAMESPACE - -class QmlFolderListModelPrivate : public QObjectPrivate +class QmlFolderListModelPrivate { public: QmlFolderListModelPrivate() @@ -113,9 +110,9 @@ public: */ QmlFolderListModel::QmlFolderListModel(QObject *parent) - : QListModelInterface(*(new QmlFolderListModelPrivate), parent) + : QListModelInterface(parent) { - Q_D(QmlFolderListModel); + d = new QmlFolderListModelPrivate; d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot); connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int)) , this, SLOT(inserted(const QModelIndex&,int,int))); @@ -129,12 +126,12 @@ QmlFolderListModel::QmlFolderListModel(QObject *parent) QmlFolderListModel::~QmlFolderListModel() { + delete d; } QHash QmlFolderListModel::data(int index, const QList &roles) const { Q_UNUSED(roles); - Q_D(const QmlFolderListModel); QHash folderData; QModelIndex modelIndex = d->model.index(index, 0, d->folderIndex); if (modelIndex.isValid()) { @@ -147,7 +144,6 @@ QHash QmlFolderListModel::data(int index, const QList &roles) int QmlFolderListModel::count() const { - Q_D(const QmlFolderListModel); return d->count; } @@ -180,13 +176,11 @@ QString QmlFolderListModel::toString(int role) const */ QUrl QmlFolderListModel::folder() const { - Q_D(const QmlFolderListModel); return d->folder; } void QmlFolderListModel::setFolder(const QUrl &folder) { - Q_D(QmlFolderListModel); if (folder == d->folder) return; QModelIndex index = d->model.index(folder.toLocalFile()); @@ -199,7 +193,6 @@ void QmlFolderListModel::setFolder(const QUrl &folder) QUrl QmlFolderListModel::parentFolder() const { - Q_D(const QmlFolderListModel); int pos = d->folder.path().lastIndexOf(QLatin1Char('/')); if (pos == -1) return QUrl(); @@ -224,20 +217,17 @@ QUrl QmlFolderListModel::parentFolder() const */ QStringList QmlFolderListModel::nameFilters() const { - Q_D(const QmlFolderListModel); return d->nameFilters; } void QmlFolderListModel::setNameFilters(const QStringList &filters) { - Q_D(QmlFolderListModel); d->nameFilters = filters; d->model.setNameFilters(d->nameFilters); } void QmlFolderListModel::componentComplete() { - Q_D(QmlFolderListModel); if (!d->folder.isValid() || !QDir().exists(d->folder.toLocalFile())) setFolder(QUrl(QLatin1String("file://")+QDir::currentPath())); @@ -247,13 +237,11 @@ void QmlFolderListModel::componentComplete() QmlFolderListModel::SortField QmlFolderListModel::sortField() const { - Q_D(const QmlFolderListModel); return d->sortField; } void QmlFolderListModel::setSortField(SortField field) { - Q_D(QmlFolderListModel); if (field != d->sortField) { d->sortField = field; d->updateSorting(); @@ -262,13 +250,11 @@ void QmlFolderListModel::setSortField(SortField field) bool QmlFolderListModel::sortReversed() const { - Q_D(const QmlFolderListModel); return d->sortReversed; } void QmlFolderListModel::setSortReversed(bool rev) { - Q_D(QmlFolderListModel); if (rev != d->sortReversed) { d->sortReversed = rev; d->updateSorting(); @@ -283,7 +269,6 @@ void QmlFolderListModel::setSortReversed(bool rev) */ bool QmlFolderListModel::isFolder(int index) const { - Q_D(const QmlFolderListModel); if (index != -1) { QModelIndex idx = d->model.index(index, 0, d->folderIndex); if (idx.isValid()) @@ -294,7 +279,6 @@ bool QmlFolderListModel::isFolder(int index) const void QmlFolderListModel::refresh() { - Q_D(QmlFolderListModel); d->folderIndex = QModelIndex(); if (d->count) { int tmpCount = d->count; @@ -310,7 +294,6 @@ void QmlFolderListModel::refresh() void QmlFolderListModel::inserted(const QModelIndex &index, int start, int end) { - Q_D(QmlFolderListModel); if (index == d->folderIndex) { d->count = d->model.rowCount(d->folderIndex); emit itemsInserted(start, end - start + 1); @@ -319,7 +302,6 @@ void QmlFolderListModel::inserted(const QModelIndex &index, int start, int end) void QmlFolderListModel::removed(const QModelIndex &index, int start, int end) { - Q_D(QmlFolderListModel); if (index == d->folderIndex) { d->count = d->model.rowCount(d->folderIndex); emit itemsRemoved(start, end - start + 1); @@ -328,7 +310,6 @@ void QmlFolderListModel::removed(const QModelIndex &index, int start, int end) void QmlFolderListModel::dataChanged(const QModelIndex &start, const QModelIndex &end) { - Q_D(QmlFolderListModel); qDebug() << "data changed"; if (start.parent() == d->folderIndex) emit itemsChanged(start.row(), end.row() - start.row() + 1, roles()); @@ -343,13 +324,11 @@ void QmlFolderListModel::dataChanged(const QModelIndex &start, const QModelIndex */ bool QmlFolderListModel::showDirs() const { - Q_D(const QmlFolderListModel); return d->model.filter() & QDir::AllDirs; } void QmlFolderListModel::setShowDirs(bool on) { - Q_D(QmlFolderListModel); if (!(d->model.filter() & QDir::AllDirs) == !on) return; if (on) @@ -367,13 +346,11 @@ void QmlFolderListModel::setShowDirs(bool on) */ bool QmlFolderListModel::showDotAndDotDot() const { - Q_D(const QmlFolderListModel); return !(d->model.filter() & QDir::NoDotAndDotDot); } void QmlFolderListModel::setShowDotAndDotDot(bool on) { - Q_D(QmlFolderListModel); if (!(d->model.filter() & QDir::NoDotAndDotDot) == on) return; if (on) @@ -391,13 +368,11 @@ void QmlFolderListModel::setShowDotAndDotDot(bool on) */ bool QmlFolderListModel::showOnlyReadable() const { - Q_D(const QmlFolderListModel); return d->model.filter() & QDir::Readable; } void QmlFolderListModel::setShowOnlyReadable(bool on) { - Q_D(QmlFolderListModel); if (!(d->model.filter() & QDir::Readable) == !on) return; if (on) diff --git a/examples/declarative/loader/qmlfolderlistmodel.h b/examples/declarative/loader/qmlfolderlistmodel.h index 66e600b..49b508d 100644 --- a/examples/declarative/loader/qmlfolderlistmodel.h +++ b/examples/declarative/loader/qmlfolderlistmodel.h @@ -45,17 +45,11 @@ #include #include -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - class QmlContext; class QModelIndex; class QmlFolderListModelPrivate; -class Q_DECLARATIVE_EXPORT QmlFolderListModel : public QListModelInterface, public QmlParserStatus +class QmlFolderListModel : public QListModelInterface, public QmlParserStatus { Q_OBJECT Q_INTERFACES(QmlParserStatus) @@ -115,14 +109,10 @@ private Q_SLOTS: void dataChanged(const QModelIndex &start, const QModelIndex &end); private: - Q_DECLARE_PRIVATE(QmlFolderListModel) Q_DISABLE_COPY(QmlFolderListModel) + QmlFolderListModelPrivate *d; }; -QT_END_NAMESPACE - QML_DECLARE_TYPE(QmlFolderListModel) -QT_END_HEADER - #endif // QMLFOLDERLISTMODEL_H -- cgit v0.12 From fa3a9815a3c4b1b7cd464648e67c16d299773f87 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Thu, 22 Oct 2009 11:11:27 +1000 Subject: Test createQmlObject URL resolution (must be relative to calling context). Task-number:QT-2339 See also c1a241652c587e6da92bf853608aed37938e1e48 Also make test more data-driven (and hence independently reported). --- .../qmlecmascript/data/TypeForDynamicCreation.qml | 2 ++ .../qmlecmascript/data/dynamicCreation.qml | 5 ++++ .../qmlecmascript/tst_qmlecmascript.cpp | 29 ++++++++++++++-------- 3 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 tests/auto/declarative/qmlecmascript/data/TypeForDynamicCreation.qml diff --git a/tests/auto/declarative/qmlecmascript/data/TypeForDynamicCreation.qml b/tests/auto/declarative/qmlecmascript/data/TypeForDynamicCreation.qml new file mode 100644 index 0000000..56e0625 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/TypeForDynamicCreation.qml @@ -0,0 +1,2 @@ +import Qt.test 1.0 +MyQmlObject{objectName:"objectThree"} diff --git a/tests/auto/declarative/qmlecmascript/data/dynamicCreation.qml b/tests/auto/declarative/qmlecmascript/data/dynamicCreation.qml index ef39590..ed5e571 100644 --- a/tests/auto/declarative/qmlecmascript/data/dynamicCreation.qml +++ b/tests/auto/declarative/qmlecmascript/data/dynamicCreation.qml @@ -13,4 +13,9 @@ MyQmlObject{ var component = createComponent('dynamicCreation.helper.qml'); obj.objectProperty = component.createObject(); } + + function createThree() + { + obj.objectProperty = createQmlObject('TypeForDynamicCreation{}', obj); + } } diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index f24882a..34b49e6 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -56,6 +56,7 @@ private slots: void signalParameterTypes(); void objectsCompareAsEqual(); void scriptAccess(); + void dynamicCreation_data(); void dynamicCreation(); void dynamicDestruction(); void objectToString(); @@ -639,27 +640,33 @@ void tst_qmlecmascript::scriptAccess() QCOMPARE(object->property("test3").toInt(), 0); } +void tst_qmlecmascript::dynamicCreation_data() +{ + QTest::addColumn("method"); + QTest::addColumn("createdName"); + + QTest::newRow("One") << "createOne" << "objectOne"; + QTest::newRow("Two") << "createTwo" << "objectTwo"; + QTest::newRow("Three") << "createThree" << "objectThree"; +} + /* Test using createQmlObject to dynamically generate an item Also using createComponent is tested. */ void tst_qmlecmascript::dynamicCreation() { + QFETCH(QString, method); + QFETCH(QString, createdName); + QmlComponent component(&engine, TEST_FILE("dynamicCreation.qml")); MyQmlObject *object = qobject_cast(component.create()); QVERIFY(object != 0); - QObject *createdQmlObject = 0; - QObject *createdComponent = 0; - - QMetaObject::invokeMethod(object, "createOne"); - createdQmlObject = object->objectProperty(); - QVERIFY(createdQmlObject); - QCOMPARE(createdQmlObject->objectName(), QString("objectOne")); - QMetaObject::invokeMethod(object, "createTwo"); - createdComponent = object->objectProperty(); - QVERIFY(createdComponent); - QCOMPARE(createdComponent->objectName(), QString("objectTwo")); + QMetaObject::invokeMethod(object, method.toUtf8()); + QObject *created = object->objectProperty(); + QVERIFY(created); + QCOMPARE(created->objectName(), createdName); } /* -- cgit v0.12 From a3b3ba02f0eba2f435f552a9aa64fc9fceade972 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 22 Oct 2009 11:14:34 +1000 Subject: Support assigning scripts to QML properties --- src/declarative/qml/qml.pri | 2 + src/declarative/qml/qmlcompiler.cpp | 32 +++++ src/declarative/qml/qmlcompiler_p.h | 3 + src/declarative/qml/qmlengine.cpp | 10 +- src/declarative/qml/qmlinstruction_p.h | 6 + src/declarative/qml/qmlparser.cpp | 10 ++ src/declarative/qml/qmlparser_p.h | 2 + src/declarative/qml/qmlscriptstring.cpp | 154 +++++++++++++++++++++ src/declarative/qml/qmlscriptstring.h | 87 ++++++++++++ src/declarative/qml/qmlvme.cpp | 16 +++ .../declarative/qmllanguage/data/scriptString.qml | 6 + tests/auto/declarative/qmllanguage/testtypes.cpp | 2 +- tests/auto/declarative/qmllanguage/testtypes.h | 31 +++++ .../declarative/qmllanguage/tst_qmllanguage.cpp | 19 +++ 14 files changed, 375 insertions(+), 5 deletions(-) create mode 100644 src/declarative/qml/qmlscriptstring.cpp create mode 100644 src/declarative/qml/qmlscriptstring.h create mode 100644 tests/auto/declarative/qmllanguage/data/scriptString.qml diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 58a18a2..b6e86a8 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -40,6 +40,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlpropertycache.cpp \ qml/qmlintegercache.cpp \ qml/qmltypenamecache.cpp \ + qml/qmlscriptstring.cpp \ qml/qmlobjectscriptclass.cpp \ qml/qmlcontextscriptclass.cpp \ qml/qmlglobalscriptclass.cpp \ @@ -102,6 +103,7 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlpropertycache_p.h \ qml/qmlintegercache_p.h \ qml/qmltypenamecache_p.h \ + qml/qmlscriptstring.h \ qml/qmlobjectscriptclass_p.h \ qml/qmlcontextscriptclass_p.h \ qml/qmlglobalscriptclass_p.h \ diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index e2fd7cb..726051e 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -69,6 +69,7 @@ #include #include "qmlmetaproperty_p.h" #include "qmlrewrite_p.h" +#include #include "qmlscriptparser_p.h" @@ -860,6 +861,17 @@ void QmlCompiler::genObject(QmlParser::Object *obj) void QmlCompiler::genObjectBody(QmlParser::Object *obj) { + typedef QPair PropPair; + foreach(const PropPair &prop, obj->scriptStringProperties) { + QmlInstruction ss; + ss.type = QmlInstruction::StoreScriptString; + ss.storeScriptString.propertyIndex = prop.first->index; + ss.storeScriptString.value = + output->indexForString(prop.first->values.at(0)->value.asScript()); + ss.storeScriptString.scope = prop.second; + output->bytecode << ss; + } + bool seenDefer = false; foreach(Property *prop, obj->valueProperties) { if (prop->isDeferred) { @@ -1371,6 +1383,10 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop, COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); + } else if (prop->type == qMetaTypeId()) { + + COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt)); + } else { COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); @@ -1823,6 +1839,22 @@ bool QmlCompiler::buildListProperty(QmlParser::Property *prop, return true; } +// Compiles an assignment to a QmlScriptString property +bool QmlCompiler::buildScriptStringProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) +{ + if (prop->values.count() > 1) + COMPILE_EXCEPTION(prop->values.at(1), qApp->translate("QmlCompiler", "Cannot assign multiple values to a script property")); + + if (prop->values.at(0)->object || !prop->values.at(0)->value.isScript()) + COMPILE_EXCEPTION(prop->values.at(0), qApp->translate("QmlCompiler", "Invalid property assignment: script expected")); + + obj->addScriptStringProperty(prop, ctxt.stack); + + return true; +} + // Compile regular property assignments of the form "property: " // // ### The following problems exist diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index cff4937..8a9ca9c 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -197,6 +197,9 @@ private: bool buildListProperty(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &ctxt); + bool buildScriptStringProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); bool buildPropertyAssignment(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &ctxt); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 6361da4..9fad80b 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -78,8 +78,8 @@ #include #include #include -#include "private/qmlcomponentjs_p.h" -#include "private/qmlmetaproperty_p.h" +#include +#include #include #include #include @@ -88,6 +88,7 @@ #include #include #include +#include #ifdef Q_OS_WIN // for %APPDATA% #include "qt_windows.h" @@ -219,6 +220,9 @@ Q_GLOBAL_STATIC(QmlEngineDebugServer, qmlEngineDebugServer); void QmlEnginePrivate::init() { Q_Q(QmlEngine); + qRegisterMetaType("QVariant"); + qRegisterMetaType("QmlScriptString"); + scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); @@ -284,8 +288,6 @@ QmlEngine::QmlEngine(QObject *parent) { Q_D(QmlEngine); d->init(); - - qRegisterMetaType("QVariant"); } /*! diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 5265d42..dc18b05 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -119,6 +119,7 @@ public: StoreSignal, /* storeSignal */ StoreScript, /* storeScript */ + StoreScriptString, /* storeScriptString */ // // Unresolved single assignment @@ -245,6 +246,11 @@ public: int value; } storeString; struct { + int propertyIndex; + int value; + int scope; + } storeScriptString; + struct { int value; int fileName; int lineNumber; diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index bae263a..f9e3c50 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -80,6 +80,9 @@ QmlParser::Object::~Object() prop->release(); foreach(Property *prop, valueTypeProperties) prop->release(); + typedef QPair PropPair; + foreach(const PropPair &prop, scriptStringProperties) + prop.first->release(); foreach(const DynamicProperty &prop, dynamicProperties) if (prop.defaultValue) prop.defaultValue->release(); foreach(Object *obj, scriptBlockObjects) @@ -142,6 +145,13 @@ void QmlParser::Object::addValueTypeProperty(Property *p) valueTypeProperties << p; } +void QmlParser::Object::addScriptStringProperty(Property *p, int stack) +{ + p->addref(); + scriptStringProperties << qMakePair(p, stack); +} + + Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) { if (!properties.contains(name)) { diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 88d7d77..f0867ea 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -160,11 +160,13 @@ namespace QmlParser void addAttachedProperty(Property *); void addGroupedProperty(Property *); void addValueTypeProperty(Property *); + void addScriptStringProperty(Property *, int = 0); QList valueProperties; QList signalProperties; QList attachedProperties; QList groupedProperties; QList valueTypeProperties; + QList > scriptStringProperties; // Script blocks that were nested under this object QStringList scriptBlocks; diff --git a/src/declarative/qml/qmlscriptstring.cpp b/src/declarative/qml/qmlscriptstring.cpp new file mode 100644 index 0000000..8a6afcc --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlscriptstring.h" + +QT_BEGIN_NAMESPACE + +class QmlScriptStringPrivate : public QSharedData +{ +public: + QmlScriptStringPrivate() : context(0), scope(0) {} + + QmlContext *context; + QObject *scope; + QString script; +}; + +/*! +\class QmlScriptString +\brief The QmlScriptString class encapsulates a script and its context. + +The QmlScriptString is used by properties that want to accept a script "assignment" from QML. + +Normally, the following code would result in a binding being established for the \c script +property. If the property had a type of QmlScriptString, the script - \e {print(1921)} - itself +would be passed to the property and it could choose how to handle it. + +\code +MyType { + script: print(1921) +} +\endcode +*/ + +/*! +Construct an empty instance. +*/ +QmlScriptString::QmlScriptString() +: d(new QmlScriptStringPrivate) +{ +} + +/*! +Copy \a other. +*/ +QmlScriptString::QmlScriptString(const QmlScriptString &other) +: d(other.d) +{ +} + +/*! +\internal +*/ +QmlScriptString::~QmlScriptString() +{ +} + +/*! +Assign \a other to this. +*/ +QmlScriptString &QmlScriptString::operator=(const QmlScriptString &other) +{ + d = other.d; + return *this; +} + +/*! +Return the context for the script. +*/ +QmlContext *QmlScriptString::context() const +{ + return d->context; +} + +/*! +Sets the \a context for the script. +*/ +void QmlScriptString::setContext(QmlContext *context) +{ + d->context = context; +} + +/*! +Returns the scope object for the script. +*/ +QObject *QmlScriptString::scopeObject() const +{ + return d->scope; +} + +/*! +Sets the scope \a object for the script. +*/ +void QmlScriptString::setScopeObject(QObject *object) +{ + d->scope = object; +} + +/*! +Returns the script text. +*/ +QString QmlScriptString::script() const +{ + return d->script; +} + +/*! +Sets the \a script text. +*/ +void QmlScriptString::setScript(const QString &script) +{ + d->script = script; +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlscriptstring.h b/src/declarative/qml/qmlscriptstring.h new file mode 100644 index 0000000..c6067ce --- /dev/null +++ b/src/declarative/qml/qmlscriptstring.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSCRIPTSTRING_H +#define QMLSCRIPTSTRING_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QObject; +class QmlContext; +class QmlScriptStringPrivate; +class Q_DECLARATIVE_EXPORT QmlScriptString +{ +public: + QmlScriptString(); + QmlScriptString(const QmlScriptString &); + ~QmlScriptString(); + + QmlScriptString &operator=(const QmlScriptString &); + + QmlContext *context() const; + void setContext(QmlContext *); + + QObject *scopeObject() const; + void setScopeObject(QObject *); + + QString script() const; + void setScript(const QString &); + +private: + QSharedDataPointer d; +}; + +Q_DECLARE_METATYPE(QmlScriptString); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLSCRIPTSTRING_H + diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 1f3903d..7f673a2 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -67,6 +67,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -552,6 +553,21 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, } break; + case QmlInstruction::StoreScriptString: + { + QObject *target = stack.top(); + QObject *scope = stack.at(stack.count() - 1 - instr.storeScriptString.scope); + QmlScriptString ss; + ss.setContext(ctxt); + ss.setScopeObject(scope); + ss.setScript(primitives.at(instr.storeScriptString.value)); + + void *a[] = { &ss, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeScriptString.propertyIndex, a); + } + break; + case QmlInstruction::BeginObject: { QObject *target = stack.top(); diff --git a/tests/auto/declarative/qmllanguage/data/scriptString.qml b/tests/auto/declarative/qmllanguage/data/scriptString.qml new file mode 100644 index 0000000..51e6e48 --- /dev/null +++ b/tests/auto/declarative/qmllanguage/data/scriptString.qml @@ -0,0 +1,6 @@ +import Test 1.0 + +MyTypeObject { + scriptProperty: foo + bar + grouped.script: print(1921) +} diff --git a/tests/auto/declarative/qmllanguage/testtypes.cpp b/tests/auto/declarative/qmllanguage/testtypes.cpp index c11e195..58d99f1 100644 --- a/tests/auto/declarative/qmllanguage/testtypes.cpp +++ b/tests/auto/declarative/qmllanguage/testtypes.cpp @@ -7,4 +7,4 @@ QML_DEFINE_TYPE(Test,1,0,0,MyContainer,MyContainer); QML_DEFINE_TYPE(Test,1,0,0,MyPropertyValueSource,MyPropertyValueSource); QML_DEFINE_TYPE(Test,1,0,0,MyDotPropertyObject,MyDotPropertyObject); QML_DEFINE_TYPE(Test,1,0,0,MyNamespacedType,MyNamespace::MyNamespacedType); - +QML_DEFINE_NOCREATE_TYPE(MyGroupedObject); diff --git a/tests/auto/declarative/qmllanguage/testtypes.h b/tests/auto/declarative/qmllanguage/testtypes.h index b1da9fb..355ff8b 100644 --- a/tests/auto/declarative/qmllanguage/testtypes.h +++ b/tests/auto/declarative/qmllanguage/testtypes.h @@ -10,6 +10,7 @@ #include #include #include +#include class MyInterface { @@ -112,6 +113,21 @@ private: }; QML_DECLARE_TYPE(MyQmlObject); +class MyGroupedObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QmlScriptString script READ script WRITE setScript); +public: + QmlScriptString script() const { return m_script; } + void setScript(const QmlScriptString &s) { m_script = s; } + +private: + QmlScriptString m_script; +}; + +QML_DECLARE_TYPE(MyGroupedObject); + + class MyTypeObject : public QObject { Q_OBJECT @@ -142,6 +158,9 @@ class MyTypeObject : public QObject Q_PROPERTY(bool boolProperty READ boolProperty WRITE setBoolProperty); Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty); + Q_PROPERTY(QmlScriptString scriptProperty READ scriptProperty WRITE setScriptProperty); + Q_PROPERTY(MyGroupedObject *grouped READ grouped CONSTANT); + public: MyTypeObject() : objectPropertyValue(0), componentPropertyValue(0) {} @@ -334,6 +353,17 @@ public: variantPropertyValue = v; } + QmlScriptString scriptPropertyValue; + QmlScriptString scriptProperty() const { + return scriptPropertyValue; + } + void setScriptProperty(const QmlScriptString &v) { + scriptPropertyValue = v; + } + + MyGroupedObject groupedValue; + MyGroupedObject *grouped() { return &groupedValue; } + void doAction() { emit action(); } signals: void action(); @@ -365,6 +395,7 @@ private: QML_DECLARE_TYPE(MyContainer); + class MyPropertyValueSource : public QObject, public QmlPropertyValueSource { Q_OBJECT diff --git a/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp b/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp index 8d4ae65..97038e6 100644 --- a/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp +++ b/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp @@ -63,6 +63,7 @@ private slots: void i18n(); void i18n_data(); void onCompleted(); + void scriptString(); void importsBuiltin_data(); void importsBuiltin(); @@ -739,6 +740,24 @@ void tst_qmllanguage::onCompleted() QVERIFY(object != 0); } +// Check that assignments to QmlScriptString properties work +void tst_qmllanguage::scriptString() +{ + QmlComponent component(&engine, TEST_FILE("scriptString.qml")); + VERIFY_ERRORS(0); + + MyTypeObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->scriptProperty().script(), QString("foo + bar")); + QCOMPARE(object->scriptProperty().scopeObject(), object); + QCOMPARE(object->scriptProperty().context(), qmlContext(object)); + + QVERIFY(object->grouped() != 0); + QCOMPARE(object->grouped()->script().script(), QString("print(1921)")); + QCOMPARE(object->grouped()->script().scopeObject(), object); + QCOMPARE(object->grouped()->script().context(), qmlContext(object)); +} + // Check that first child of qml is of given type. Empty type insists on error. void tst_qmllanguage::testType(const QString& qml, const QString& type) { -- cgit v0.12 From 7717f6d250d1158ceb8b1c25ec78c8719d8252a0 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Thu, 22 Oct 2009 11:28:25 +1000 Subject: Incorporate latest cosmological theory. --- examples/declarative/animation/color-animation.qml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/declarative/animation/color-animation.qml b/examples/declarative/animation/color-animation.qml index ec3f90f..0cf8a44 100644 --- a/examples/declarative/animation/color-animation.qml +++ b/examples/declarative/animation/color-animation.qml @@ -25,18 +25,9 @@ Item { } } } - Particles { - anchors.fill: parent; source: "images/star.png"; angleDeviation: 360; velocity: 0 - velocityDeviation: 0; count: parent.width / 10; fadeInDuration: 2800 - opacity: SequentialAnimation { - running: true; repeat: true - NumberAnimation { from: 0; to: 1; duration: 5000 } - NumberAnimation { from: 1; to: 0; duration: 5000 } - } - } } - // the sun and the moon + // the sun, moon, and stars Item { width: parent.width; height: 2 * parent.height transformOrigin: "Center" @@ -52,6 +43,16 @@ Item { source: "images/moon.png"; y: parent.height - 74; anchors.horizontalCenter: parent.horizontalCenter transformOrigin: "Center"; rotation: -parent.rotation } + Particles { + x: 0; y: parent.height/2; width: parent.width; height: parent.height/2 + source: "images/star.png"; angleDeviation: 360; velocity: 0 + velocityDeviation: 0; count: parent.width / 10; fadeInDuration: 2800 + opacity: SequentialAnimation { + running: true; repeat: true + NumberAnimation { from: 0; to: 1; duration: 5000 } + NumberAnimation { from: 1; to: 0; duration: 5000 } + } + } } // ...and the ground. -- cgit v0.12