diff options
22 files changed, 439 insertions, 87 deletions
diff --git a/demos/declarative/contacts/Contact.qml b/demos/declarative/contacts/Contact.qml index 342c356..7297fa6 100644 --- a/demos/declarative/contacts/Contact.qml +++ b/demos/declarative/contacts/Contact.qml @@ -52,6 +52,11 @@ Item { } ] + function refresh() { + labelField.value = label; + emailField.value = email; + phoneField.value = phone; + } function update() { updateContactQuery.exec(); } diff --git a/demos/declarative/contacts/ContactField.qml b/demos/declarative/contacts/ContactField.qml index 3ce2c1a..cb319ae 100644 --- a/demos/declarative/contacts/ContactField.qml +++ b/demos/declarative/contacts/ContactField.qml @@ -5,7 +5,7 @@ Item { property var label: "Name" property var icon: "pics/phone.png" property var value: "" - onValueChanged: { fieldText.text=field.value } + onValueChanged: { fieldText.text = contactField.value } RemoveButton { id: removeButton anchors.right: parent.right diff --git a/demos/declarative/contacts/contacts.qml b/demos/declarative/contacts/contacts.qml index ce5a2b5..4582bd1 100644 --- a/demos/declarative/contacts/contacts.qml +++ b/demos/declarative/contacts/contacts.qml @@ -39,9 +39,11 @@ Rect { children: [ MouseRegion { anchors.fill: parent - onClicked: { Details.qml = 'Contact.qml'; + onClicked: { + Details.qml = 'Contact.qml'; wrapper.state='opened'; - contacts.mode = 'edit'; } + contacts.mode = 'edit'; + } } ] } @@ -142,7 +144,7 @@ Rect { anchors.right: parent.right anchors.rightMargin: 5 icon: "pics/new.png" - onClicked: { print("open new contact edit"); newContactItem.label = ''; newContactItem.phone = ''; newContactItem.email = ''; contacts.mode = 'new' } + onClicked: { newContactItem.refresh(); contacts.mode = 'new' } opacity: contacts.mode == 'list' ? 1 : 0 } Button { @@ -174,10 +176,15 @@ Rect { delegate: contactDelegate focus: false } - Contact { - id: newContactItem + FocusRealm { + id: newContactWrapper anchors.fill: contactListView opacity: 0 + focus: contacts.mode == 'new' + Contact { + id: newContactItem + anchors.fill: parent + } } Connection { sender: confirmEditButton @@ -234,7 +241,7 @@ Rect { ] } KeyProxy { - focus: true + focus: contacts.mode != 'new' targets: { contacts.mode == "list" ? [searchBarWrapper, contactListView] : [contactListView]} } states: [ @@ -247,7 +254,7 @@ Rect { value: 0 } SetProperty { - target: newContactItem + target: newContactWrapper property: "opacity" value: 1 } diff --git a/demos/declarative/flickr/content/ImageDetails.qml b/demos/declarative/flickr/content/ImageDetails.qml index 955f85d..6c354f6 100644 --- a/demos/declarative/flickr/content/ImageDetails.qml +++ b/demos/declarative/flickr/content/ImageDetails.qml @@ -60,8 +60,9 @@ Flipable { text: "<b>Published:</b> " + Container.photoDate } Text { id: TagsLabel; color: "white"; x: 220; anchors.top: Date.bottom; text: Container.photoTags == "" ? "" : "<b>Tags:</b> " } - Text { id: Tags; color: "white"; width: parent.width-x-20; anchors.left: TagsLabel.right; anchors.top: Date.bottom; elide: "ElideRight" - text: Container.photoTags == "" ? "" : Container.photoTags } + Text { id: Tags; color: "white"; width: parent.width-x-20; + anchors.left: TagsLabel.right; anchors.top: Date.bottom; + elide: "ElideRight"; text: Container.photoTags } ScrollBar { id: ScrollBar; x: 720; y: Flickable.y; width: 7; height: Flickable.height; opacity: 0; flickableArea: Flickable; clip: true } diff --git a/demos/declarative/flickr/flickr2.qml b/demos/declarative/flickr/flickr2.qml index 4875fa4..3b1208c 100644 --- a/demos/declarative/flickr/flickr2.qml +++ b/demos/declarative/flickr/flickr2.qml @@ -143,29 +143,31 @@ Item { ] transitions: [ Transition { - fromState: "*" - toState: "*" + fromState: "left" + toState: "right" SequentialAnimation { SetPropertyAction { target: Wrapper property: "moveToParent" - value: Bounce } ParallelAnimation { NumericAnimation { target: Wrapper - properties: "x" + properties: "x,y" to: 0 - duration: 250 - } - NumericAnimation { - target: Wrapper - properties: "y" - to: 0 - easing: "easeInQuad" - duration: 250 + easing: "easeOutQuad" + duration: 350 } } + } + }, + Transition { + fromState: "right" + toState: "left" + SequentialAnimation { + PauseAnimation { + duration: Math.floor(index/7)*100 + } SetPropertyAction { target: Wrapper property: "moveToParent" @@ -173,13 +175,7 @@ Item { ParallelAnimation { NumericAnimation { target: Wrapper - properties: "x" - to: 0 - duration: 250 - } - NumericAnimation { - target: Wrapper - properties: "y" + properties: "x,y" to: 0 easing: "easeOutQuad" duration: 250 @@ -203,14 +199,20 @@ Item { GridView { id: PhotoGridView; model: MyVisualModel.parts.leftBox cellWidth: 105; cellHeight: 105; x:32; y: 80; width: 800; height: 330; z: 1 + cacheBuffer: 100 } PathView { id: PhotoPathView; model: MyVisualModel.parts.rightBox y: 80; width: 800; height: 330; z: 1 + pathItemCount: 10; snapPosition: 0.001 path: Path { - startX: -50; startY: 40; + startX: -150; startY: 40; + PathPercent { value: 0 } + PathLine { x: -50; y: 40 } + + PathPercent { value: 0.001 } PathAttribute { name: "scale"; value: 1 } PathAttribute { name: "angle"; value: -45 } @@ -232,6 +234,10 @@ Item { PathAttribute { name: "scale"; value: 1 } PathAttribute { name: "angle"; value: -45 } + + PathPercent { value: 0.999 } + PathLine { x: 950; y: 40 } + PathPercent { value: 1.0 } } } diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri index b88b7b3..31a1d5b 100644 --- a/src/declarative/debugger/debugger.pri +++ b/src/declarative/debugger/debugger.pri @@ -1,5 +1,7 @@ SOURCES += debugger/qmldebugger.cpp \ - debugger/qmldebuggerstatus.cpp + debugger/qmldebuggerstatus.cpp \ + debugger/qmlpropertyview.cpp HEADERS += debugger/qmldebugger.h \ - debugger/qmldebuggerstatus.h + debugger/qmldebuggerstatus.h \ + debugger/qmlpropertyview_p.h diff --git a/src/declarative/debugger/qmldebugger.cpp b/src/declarative/debugger/qmldebugger.cpp index f232f02..634385b 100644 --- a/src/declarative/debugger/qmldebugger.cpp +++ b/src/declarative/debugger/qmldebugger.cpp @@ -57,9 +57,11 @@ #include <QtGui/qpushbutton.h> #include <QtGui/qtablewidget.h> #include <QtGui/qevent.h> +#include <private/qmlpropertyview_p.h> QmlDebugger::QmlDebugger(QWidget *parent) -: QWidget(parent), m_tree(0), m_warnings(0), m_watchers(0), m_text(0) +: QWidget(parent), m_tree(0), m_warnings(0), m_watchers(0), m_properties(0), + m_text(0) { QHBoxLayout *layout = new QHBoxLayout; setLayout(layout); @@ -97,6 +99,9 @@ QmlDebugger::QmlDebugger(QWidget *parent) m_watchers->setSelectionMode(QTableWidget::NoSelection); tabs->addTab(m_watchers, "Watchers"); + m_properties = new QmlPropertyView(this); + tabs->addTab(m_properties, "Properties"); + splitter->addWidget(tabs); splitter->setStretchFactor(1, 2); @@ -162,6 +167,8 @@ void QmlDebugger::itemClicked(QTreeWidgetItem *i) debug->setSelectedState(true); m_selectedItem = item->object; } + + m_properties->setObject(item->object); } if(item->url.scheme() == QLatin1String("file")) { diff --git a/src/declarative/debugger/qmldebugger.h b/src/declarative/debugger/qmldebugger.h index 8d2593d..35ff92c 100644 --- a/src/declarative/debugger/qmldebugger.h +++ b/src/declarative/debugger/qmldebugger.h @@ -57,6 +57,7 @@ class QTreeWidgetItem; class QPlainTextEdit; class QmlDebuggerItem; class QTableWidget; +class QmlPropertyView; class QmlDebugger : public QWidget { Q_OBJECT @@ -78,6 +79,7 @@ private: QTreeWidget *m_tree; QTreeWidget *m_warnings; QTableWidget *m_watchers; + QmlPropertyView *m_properties; QPlainTextEdit *m_text; QPointer<QObject> m_object; QList<QPair<quint32, QPair<int, QString> > > m_expressions; diff --git a/src/declarative/debugger/qmlpropertyview.cpp b/src/declarative/debugger/qmlpropertyview.cpp new file mode 100644 index 0000000..2434c58 --- /dev/null +++ b/src/declarative/debugger/qmlpropertyview.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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 "qmlpropertyview_p.h" +#include <QtGui/qboxlayout.h> +#include <QtGui/qtreewidget.h> +#include <QtCore/qmetaobject.h> + +QmlPropertyView::QmlPropertyView(QWidget *parent) +: QWidget(parent), m_tree(0) +{ + QVBoxLayout *layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + setLayout(layout); + + m_tree = new QTreeWidget(this); + m_tree->setHeaderLabels(QStringList() << "Property" << "Value"); + + m_tree->setColumnCount(2); + + layout->addWidget(m_tree); +} + +class QmlPropertyViewItem : public QObject, public QTreeWidgetItem +{ +Q_OBJECT +public: + QmlPropertyViewItem(QTreeWidget *widget); + + QObject *object; + QMetaProperty property; + +public slots: + void refresh(); +}; + +QmlPropertyViewItem::QmlPropertyViewItem(QTreeWidget *widget) +: QTreeWidgetItem(widget) +{ +} + +void QmlPropertyViewItem::refresh() +{ + setText(1, property.read(object).toString()); +} + +void QmlPropertyView::setObject(QObject *object) +{ + m_object = object; + + m_tree->clear(); + if(!m_object) + return; + + const QMetaObject *mo = object->metaObject(); + for(int ii = 0; ii < mo->propertyCount(); ++ii) { + QmlPropertyViewItem *item = new QmlPropertyViewItem(m_tree); + + QMetaProperty p = mo->property(ii); + item->object = object; + item->property = p; + + item->setText(0, QLatin1String(p.name())); + + static int refreshIdx = -1; + if(refreshIdx == -1) + refreshIdx = QmlPropertyViewItem::staticMetaObject.indexOfMethod("refresh()"); + + if(p.hasNotifySignal()) + QMetaObject::connect(object, p.notifySignalIndex(), + item, refreshIdx); + + item->refresh(); + } +} + +void QmlPropertyView::refresh() +{ + setObject(m_object); +} + +#include "qmlpropertyview.moc" diff --git a/src/declarative/debugger/qmlpropertyview_p.h b/src/declarative/debugger/qmlpropertyview_p.h new file mode 100644 index 0000000..fce9941 --- /dev/null +++ b/src/declarative/debugger/qmlpropertyview_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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 QMLPROPERTYVIEW_P_H +#define QMLPROPERTYVIEW_P_H + +#include <QtGui/qwidget.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_NAMESPACE + +class QTreeWidget; +class QmlPropertyView : public QWidget +{ + Q_OBJECT +public: + QmlPropertyView(QWidget *parent = 0); + + void setObject(QObject *); + +public slots: + void refresh(); + +private: + QPointer<QObject> m_object; + QTreeWidget *m_tree; +}; + +QT_END_NAMESPACE + +#endif // QMLPROPERTYVIEW_P_H + diff --git a/src/declarative/fx/qfxpathview.cpp b/src/declarative/fx/qfxpathview.cpp index 715ae5a..2b39d6e 100644 --- a/src/declarative/fx/qfxpathview.cpp +++ b/src/declarative/fx/qfxpathview.cpp @@ -145,7 +145,7 @@ QFxPathView::~QFxPathView() QVariant QFxPathView::model() const { Q_D(const QFxPathView); - return d->model ? d->model->model() : QVariant(); + return d->modelVariant; } void QFxPathView::setModel(const QVariant &model) @@ -154,13 +154,24 @@ void QFxPathView::setModel(const QVariant &model) if (d->model) { disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); + disconnect(d->model, SIGNAL(itemCreated(int, QFxItem*)), this, SLOT(itemCreated(int,QFxItem*))); + for (int i=0; i<d->items.count(); i++){ + QFxItem *p = d->items[i]; + attachedProperties.remove(p); + d->model->release(p); + } + d->items.clear(); } - if (QFxVisualItemModel *m = qvariant_cast<QFxVisualItemModel*>(model)) { + + d->modelVariant = model; + QObject *object = qvariant_cast<QObject*>(model); + QFxVisualItemModel *vim = 0; + if (object && (vim = qobject_cast<QFxVisualItemModel *>(object))) { if (d->ownModel) { delete d->model; d->ownModel = false; } - d->model = m; + d->model = vim; } else { if (!d->ownModel) { d->model = new QFxVisualItemModel(qmlContext(this)); @@ -171,6 +182,7 @@ void QFxPathView::setModel(const QVariant &model) if (d->model) { connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); + connect(d->model, SIGNAL(itemCreated(int, QFxItem*)), this, SLOT(itemCreated(int,QFxItem*))); } d->firstIndex = 0; d->pathOffset = 0; @@ -550,7 +562,7 @@ void QFxPathViewPrivate::regenerate() } items.clear(); - if (!model || model->count() <= 0 || !model->delegate() || !path) + if (!isValid()) return; if (firstIndex >= model->count()) @@ -560,14 +572,14 @@ void QFxPathViewPrivate::regenerate() int numItems = pathItems >= 0 ? pathItems : model->count(); for (int i=0; i < numItems && i < model->count(); ++i){ - QFxItem *item = model->item((i + firstIndex) % model->count()); - if (!item) + QFxItem *item = getItem((i + firstIndex) % model->count()); + if (!item) { + qWarning() << "PathView: Cannot create item, index" << (i + firstIndex) % model->count(); return; + } items.append(item); item->setZ(i); - item->setParent(q); } - q->refill(); } @@ -577,7 +589,6 @@ void QFxPathViewPrivate::updateItem(QFxItem *item, qreal percent) foreach(const QString &attr, path->attributes()) static_cast<QFxPathViewAttached *>(obj)->setValue(attr.toLatin1(), path->attributeAt(attr, percent)); } - QPointF pf = path->pointAt(percent); item->setX(pf.x() - item->width()*item->scale()/2); item->setY(pf.y() - item->height()*item->scale()/2); @@ -586,7 +597,7 @@ void QFxPathViewPrivate::updateItem(QFxItem *item, qreal percent) void QFxPathView::refill() { Q_D(QFxPathView); - if (!d->model || d->model->count() <= 0) + if (!d->isValid()) return; QList<qreal> positions; @@ -619,28 +630,28 @@ void QFxPathView::refill() if (wrapIndex < d->items.count()/2){ while(wrapIndex-- >= 0){ QFxItem* p = d->items.takeFirst(); + d->updateItem(p, 0.0); attachedProperties.remove(p); d->model->release(p); d->firstIndex++; d->firstIndex %= d->model->count(); int index = (d->firstIndex + d->items.count())%d->model->count(); - d->items << d->model->item(index); + d->items << d->getItem(index); d->items.last()->setZ(wrapIndex); - d->items.last()->setParent(this); d->pathOffset++; d->pathOffset=d->pathOffset % d->items.count(); } } else { while(wrapIndex++ < d->items.count()-1){ QFxItem* p = d->items.takeLast(); + d->updateItem(p, 1.0); attachedProperties.remove(p); d->model->release(p); d->firstIndex--; if (d->firstIndex < 0) d->firstIndex = d->model->count() - 1; - d->items.prepend(d->model->item(d->firstIndex)); + d->items.prepend(d->getItem(d->firstIndex)); d->items.first()->setZ(d->firstIndex); - d->items.first()->setParent(this); d->pathOffset--; if (d->pathOffset < 0) d->pathOffset = d->items.count() - 1; @@ -658,11 +669,12 @@ void QFxPathView::itemsInserted(int modelIndex, int count) { //XXX support animated insertion Q_D(QFxPathView); + if (!d->isValid()) + return; if (d->pathItems == -1) { for (int i = 0; i < count; ++i) { - QFxItem *item = d->model->item(modelIndex + i); + QFxItem *item = d->getItem(modelIndex + i); item->setZ(modelIndex + i); - item->setParent(this); d->items.insert(modelIndex + i, item); } refill(); @@ -687,6 +699,8 @@ void QFxPathView::itemsRemoved(int modelIndex, int count) { //XXX support animated removal Q_D(QFxPathView); + if (!d->isValid()) + return; if (d->pathItems == -1) { for (int i = 0; i < count; ++i) { QFxItem* p = d->items.takeAt(modelIndex); @@ -719,6 +733,19 @@ void QFxPathView::itemsRemoved(int modelIndex, int count) d->moveOffset.setValue(targetOffset); } +void QFxPathView::itemCreated(int index, QFxItem *item) +{ + Q_D(QFxPathView); + if (d->requestedIndex != index) { + item->setItemParent(this); + d->updateItem(item, index < d->firstIndex ? 0.0 : 1.0); + } +} + +void QFxPathView::destroyingItem(QFxItem *item) +{ +} + void QFxPathView::ticked() { Q_D(QFxPathView); diff --git a/src/declarative/fx/qfxpathview.h b/src/declarative/fx/qfxpathview.h index 23f2f07..0e1ac6f 100644 --- a/src/declarative/fx/qfxpathview.h +++ b/src/declarative/fx/qfxpathview.h @@ -115,6 +115,8 @@ private Q_SLOTS: void ticked(); void itemsInserted(int index, int count); void itemsRemoved(int index, int count); + void itemCreated(int index, QFxItem *item); + void destroyingItem(QFxItem *item); protected: QFxPathView(QFxPathViewPrivate &dd, QFxItem *parent); diff --git a/src/declarative/fx/qfxpathview_p.h b/src/declarative/fx/qfxpathview_p.h index a19d778..358daf6 100644 --- a/src/declarative/fx/qfxpathview_p.h +++ b/src/declarative/fx/qfxpathview_p.h @@ -77,7 +77,7 @@ public: : path(0), currentIndex(0), startPc(0), lastDist(0) , lastElapsed(0), stealMouse(false), ownModel(false), activeItem(0) , snapPos(0), dragMargin(0), moveOffset(this, &QFxPathViewPrivate::setOffset) - , firstIndex(0), pathItems(-1), pathOffset(0), model(0) + , firstIndex(0), pathItems(-1), pathOffset(0), requestedIndex(-1), model(0) , moveReason(Other) { fixupOffsetEvent = QmlTimeLineEvent::timeLineEvent<QFxPathViewPrivate, &QFxPathViewPrivate::fixOffset>(&moveOffset, this); @@ -92,6 +92,20 @@ public: q->connect(&tl, SIGNAL(updated()), q, SLOT(ticked())); } + QFxItem *getItem(int modelIndex) { + Q_Q(QFxPathView); + requestedIndex = modelIndex; + QFxItem *item = model->item(modelIndex); + if (item) + item->setItemParent(q); + requestedIndex = -1; + return item; + } + + bool isValid() const { + return model && model->count() > 0 && model->delegate() && path; + } + int calcCurrentIndex(); void updateCurrent(); void fixOffset(); @@ -108,8 +122,8 @@ public: qreal lastDist; int lastElapsed; qreal _offset; - int stealMouse : 1; - int ownModel : 1; + bool stealMouse : 1; + bool ownModel : 1; QTime lastPosTime; QPointF lastPos; QFxItem *activeItem; @@ -121,6 +135,7 @@ public: int firstIndex; int pathItems; int pathOffset; + int requestedIndex; QList<QFxItem *> items; QFxVisualItemModel *model; QVariant modelVariant; diff --git a/src/declarative/fx/qfxvisualitemmodel.cpp b/src/declarative/fx/qfxvisualitemmodel.cpp index 7d0d7a5..9428281 100644 --- a/src/declarative/fx/qfxvisualitemmodel.cpp +++ b/src/declarative/fx/qfxvisualitemmodel.cpp @@ -336,6 +336,10 @@ void QFxVisualItemModel::setModel(const QVariant &model) this, SIGNAL(itemsRemoved(int,int))); QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)), this, SIGNAL(itemsMoved(int,int,int))); + QObject::disconnect(d->m_visualItemModel, SIGNAL(packageCreated(int,QmlPackage*)), + this, SLOT(_q_packageCreated(int,QmlPackage*))); + QObject::disconnect(d->m_visualItemModel, SIGNAL(destroyingPackage(QmlPackage*)), + this, SLOT(_q_destroyingPackage(QmlPackage*))); d->m_visualItemModel = 0; } @@ -385,6 +389,10 @@ void QFxVisualItemModel::setModel(const QVariant &model) this, SIGNAL(itemsRemoved(int,int))); QObject::connect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)), this, SIGNAL(itemsMoved(int,int,int))); + QObject::connect(d->m_visualItemModel, SIGNAL(packageCreated(int,QmlPackage*)), + this, SLOT(_q_packageCreated(int,QmlPackage*))); + QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QmlPackage*)), + this, SLOT(_q_destroyingPackage(QmlPackage*))); return; } if (!d->m_modelList) @@ -397,6 +405,8 @@ void QFxVisualItemModel::setModel(const QVariant &model) QmlComponent *QFxVisualItemModel::delegate() const { Q_D(const QFxVisualItemModel); + if (d->m_visualItemModel) + return d->m_visualItemModel->delegate(); return d->m_delegate; } @@ -404,7 +414,6 @@ void QFxVisualItemModel::setDelegate(QmlComponent *delegate) { Q_D(QFxVisualItemModel); d->m_delegate = delegate; - if (d->modelCount()) emit itemsInserted(0, d->modelCount()); } @@ -445,6 +454,7 @@ void QFxVisualItemModel::release(QFxItem *item) item->setItemParent(0); QObject *obj = item; + bool inPackage = false; if (QmlPackage *package = d->m_packaged.value(item)) { static_cast<QObject*>(item)->setParent(package); d->m_packaged.remove(item); @@ -454,6 +464,7 @@ void QFxVisualItemModel::release(QFxItem *item) if (*iter == package) return; } + inPackage = true; obj = package; // fall through and delete } @@ -461,6 +472,8 @@ void QFxVisualItemModel::release(QFxItem *item) for (QHash<int, QObject *>::Iterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ++iter) { if (*iter == obj) { + if (inPackage) + emit destroyingPackage(qobject_cast<QmlPackage*>(obj)); delete obj; d->m_cache.erase(iter); return; @@ -511,6 +524,7 @@ QFxItem *QFxVisualItemModel::item(int index, const QByteArray &viewId, bool comp QObject *o = package->part(QLatin1String(viewId)); item = qobject_cast<QFxItem *>(o); d->m_packaged[o] = package; + emit packageCreated(index, package); } } @@ -688,6 +702,18 @@ void QFxVisualItemModel::_q_dataChanged(const QModelIndex &begin, const QModelIn _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles); } +void QFxVisualItemModel::_q_packageCreated(int index, QmlPackage *package) +{ + Q_D(QFxVisualItemModel); + emit itemCreated(index, qobject_cast<QFxItem*>(package->part(d->m_part))); +} + +void QFxVisualItemModel::_q_destroyingPackage(QmlPackage *package) +{ + Q_D(QFxVisualItemModel); + emit destroyingItem(qobject_cast<QFxItem*>(package->part(d->m_part))); +} + QML_DEFINE_TYPE(QFxVisualItemModel,VisualModel); QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxvisualitemmodel.h b/src/declarative/fx/qfxvisualitemmodel.h index 5ec42e9..33017e2 100644 --- a/src/declarative/fx/qfxvisualitemmodel.h +++ b/src/declarative/fx/qfxvisualitemmodel.h @@ -60,6 +60,7 @@ QT_MODULE(Declarative) class QFxItem; class QmlComponent; +class QmlPackage; class QFxVisualItemModelPrivate; class QFxVisualItemModel : public QObject { @@ -98,6 +99,10 @@ Q_SIGNALS: void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void itemsMoved(int from, int to, int count); + void itemCreated(int index, QFxItem *item); + void packageCreated(int index, QmlPackage *package); + void destroyingItem(QFxItem *item); + void destroyingPackage(QmlPackage *package); private Q_SLOTS: void _q_itemsChanged(int, int, const QList<int> &); @@ -107,6 +112,8 @@ private Q_SLOTS: void _q_rowsInserted(const QModelIndex &,int,int); void _q_rowsRemoved(const QModelIndex &,int,int); void _q_dataChanged(const QModelIndex&,const QModelIndex&); + void _q_packageCreated(int index, QmlPackage *package); + void _q_destroyingPackage(QmlPackage *package); private: Q_DISABLE_COPY(QFxVisualItemModel) diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index 689446b..a31be81 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -149,16 +149,15 @@ int QmlDomDocument::version() const \sa QmlDomDocument::save() QmlDomDocument::loadError() */ -bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) +bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data, const QUrl &url) { Q_UNUSED(engine); - d->errors.clear(); QmlCompiledComponent component; QmlCompiler compiler; - QmlCompositeTypeData *td = ((QmlEnginePrivate *)QmlEnginePrivate::get(engine))->typeManager.getImmediate(data, QUrl());; + QmlCompositeTypeData *td = ((QmlEnginePrivate *)QmlEnginePrivate::get(engine))->typeManager.getImmediate(data, url);; if(td->status == QmlCompositeTypeData::Error) { d->errors = td->errors; diff --git a/src/declarative/qml/qmldom.h b/src/declarative/qml/qmldom.h index daca888..f90fb08 100644 --- a/src/declarative/qml/qmldom.h +++ b/src/declarative/qml/qmldom.h @@ -73,7 +73,7 @@ public: int version() const; QList<QmlError> errors() const; - bool load(QmlEngine *, const QByteArray &); + bool load(QmlEngine *, const QByteArray &, const QUrl & = QUrl()); QByteArray save() const; QmlDomObject rootObject() const; diff --git a/tests/auto/declarative/qmldom/qmldom.pro b/tests/auto/declarative/qmldom/qmldom.pro index 5294cb4..d566354 100644 --- a/tests/auto/declarative/qmldom/qmldom.pro +++ b/tests/auto/declarative/qmldom/qmldom.pro @@ -1,3 +1,5 @@ load(qttest_p4) contains(QT_CONFIG,declarative): QT += declarative SOURCES += tst_qmldom.cpp + +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/qmldom/tst_qmldom.cpp b/tests/auto/declarative/qmldom/tst_qmldom.cpp index 36d37f6..ca8929d 100644 --- a/tests/auto/declarative/qmldom/tst_qmldom.cpp +++ b/tests/auto/declarative/qmldom/tst_qmldom.cpp @@ -4,6 +4,7 @@ #include <QtDeclarative/qmldom.h> #include <QtCore/QDebug> +#include <QtCore/QFile> class tst_qmldom : public QObject { @@ -15,6 +16,7 @@ private slots: void loadSimple(); void loadProperties(); void loadChildObject(); + void loadComposite(); void testValueSource(); @@ -30,7 +32,7 @@ void tst_qmldom::loadSimple() QmlDomDocument document; QVERIFY(document.load(&engine, qml)); - QVERIFY(document.loadError().isEmpty()); + QVERIFY(document.errors().isEmpty()); QmlDomObject rootObject = document.rootObject(); QVERIFY(rootObject.isValid()); @@ -87,6 +89,27 @@ void tst_qmldom::loadChildObject() QVERIFY(childItem.objectType() == "Item"); } +void tst_qmldom::loadComposite() +{ + QFile file(SRCDIR "/top.qml"); + QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); + + QmlDomDocument document; + QVERIFY(document.load(&engine, file.readAll(), QUrl::fromLocalFile(file.fileName()))); + QVERIFY(document.errors().isEmpty()); + + QmlDomObject rootItem = document.rootObject(); + QVERIFY(rootItem.isValid()); + QCOMPARE(rootItem.objectType(), QByteArray("MyComponent")); + QCOMPARE(rootItem.properties().size(), 2); + + QmlDomProperty widthProperty = rootItem.property("width"); + QVERIFY(widthProperty.value().isLiteral()); + + QmlDomProperty heightProperty = rootItem.property("height"); + QVERIFY(heightProperty.value().isLiteral()); +} + void tst_qmldom::testValueSource() { QByteArray qml = "Rect { height: Follow { spring: 1.4; damping: .15; source: Math.min(Math.max(-130, value*2.2 - 130), 133); }}"; diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp index 3f74ef6..379fda9 100644 --- a/tools/qmlviewer/main.cpp +++ b/tools/qmlviewer/main.cpp @@ -26,7 +26,7 @@ void usage() qWarning(" -v, -version ............................. display version"); qWarning(" -frameless ............................... run with no window frame"); qWarning(" -skin <qvfbskindir> ...................... run with a skin window frame"); - qWarning(" -recordfile <output> ..................... set output file"); + qWarning(" -recordfile <output> ..................... set video recording file"); qWarning(" - ImageMagick 'convert' for GIF)"); qWarning(" - png file for raw frames"); qWarning(" - 'ffmpeg' for other formats"); @@ -69,7 +69,7 @@ int main(int argc, char ** argv) int autorecord_from = 0; int autorecord_to = 0; QString dither = "none"; - QString recordfile = "animation.gif"; + QString recordfile; QString skin; bool devkeys = false; bool cache = false; diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 04054ec..8457972 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -31,6 +31,7 @@ #include <QFile> #include <QFileInfo> #include <QVBoxLayout> +#include <QProgressDialog> #include <QProcess> #include <QMenuBar> #include <QMenu> @@ -86,15 +87,15 @@ void QmlViewer::createMenuBar() fileMenu->addSeparator(); fileMenu->addAction(quitAction); - /*QMenu *recordMenu = menuBar()->addMenu(tr("&Recording")); + QMenu *recordMenu = menuBar()->addMenu(tr("&Recording")); - QAction *snapshotAction = new QAction(tr("&Take Snapsot"), this); + QAction *snapshotAction = new QAction(tr("&Take Snapsot\tF3"), this); connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot())); recordMenu->addAction(snapshotAction); - recordAction = new QAction(tr("&Start Recording Video"), this); - connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecording())); - recordMenu->addAction(recordAction);*/ + recordAction = new QAction(tr("Start Recording &Video\tF2"), this); + connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection())); + recordMenu->addAction(recordAction); QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); QAction *aboutAction = new QAction(tr("&About Qt..."), this); @@ -111,13 +112,31 @@ void QmlViewer::takeSnapShot() ++snapshotcount; } +void QmlViewer::toggleRecordingWithSelection() +{ + if (!recordTimer.isActive()) { + QString fileName = QFileDialog::getSaveFileName(this, tr("Save Video File"), "", tr("Common Video files (*.avi *.mpeg *.mov);; GIF Animation (*.gif);; Individual PNG frames (*.png);; All ffmpeg formats (*.*)")); + if (fileName.isEmpty()) + return; + if (!fileName.contains(QRegExp(".[^\\/]*$"))) + fileName += ".avi"; + setRecordFile(fileName); + } + toggleRecording(); +} + void QmlViewer::toggleRecording() { - bool recording = recordTimer.isActive(); - //recordAction->setText(recording ? tr("&Start Recording Video") : tr("&End Recording Video")); - setRecording(!recording); + if (record_file.isEmpty()) { + toggleRecordingWithSelection(); + return; + } + bool recording = !recordTimer.isActive(); + recordAction->setText(recording ? tr("&Stop Recording Video\tF2") : tr("&Start Recording Video\tF2")); + setRecording(recording); } + void QmlViewer::reload() { openQml(currentFileName); @@ -389,6 +408,9 @@ void QmlViewer::setRecording(bool on) frame_stream->close(); qDebug() << "Wrote" << record_file; } else { + QProgressDialog progress(tr("Saving frames..."), tr("Cancel"), 0, frames.count()+10, this); + progress.setWindowModality(Qt::WindowModal); + int frame=0; QStringList inputs; qDebug() << "Saving frames..."; @@ -406,6 +428,9 @@ void QmlViewer::setRecording(bool on) png_output = false; } foreach (QImage* img, frames) { + progress.setValue(progress.value()+1); + if (progress.wasCanceled()) + break; QString name; name.sprintf(framename.toLocal8Bit(),frame++); if (record_dither=="ordered") @@ -420,31 +445,35 @@ void QmlViewer::setRecording(bool on) delete img; } - if (png_output) { - framename.replace(QRegExp("%\\d*."),"*"); - qDebug() << "Wrote frames" << framename; - inputs.clear(); // don't remove them - } else { - // ImageMagick and gifsicle for GIF encoding - QStringList args; - args << "-delay" << QString::number(record_period/10); - args << inputs; - args << record_file; - qDebug() << "Converting..." << record_file << "(this may take a while)"; - if (0!=QProcess::execute("convert", args)) { - qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted"; + if (!progress.wasCanceled()) { + if (png_output) { + framename.replace(QRegExp("%\\d*."),"*"); + qDebug() << "Wrote frames" << framename; inputs.clear(); // don't remove them - qDebug() << "Wrote frames tmp-frame*.png"; } else { - if (record_file.right(4).toLower() == ".gif") { - qDebug() << "Compressing..." << record_file; - if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << record_file << record_file)) - qWarning() << "Cannot run 'gifsicle' - not compressed"; + // ImageMagick and gifsicle for GIF encoding + progress.setLabelText(tr("Converting frames to GIF file...")); + QStringList args; + args << "-delay" << QString::number(record_period/10); + args << inputs; + args << record_file; + qDebug() << "Converting..." << record_file << "(this may take a while)"; + if (0!=QProcess::execute("convert", args)) { + qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted"; + inputs.clear(); // don't remove them + qDebug() << "Wrote frames tmp-frame*.png"; + } else { + if (record_file.right(4).toLower() == ".gif") { + qDebug() << "Compressing..." << record_file; + if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << record_file << record_file)) + qWarning() << "Cannot run 'gifsicle' - not compressed"; + } + qDebug() << "Wrote" << record_file; } - qDebug() << "Wrote" << record_file; } } + progress.setValue(progress.maximum()-1); foreach (QString name, inputs) QFile::remove(name); diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h index 405e8d9..fc8a427 100644 --- a/tools/qmlviewer/qmlviewer.h +++ b/tools/qmlviewer/qmlviewer.h @@ -50,6 +50,7 @@ public slots: void reload(); void takeSnapShot(); void toggleRecording(); + void toggleRecordingWithSelection(); protected: virtual void keyPressEvent(QKeyEvent *); |