summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Walters <ian.walters@nokia.com>2009-05-07 05:14:04 (GMT)
committerIan Walters <ian.walters@nokia.com>2009-05-07 05:14:04 (GMT)
commit45f531b9863fb64e6d4df2c77af01f14019f217e (patch)
tree8d65d6c7b64bd0aec300a3f396b175fbb70ff747
parent73667e2618ecbd00f6496006fcfc3c56ac99be6d (diff)
parente82217bf8e4ebaba20eb255bd52a9f261467b9d8 (diff)
downloadQt-45f531b9863fb64e6d4df2c77af01f14019f217e.zip
Qt-45f531b9863fb64e6d4df2c77af01f14019f217e.tar.gz
Qt-45f531b9863fb64e6d4df2c77af01f14019f217e.tar.bz2
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
-rw-r--r--demos/declarative/flickr/content/ImageDetails.qml9
-rw-r--r--demos/declarative/flickr/content/Progress.qml25
-rw-r--r--demos/declarative/flickr/flickr.qml8
-rw-r--r--demos/declarative/flickr/flickr2.qml274
-rw-r--r--doc/src/declarative/animation.qdoc17
-rw-r--r--src/declarative/debugger/qmldebugger.cpp154
-rw-r--r--src/declarative/debugger/qmldebugger.h12
-rw-r--r--src/declarative/fx/qfximage.cpp106
-rw-r--r--src/declarative/fx/qfximage.h5
-rw-r--r--src/declarative/fx/qfximage_p.h12
-rw-r--r--src/declarative/fx/qfxpixmap.cpp8
-rw-r--r--src/declarative/fx/qfxpixmap.h3
-rw-r--r--src/declarative/qml/qmlengine.cpp36
-rw-r--r--src/declarative/qml/qmlengine_p.h11
-rw-r--r--src/declarative/qml/qmlmetaproperty.cpp12
-rw-r--r--src/declarative/qml/qmlmetaproperty.h1
-rw-r--r--src/declarative/util/qmlanimation.cpp3
-rw-r--r--src/declarative/util/qmlanimation_p.h14
-rw-r--r--src/declarative/util/qmllistmodel.cpp68
-rw-r--r--tools/qmlviewer/main.cpp1
-rw-r--r--tools/qmlviewer/qmlviewer.cpp42
-rw-r--r--tools/qmlviewer/qmlviewer.h3
22 files changed, 726 insertions, 98 deletions
diff --git a/demos/declarative/flickr/content/ImageDetails.qml b/demos/declarative/flickr/content/ImageDetails.qml
index d721983..955f85d 100644
--- a/demos/declarative/flickr/content/ImageDetails.qml
+++ b/demos/declarative/flickr/content/ImageDetails.qml
@@ -3,7 +3,6 @@ Flipable {
property var frontContainer: ContainerFront
property var flickableArea: Flickable
- property var fullScreenArea: BigImage
property string photoTitle: ""
property string photoDescription: ""
property string photoTags: ""
@@ -73,7 +72,8 @@ Flipable {
Rect { anchors.fill: parent; color: "black"; opacity: 0.4; pen.color: "white"; pen.width: 2 }
- Loading { anchors.centeredIn: parent; visible: BigImage.status }
+// Loading { anchors.centeredIn: parent; visible: BigImage.status }
+ Progress { anchors.centeredIn: parent; width: 200; height: 18; progress: BigImage.progress; visible: BigImage.status }
Flickable {
id: Flick; width: Container.width - 10; height: Container.height - 10
x: 5; y: 5; clip: true; viewportWidth: (BigImage.width * BigImage.scale) + BigImage.x;
@@ -89,6 +89,11 @@ Flipable {
MediaButton {
id: BackButton2; x: 630; y: 370; text: "Back"; onClicked: { Container.state = '' }
}
+ Text {
+ text: "Image Unavailable"
+ visible: BigImage.status == 'Error'
+ anchors.centeredIn: parent; color: "white"; font.bold: true
+ }
Slider { id: Slider; x: 25; y: 374; imageWidth: Container.photoWidth; imageHeight: Container.photoHeight }
}
diff --git a/demos/declarative/flickr/content/Progress.qml b/demos/declarative/flickr/content/Progress.qml
new file mode 100644
index 0000000..92a232e
--- /dev/null
+++ b/demos/declarative/flickr/content/Progress.qml
@@ -0,0 +1,25 @@
+Item {
+ id: Progress;
+
+ property var progress: 0
+
+ Rect {
+ id: Container; anchors.fill: parent; gradientColor: "#66000000";
+ pen.color: "white"; pen.width: 1; color: "#66343434"; radius: height/2 - 2
+ }
+
+ Rect {
+ id: Fill
+ y: 2; height: parent.height-4;
+ x: 2; width: Math.max(parent.width * progress - 4, 0);
+ opacity: width < 1 ? 0 : 1
+ color: "lightsteelblue"; gradientColor: "steelblue"; radius: height/2 - 2
+ }
+
+ Text {
+ text: Math.round(progress * 100) + "%"
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ color: "white"; font.bold: true
+ }
+}
diff --git a/demos/declarative/flickr/flickr.qml b/demos/declarative/flickr/flickr.qml
index 83fd845..85af8e3 100644
--- a/demos/declarative/flickr/flickr.qml
+++ b/demos/declarative/flickr/flickr.qml
@@ -37,14 +37,18 @@ Item {
Connection {
sender: ImageDetails; signal: "closed()"
- script: { if (Wrapper.state == 'Details') Wrapper.state = '' }
+ script: {
+ if (Wrapper.state == 'Details') {
+ Wrapper.state = '';
+ ImageDetails.photoUrl = "";
+ }
+ }
}
Script {
function photoClicked() {
ImageDetails.photoTitle = title;
ImageDetails.flickableArea.yPosition = 0;
- ImageDetails.fullScreenArea.source = "";
ImageDetails.photoDescription = description;
ImageDetails.photoTags = tags;
ImageDetails.photoWidth = photoWidth;
diff --git a/demos/declarative/flickr/flickr2.qml b/demos/declarative/flickr/flickr2.qml
new file mode 100644
index 0000000..4875fa4
--- /dev/null
+++ b/demos/declarative/flickr/flickr2.qml
@@ -0,0 +1,274 @@
+import "content"
+
+Item {
+ id: MainWindow; width: 800; height: 450
+
+ property bool showPathView : false
+
+ VisualModel {
+ id: MyVisualModel
+ model:
+ XmlListModel {
+ id: FeedModel
+ property string tags : ""
+ source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+tags+"&" : "")+"format=rss2"
+ query: "doc($src)/rss/channel/item"
+ namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";"
+
+ Role { name: "title"; query: "title/string()" }
+ Role { name: "imagePath"; query: "media:thumbnail/@url/string()" }
+ Role { name: "url"; query: "media:content/@url/string()" }
+ Role { name: "description"; query: "description/string()"; isCData: true }
+ Role { name: "tags"; query: "media:category/string()" }
+ Role { name: "photoWidth"; query: "media:content/@width/string()" }
+ Role { name: "photoHeight"; query: "media:content/@height/string()" }
+ Role { name: "photoType"; query: "media:content/@type/string()" }
+ Role { name: "photoAuthor"; query: "author/string()" }
+ Role { name: "photoDate"; query: "pubDate/string()" }
+ }
+
+ delegate: Package {
+ Item {
+ id: Wrapper; width: 85; height: 85
+ scale: Wrapper.PathView.scale; z: Wrapper.PathView.z
+
+ transform: [
+ Rotation3D { id: Rotation; axis.startX: 30; axis.endX: 30; axis.endY: 60; angle: Wrapper.PathView.angle }
+ ]
+
+ Connection {
+ sender: ImageDetails; signal: "closed()"
+ script: { if (Wrapper.state == 'Details') Wrapper.state = '' }
+ }
+
+ Script {
+ function photoClicked() {
+ ImageDetails.photoTitle = title;
+ ImageDetails.flickableArea.yPosition = 0;
+ ImageDetails.fullScreenArea.source = "";
+ ImageDetails.photoDescription = description;
+ ImageDetails.photoTags = tags;
+ ImageDetails.photoWidth = photoWidth;
+ ImageDetails.photoHeight = photoHeight;
+ ImageDetails.photoType = photoType;
+ ImageDetails.photoAuthor = photoAuthor;
+ ImageDetails.photoDate = photoDate;
+ ImageDetails.photoUrl = url;
+ ImageDetails.rating = 0;
+ Wrapper.state = "Details";
+ }
+ }
+
+ Rect {
+ id: WhiteRect; anchors.fill: parent; color: "white"; radius: 5
+
+ Loading { x: 26; y: 26; visible: Thumb.status }
+ Image { id: Thumb; source: imagePath; x: 5; y: 5 }
+
+ Item {
+ id: Shadows
+ Image { source: "content/pics/shadow-right.png"; x: WhiteRect.width; height: WhiteRect.height }
+ Image { source: "content/pics/shadow-bottom.png"; y: WhiteRect.height; width: WhiteRect.width }
+ Image { id: Corner; source: "content/pics/shadow-corner.png"; x: WhiteRect.width; y: WhiteRect.height }
+ }
+ }
+
+ MouseRegion { anchors.fill: Wrapper; onClicked: { photoClicked() } }
+
+ states: [
+ State {
+ name: "Details"
+ SetProperties { target: ImageDetails; z: 2 }
+ ParentChange { target: Wrapper; parent: ImageDetails.frontContainer }
+ SetProperties { target: Wrapper; x: 45; y: 35; scale: 1; z: 1000 }
+ SetProperties { target: Rotation; angle: 0 }
+ SetProperties { target: Shadows; opacity: 0 }
+ SetProperties { target: ImageDetails; y: 20 }
+ SetProperties { target: PhotoGridView; y: "-480" }
+ SetProperties { target: PhotoPathView; y: "-480" }
+ SetProperties { target: CloseButton; opacity: 0 }
+ SetProperties { target: FetchButton; opacity: 0 }
+ SetProperties { target: CategoryText; y: "-50" }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ fromState: "*"; toState: "Details"
+ ParentChangeAction { }
+ NumericAnimation { properties: "x,y,scale,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ },
+ Transition {
+ fromState: "Details"; toState: "*"
+ SequentialAnimation {
+ ParentChangeAction { }
+ NumericAnimation { properties: "x,y,scale,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ SetPropertyAction { filter: Wrapper; properties: "z" }
+ }
+ }
+ ]
+ }
+
+ Item {
+ Package.name: "rightBox"
+ id: RightBox; x: 200; width: 85; height: 85
+ }
+
+ Item {
+ Package.name: "leftBox"
+ id: LeftBox; width: 85; height: 85
+ }
+
+ Item {
+ id: MyItem
+ states: [
+ State {
+ name: "left"
+ when: MainWindow.showPathView == true
+ SetProperty {
+ target: Wrapper
+ property: "moveToParent"
+ value: LeftBox
+ }
+ },
+ State {
+ name: "right"
+ when: MainWindow.showPathView == false
+ SetProperty {
+ target: Wrapper
+ property: "moveToParent"
+ value: RightBox
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ fromState: "*"
+ toState: "*"
+ SequentialAnimation {
+ SetPropertyAction {
+ target: Wrapper
+ property: "moveToParent"
+ value: Bounce
+ }
+ ParallelAnimation {
+ NumericAnimation {
+ target: Wrapper
+ properties: "x"
+ to: 0
+ duration: 250
+ }
+ NumericAnimation {
+ target: Wrapper
+ properties: "y"
+ to: 0
+ easing: "easeInQuad"
+ duration: 250
+ }
+ }
+ SetPropertyAction {
+ target: Wrapper
+ property: "moveToParent"
+ }
+ ParallelAnimation {
+ NumericAnimation {
+ target: Wrapper
+ properties: "x"
+ to: 0
+ duration: 250
+ }
+ NumericAnimation {
+ target: Wrapper
+ properties: "y"
+ to: 0
+ easing: "easeOutQuad"
+ duration: 250
+ }
+ }
+ }
+ }
+ ]
+ state: "right"
+ }
+
+ }
+ }
+
+
+ Item {
+ id: Background
+
+ Image { source: "content/pics/background.png"; opaque: true }
+
+ GridView {
+ id: PhotoGridView; model: MyVisualModel.parts.leftBox
+ cellWidth: 105; cellHeight: 105; x:32; y: 80; width: 800; height: 330; z: 1
+ }
+
+ PathView {
+ id: PhotoPathView; model: MyVisualModel.parts.rightBox
+ y: 80; width: 800; height: 330; z: 1
+ path: Path {
+ startX: -50; startY: 40;
+
+ PathAttribute { name: "scale"; value: 1 }
+ PathAttribute { name: "angle"; value: -45 }
+
+ PathCubic {
+ x: 400; y: 220
+ control1X: 140; control1Y: 40
+ control2X: 210; control2Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1.2 }
+ PathAttribute { name: "z"; value: 1 }
+ PathAttribute { name: "angle"; value: 0 }
+
+ PathCubic {
+ x: 850; y: 40
+ control2X: 660; control2Y: 40
+ control1X: 590; control1Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1 }
+ PathAttribute { name: "angle"; value: -45 }
+ }
+
+ }
+
+ ImageDetails { id: ImageDetails; width: 750; x: 25; y: 500; height: 410 }
+
+ MediaButton {
+ id: CloseButton; x: 680; y: 410; text: "View Mode"
+ onClicked: { if (MainWindow.showPathView == true) MainWindow.showPathView = false; else MainWindow.showPathView = true }
+ }
+
+ MediaButton {
+ id: FetchButton
+ text: "Update"
+ anchors.right: CloseButton.left; anchors.rightMargin: 5
+ anchors.top: CloseButton.top
+ onClicked: { FeedModel.reload(); }
+ }
+
+ states: [
+ State {
+ name: "PathView"
+ }
+ ]
+
+ transitions: [
+ Transition {
+ fromState: "*"; toState: "*"
+ NumericAnimation { properties: "y"; duration: 650; easing: "easeOutBounce(amplitude:0.1)" }
+ }
+ ]
+ }
+
+ Text {
+ id: CategoryText; anchors.horizontalCenter: parent.horizontalCenter; y: 15;
+ text: "Flickr - " +
+ (FeedModel.tags=="" ? "Uploads from everyone" : "Recent Uploads tagged " + FeedModel.tags)
+ font.size: 16; font.bold: true; color: "white"; style: "Raised"; styleColor: "black"
+ }
+}
diff --git a/doc/src/declarative/animation.qdoc b/doc/src/declarative/animation.qdoc
index f7e03ee..f17f5c9 100644
--- a/doc/src/declarative/animation.qdoc
+++ b/doc/src/declarative/animation.qdoc
@@ -25,7 +25,7 @@ Other Features:
\o Animation synchronization
\endlist
-The simplest form of animation is using \c NumericAnimation
+The simplest form of animation is using \l NumericAnimation
The following example creates a bouncing effect:
\code
@@ -34,20 +34,15 @@ Rect {
width: 120; height: 200; color: "white"
Image {
id: img
- source: "pics/qtlogo.png"
+ source: "qt-logo.png"
x: 60-img.width/2
- y: 200-img.height
+ y: 0
y: SequentialAnimation {
running: true
repeat: true
- NumericAnimation {
- to: 200-img.height
- easing: "easeOutBounce(amplitude:100)"
- duration: 2000
- }
- PauseAnimation {
- duration: 1000
- }
+ NumericAnimation { to: 200-img.height; easing: "easeOutBounce"; duration: 2000 }
+ PauseAnimation { duration: 1000 }
+ NumericAnimation { to: 0; easing: "easeOutQuad"; duration: 1000 }
}
}
}
diff --git a/src/declarative/debugger/qmldebugger.cpp b/src/declarative/debugger/qmldebugger.cpp
index 033a15f..a1956f9 100644
--- a/src/declarative/debugger/qmldebugger.cpp
+++ b/src/declarative/debugger/qmldebugger.cpp
@@ -43,6 +43,8 @@
#include <QtGui/qtreewidget.h>
#include <QtGui/qboxlayout.h>
#include <QtGui/qplaintextedit.h>
+#include <QTextBlock>
+#include <QtGui/qtabwidget.h>
#include <QtDeclarative/qmlbindablevalue.h>
#include <private/qmlboundsignal_p.h>
#include <private/qmlcontext_p.h>
@@ -52,10 +54,11 @@
#include <QtCore/qurl.h>
#include <QtGui/qsplitter.h>
#include <QtGui/qpushbutton.h>
+#include <QtGui/qtablewidget.h>
#include <QtGui/qevent.h>
QmlDebugger::QmlDebugger(QWidget *parent)
-: QWidget(parent), m_tree(0)
+: QWidget(parent), m_tree(0), m_warnings(0), m_watchers(0), m_text(0)
{
QHBoxLayout *layout = new QHBoxLayout;
setLayout(layout);
@@ -69,18 +72,34 @@ QmlDebugger::QmlDebugger(QWidget *parent)
splitter->addWidget(treeWid);
m_tree = new QTreeWidget(treeWid);
+ m_tree->setSelectionMode(QTreeWidget::NoSelection);
m_tree->setHeaderHidden(true);
- QObject::connect(m_tree, SIGNAL(itemPressed(QTreeWidgetItem *, int)), this, SLOT(itemPressed(QTreeWidgetItem *)));
+ QObject::connect(m_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(itemClicked(QTreeWidgetItem *)));
+ QObject::connect(m_tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(itemDoubleClicked(QTreeWidgetItem *)));
vlayout->addWidget(m_tree);
QPushButton *pb = new QPushButton("Refresh", treeWid);
QObject::connect(pb, SIGNAL(clicked()), this, SLOT(refresh()));
vlayout->addWidget(pb);
+ QTabWidget *tabs = new QTabWidget(this);
+
m_text = new QPlainTextEdit(this);
m_text->setReadOnly(true);
- splitter->addWidget(m_text);
+ tabs->addTab(m_text, "File");
+
+ m_warnings = new QTreeWidget(this);
+ m_warnings->setHeaderHidden(true);
+ tabs->addTab(m_warnings, "Warnings");
+
+ m_watchers = new QTableWidget(this);
+ m_watchers->setSelectionMode(QTableWidget::NoSelection);
+ tabs->addTab(m_watchers, "Watchers");
+
+ splitter->addWidget(tabs);
splitter->setStretchFactor(1, 2);
+
+ setGeometry(0, 100, 800, 600);
}
class QmlDebuggerItem : public QTreeWidgetItem
@@ -103,31 +122,29 @@ public:
QPointer<QmlBindableValue> bindableValue;
};
-void QmlDebugger::itemPressed(QTreeWidgetItem *i)
+void QmlDebugger::itemDoubleClicked(QTreeWidgetItem *i)
{
QmlDebuggerItem *item = static_cast<QmlDebuggerItem *>(i);
if(item->bindableValue) {
- QString str;
-
QmlExpressionPrivate *p = item->bindableValue->d;
- if(p->log) {
- QString str;
- QDebug d(&str);
- for(int ii = 0; ii < p->log->count(); ++ii) {
- d << p->log->at(ii).result() << "\n";
- QStringList warnings = p->log->at(ii).warnings();
- foreach(const QString &warning, warnings)
- d << " " << warning << "\n";
- }
- m_text->setPlainText(str);
+ if(m_watchedIds.contains(p->id)) {
+ m_watchedIds.remove(p->id);
+ item->setForeground(0, Qt::green);
} else {
- m_text->setPlainText("No history");
+ m_watchedIds.insert(p->id);
+ item->setForeground(0, QColor("purple"));
}
- } else if(item->url.scheme() == QLatin1String("file")) {
+ }
+}
+
+void QmlDebugger::itemClicked(QTreeWidgetItem *i)
+{
+ QmlDebuggerItem *item = static_cast<QmlDebuggerItem *>(i);
+ if(item->url.scheme() == QLatin1String("file")) {
QString f = item->url.toLocalFile();
QFile file(f);
file.open(QIODevice::ReadOnly);
@@ -141,17 +158,11 @@ void QmlDebugger::itemPressed(QTreeWidgetItem *i)
QTextDocument *document = m_text->document();
QTextCharFormat format;
format.setForeground(Qt::lightGray);
- {
- QTextCursor cursor(document);
- cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
- cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor, item->startLine - 1);
- cursor.setCharFormat(format);
- }
{
QTextCursor cursor(document);
cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
- cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, item->endLine);
+ cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, item->endLine);
cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
cursor.setCharFormat(format);
}
@@ -159,31 +170,87 @@ void QmlDebugger::itemPressed(QTreeWidgetItem *i)
{
QTextCursor cursor(document);
cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
- cursor.setCharFormat(QTextCharFormat());
+ cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor, item->startLine - 1);
+ cursor.setCharFormat(format);
}
{
QTextCursor cursor(document);
cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
- cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, item->startLine - 1);
+ cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, item->startLine - 1);
m_text->setTextCursor(cursor);
m_text->centerCursor();
}
+
+
}
}
}
-static bool makeItem(QObject *obj, QmlDebuggerItem *item)
+bool QmlDebugger::makeItem(QObject *obj, QmlDebuggerItem *item)
{
bool rv = true;
QString text;
if(QmlBindableValue *bv = qobject_cast<QmlBindableValue *>(obj)) {
+ QmlExpressionPrivate *p = bv->d;
+
text = bv->property().name() + ": " + bv->expression();
- item->setForeground(0, Qt::green);
+ bool watched = m_watchedIds.contains(p->id);
+ if(watched)
+ item->setForeground(0, QColor("purple"));
+ else
+ item->setForeground(0, Qt::green);
item->bindableValue = bv;
+
+ if(p->log) {
+ QTreeWidgetItem *warningItem = 0;
+
+ int column = m_watchers->columnCount();
+
+ if(watched) {
+ m_watchers->insertColumn(column);
+ QTableWidgetItem *tableheader = new QTableWidgetItem;
+ tableheader->setText(bv->expression());
+ tableheader->setToolTip(bv->expression());
+ m_watchers->setHorizontalHeaderItem(column, tableheader);
+ }
+
+ for(int ii = 0; ii < p->log->count(); ++ii) {
+ const QmlExpressionLog &log = p->log->at(ii);
+
+ QString variant; QDebug d(&variant); d << log.result();
+ if(watched) {
+ QString str = log.result().toString();
+ if(str.isEmpty())
+ str = variant;
+ m_expressions << qMakePair(log.time(), qMakePair(column, str));
+ }
+
+ if(!log.warnings().isEmpty()) {
+
+ if(!warningItem) {
+ warningItem = new QTreeWidgetItem(m_warnings);
+ warningItem->setText(0, bv->expression());
+ }
+
+ QTreeWidgetItem *entry = new QTreeWidgetItem(warningItem);
+ entry->setExpanded(true);
+
+ entry->setText(0, variant);
+
+ foreach(const QString &warning, log.warnings()) {
+ QTreeWidgetItem *w = new QTreeWidgetItem(entry);
+ w->setText(0, warning);
+ }
+ }
+
+ }
+
+ }
+
} else if(QmlBoundSignal *bs = qobject_cast<QmlBoundSignal *>(obj)) {
QMetaMethod method = obj->parent()->metaObject()->method(bs->index());
QByteArray sig = method.signature();
@@ -237,7 +304,7 @@ static bool makeItem(QObject *obj, QmlDebuggerItem *item)
return rv;
}
-static void buildTree(QObject *obj, QmlDebuggerItem *parent)
+void QmlDebugger::buildTree(QObject *obj, QmlDebuggerItem *parent)
{
QObjectList children = obj->children();
@@ -253,9 +320,20 @@ void QmlDebugger::refresh()
setDebugObject(m_object);
}
+bool operator<(const QPair<quint32, QPair<int, QString> > &lhs,
+ const QPair<quint32, QPair<int, QString> > &rhs)
+{
+ return lhs.first < rhs.first;
+}
+
void QmlDebugger::setDebugObject(QObject *obj)
{
m_tree->clear();
+ m_warnings->clear();
+ m_watchers->clear();
+ m_watchers->setColumnCount(0);
+ m_watchers->setRowCount(0);
+ m_expressions.clear();
m_object = obj;
if(!obj)
@@ -265,6 +343,20 @@ void QmlDebugger::setDebugObject(QObject *obj)
makeItem(obj, item);
buildTree(obj, item);
item->setExpanded(true);
- setGeometry(0, 100, 800, 600);
+
+ m_watchers->setRowCount(m_expressions.count());
+
+ qSort(m_expressions.begin(), m_expressions.end());
+
+ for(int ii = 0; ii < m_expressions.count(); ++ii) {
+
+ const QPair<quint32, QPair<int, QString> > &expr = m_expressions.at(ii);
+ QTableWidgetItem *item = new QTableWidgetItem;
+ item->setText(expr.second.second);
+ m_watchers->setItem(ii, expr.second.first, item);
+
+ }
+
+
}
diff --git a/src/declarative/debugger/qmldebugger.h b/src/declarative/debugger/qmldebugger.h
index 943abef..e04eb2e 100644
--- a/src/declarative/debugger/qmldebugger.h
+++ b/src/declarative/debugger/qmldebugger.h
@@ -43,6 +43,7 @@
#define QMLDEBUGGER_H
#include <QtCore/qpointer.h>
+#include <QtCore/qset.h>
#include <QtGui/qwidget.h>
QT_BEGIN_HEADER
@@ -54,6 +55,8 @@ QT_MODULE(Declarative)
class QTreeWidget;
class QTreeWidgetItem;
class QPlainTextEdit;
+class QmlDebuggerItem;
+class QTableWidget;
class QmlDebugger : public QWidget
{
Q_OBJECT
@@ -66,12 +69,19 @@ public slots:
void refresh();
private slots:
- void itemPressed(QTreeWidgetItem *);
+ void itemClicked(QTreeWidgetItem *);
+ void itemDoubleClicked(QTreeWidgetItem *);
private:
+ void buildTree(QObject *obj, QmlDebuggerItem *parent);
+ bool makeItem(QObject *obj, QmlDebuggerItem *item);
QTreeWidget *m_tree;
+ QTreeWidget *m_warnings;
+ QTableWidget *m_watchers;
QPlainTextEdit *m_text;
QPointer<QObject> m_object;
+ QList<QPair<quint32, QPair<int, QString> > > m_expressions;
+ QSet<quint32> m_watchedIds;
};
QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp
index 106d551..d66846d 100644
--- a/src/declarative/fx/qfximage.cpp
+++ b/src/declarative/fx/qfximage.cpp
@@ -125,8 +125,8 @@ QFxImage::QFxImage(QFxImagePrivate &dd, QFxItem *parent)
QFxImage::~QFxImage()
{
Q_D(const QFxImage);
- if (d->reply)
- d->reply->deleteLater();
+ if (d->sciReply)
+ d->sciReply->deleteLater();
}
/*!
@@ -783,6 +783,19 @@ QString QFxImage::propertyInfo() const
return d->url.toString();
}
+/*!
+ \qmlproperty enum Image::status
+
+ This property holds the status of image loading. It can be one of:
+ \list
+ \o Idle - no image has been set, or the image has been loaded
+ \o Loading - the images is currently being loaded
+ \o Error - an error occurred while loading the image
+ \endlist
+
+ \sa progress
+*/
+
QFxImage::Status QFxImage::status() const
{
Q_D(const QFxImage);
@@ -790,6 +803,21 @@ QFxImage::Status QFxImage::status() const
}
/*!
+ \qmlproperty real Image::progress
+
+ This property holds the progress of image loading, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+
+ \sa status
+*/
+
+qreal QFxImage::progress() const
+{
+ Q_D(const QFxImage);
+ return d->progress;
+}
+
+/*!
\qmlproperty string Image::source
Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt.
@@ -831,9 +859,9 @@ void QFxImage::setSource(const QString &url)
if (url == d->source)
return;
- if (d->reply) {
- d->reply->deleteLater();
- d->reply = 0;
+ if (d->sciReply) {
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
}
if (!d->url.isEmpty())
@@ -844,10 +872,25 @@ void QFxImage::setSource(const QString &url)
d->source = url;
d->url = qmlContext(this)->resolvedUrl(url);
d->sciurl = QUrl();
+ if (d->progress != 0.0) {
+ d->progress = 0.0;
+ emit progressChanged(d->progress);
+ }
if (url.isEmpty()) {
setPixmap(QPixmap());
d->status = Idle;
+ d->progress = 1.0;
+ setImplicitWidth(0);
+ setImplicitHeight(0);
+#if defined(QFX_RENDER_OPENGL)
+ d->_texDirty = true;
+ d->_tex.clear();
+#endif
+ emit statusChanged(d->status);
+ emit sourceChanged(d->source);
+ emit progressChanged(1.0);
+ update();
} else {
d->status = Loading;
if (d->url.path().endsWith(QLatin1String(".sci"))) {
@@ -861,12 +904,19 @@ void QFxImage::setSource(const QString &url)
{
QNetworkRequest req(d->url);
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
- d->reply = qmlEngine(this)->networkAccessManager()->get(req);
- QObject::connect(d->reply, SIGNAL(finished()),
+ d->sciReply = qmlEngine(this)->networkAccessManager()->get(req);
+ QObject::connect(d->sciReply, SIGNAL(finished()),
this, SLOT(sciRequestFinished()));
}
} else {
- QFxPixmap::get(qmlEngine(this), d->url, this, SLOT(requestFinished()));
+ d->reply = QFxPixmap::get(qmlEngine(this), d->url, this, SLOT(requestFinished()));
+ if (d->reply) {
+ connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ } else {
+ d->progress = 1.0;
+ emit progressChanged(d->progress);
+ }
}
}
@@ -879,6 +929,12 @@ void QFxImage::requestFinished()
if (d->url.path().endsWith(QLatin1String(".sci"))) {
d->_pix = QFxPixmap(d->sciurl);
} else {
+ if (d->reply) {
+ disconnect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ if (d->reply->error() != QNetworkReply::NoError)
+ d->status = Error;
+ }
d->_pix = QFxPixmap(d->url);
d->_pix.setOpaque(d->_opaque);
setOptions(QFxImage::SimpleItem, true);
@@ -886,32 +942,43 @@ void QFxImage::requestFinished()
setImplicitWidth(d->_pix.width());
setImplicitHeight(d->_pix.height());
- d->status = Idle;
+ if (d->status == Loading)
+ d->status = Idle;
+ d->progress = 1.0;
#if defined(QFX_RENDER_OPENGL)
d->_texDirty = true;
d->_tex.clear();
#endif
emit statusChanged(d->status);
emit sourceChanged(d->source);
+ emit progressChanged(1.0);
update();
}
void QFxImage::sciRequestFinished()
{
Q_D(QFxImage);
- if (d->reply->error() != QNetworkReply::NoError) {
+ if (d->sciReply->error() != QNetworkReply::NoError) {
d->status = Error;
- d->reply->deleteLater();
- d->reply = 0;
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
emit statusChanged(d->status);
} else {
- QFxGridScaledImage sci(d->reply);
- d->reply->deleteLater();
- d->reply = 0;
+ QFxGridScaledImage sci(d->sciReply);
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
setGridScaledImage(sci);
}
}
+void QFxImage::requestProgress(qint64 received, qint64 total)
+{
+ Q_D(QFxImage);
+ if (d->status == Loading && total > 0) {
+ d->progress = qreal(received)/total;
+ emit progressChanged(d->progress);
+ }
+}
void QFxImage::setGridScaledImage(const QFxGridScaledImage& sci)
{
@@ -921,7 +988,14 @@ void QFxImage::setGridScaledImage(const QFxGridScaledImage& sci)
emit statusChanged(d->status);
} else {
d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl()));
- QFxPixmap::get(qmlEngine(this), d->sciurl, this, SLOT(requestFinished()));
+ d->reply = QFxPixmap::get(qmlEngine(this), d->sciurl, this, SLOT(requestFinished()));
+ if (d->reply) {
+ connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ } else {
+ d->progress = 1.0;
+ emit progressChanged(d->progress);
+ }
QFxScaleGrid *sg = scaleGrid();
sg->setTop(sci.gridTop());
sg->setBottom(sci.gridBottom());
diff --git a/src/declarative/fx/qfximage.h b/src/declarative/fx/qfximage.h
index 37fe5be..dc13a97 100644
--- a/src/declarative/fx/qfximage.h
+++ b/src/declarative/fx/qfximage.h
@@ -43,6 +43,7 @@
#define QFXIMAGE_H
#include <qfxitem.h>
+#include <QtNetwork/qnetworkreply.h>
QT_BEGIN_HEADER
@@ -58,6 +59,7 @@ class Q_DECLARATIVE_EXPORT QFxImage : public QFxItem
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
Q_PROPERTY(QFxScaleGrid *scaleGrid READ scaleGrid)
Q_PROPERTY(bool tile READ isTiled WRITE setTiled)
@@ -84,6 +86,7 @@ public:
enum Status { Idle, Loading, Error };
Status status() const;
+ qreal progress() const;
QString source() const;
virtual void setSource(const QString &url);
@@ -101,6 +104,7 @@ public:
Q_SIGNALS:
void sourceChanged(const QString &);
void statusChanged(Status);
+ void progressChanged(qreal progress);
protected:
QFxImage(QFxImagePrivate &dd, QFxItem *parent);
@@ -109,6 +113,7 @@ protected:
private Q_SLOTS:
void requestFinished();
void sciRequestFinished();
+ void requestProgress(qint64,qint64);
private:
Q_DISABLE_COPY(QFxImage)
diff --git a/src/declarative/fx/qfximage_p.h b/src/declarative/fx/qfximage_p.h
index fbb4c44..8227ce4 100644
--- a/src/declarative/fx/qfximage_p.h
+++ b/src/declarative/fx/qfximage_p.h
@@ -76,7 +76,7 @@ public:
#if defined(QFX_RENDER_OPENGL)
_texDirty(true),
#endif
- status(QFxImage::Idle), reply(0)
+ status(QFxImage::Idle), sciReply(0), progress(0.0)
{
}
@@ -95,10 +95,10 @@ public:
}
QFxScaleGrid *_scaleGrid;
- bool _tiled;
QFxPixmap _pix;
- bool _smooth;
- bool _opaque;
+ bool _tiled : 1;
+ bool _smooth : 1;
+ bool _opaque : 1;
#if defined(QFX_RENDER_OPENGL)
void checkDirty();
bool _texDirty;
@@ -109,7 +109,9 @@ public:
QString source;
QUrl url;
QUrl sciurl;
- QNetworkReply *reply;
+ QNetworkReply *sciReply;
+ QPointer<QNetworkReply> reply;
+ qreal progress;
};
QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxpixmap.cpp b/src/declarative/fx/qfxpixmap.cpp
index 0d456c6..3fdd8e5 100644
--- a/src/declarative/fx/qfxpixmap.cpp
+++ b/src/declarative/fx/qfxpixmap.cpp
@@ -233,8 +233,11 @@ QFxPixmap::operator const QSimpleCanvasConfig::Image &() const
Starts a network request to load \a url. When the URL is loaded,
the given slot is invoked. Note that if the image is already cached,
the slot may be invoked immediately.
+
+ Returns a QNetworkReply if the image is not immediately available, otherwise
+ returns 0. The QNetworkReply must not be stored - it may be destroyed at any time.
*/
-void QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char* slot)
+QNetworkReply *QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char* slot)
{
QString key = url.toString();
QFxPixmapCache::Iterator iter = qfxPixmapCache.find(key);
@@ -259,11 +262,14 @@ void QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char
if ((*iter)->reply) {
// still loading
QObject::connect((*iter)->reply, SIGNAL(finished()), obj, slot);
+ return (*iter)->reply;
} else {
// already loaded
QObject dummy;
QObject::connect(&dummy, SIGNAL(destroyed()), obj, slot);
}
+
+ return 0;
}
/*!
diff --git a/src/declarative/fx/qfxpixmap.h b/src/declarative/fx/qfxpixmap.h
index 9a3ba4e..748991e 100644
--- a/src/declarative/fx/qfxpixmap.h
+++ b/src/declarative/fx/qfxpixmap.h
@@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class QmlEngine;
+class QNetworkReply;
class QFxPixmapPrivate;
class Q_DECLARATIVE_EXPORT QFxPixmap
{
@@ -65,7 +66,7 @@ public:
QFxPixmap &operator=(const QFxPixmap &);
- static void get(QmlEngine *, const QUrl& url, QObject*, const char* slot);
+ static QNetworkReply *get(QmlEngine *, const QUrl& url, QObject*, const char* slot);
static void cancelGet(const QUrl& url, QObject* obj, const char* slot);
bool isNull() const;
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index be5226e..15b5879 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -139,7 +139,7 @@ QStack<QmlEngine *> *QmlEngineStack::engines()
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e)
: rootContext(0), currentBindContext(0), currentExpression(0), q(e),
- rootComponent(0), networkAccessManager(0), typeManager(e)
+ rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1)
{
QScriptValue proto = scriptEngine.newObject();
proto.setProperty(QLatin1String("emit"),
@@ -720,17 +720,17 @@ QmlEngine *QmlEngine::activeEngine()
QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b)
-: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), log(0)
+: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), id(0), log(0)
{
}
QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc)
-: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), log(0)
+: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), id(0), log(0)
{
}
QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr, bool ssecompile)
-: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), log(0)
+: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), id(0), log(0)
{
if (ssecompile) {
#ifdef Q_ENABLE_PERFORMANCE_LOG
@@ -765,6 +765,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr,
: d(new QmlExpressionPrivate(this, expr, rc))
{
d->ctxt = ctxt;
+ if(ctxt && ctxt->engine())
+ d->id = ctxt->engine()->d_func()->getUniqueId();
d->me = me;
}
@@ -774,6 +776,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expr,
: d(new QmlExpressionPrivate(this, expr, ssecompile))
{
d->ctxt = ctxt;
+ if(ctxt && ctxt->engine())
+ d->id = ctxt->engine()->d_func()->getUniqueId();
d->me = me;
}
@@ -789,6 +793,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression,
: d(new QmlExpressionPrivate(this, expression, true))
{
d->ctxt = ctxt;
+ if(ctxt && ctxt->engine())
+ d->id = ctxt->engine()->d_func()->getUniqueId();
d->me = scope;
}
@@ -810,7 +816,7 @@ QmlEngine *QmlExpression::engine() const
}
/*!
- Returns teh QmlContext this expression is associated with, or 0 if there
+ Returns the QmlContext this expression is associated with, or 0 if there
is no association or the QmlContext has been destroyed.
*/
QmlContext *QmlExpression::context() const
@@ -988,6 +994,7 @@ QVariant QmlExpression::value()
if(qmlDebugger()) {
QmlExpressionLog log;
+ log.setTime(engine()->d_func()->getUniqueId());
log.setExpression(expression());
log.setResult(rv);
@@ -997,8 +1004,8 @@ QVariant QmlExpression::value()
if (prop.hasChangedNotifier()) {
prop.connectNotifier(d->proxy, changedIndex);
- } else {
- QString warn = QLatin1String("Expression depends on property without a NOTIFY signal: ") + QLatin1String(prop.object()->metaObject()->className()) + QLatin1String(".") + prop.name();
+ } else if (prop.needsChangedNotifier()) {
+ QString warn = QLatin1String("Expression depends on property without a NOTIFY signal: [") + QLatin1String(prop.object()->metaObject()->className()) + QLatin1String("].") + prop.name();
log.addWarning(warn);
}
}
@@ -1015,6 +1022,7 @@ QVariant QmlExpression::value()
}
} else {
QmlExpressionLog log;
+ log.setTime(engine()->d_func()->getUniqueId());
log.setExpression(expression());
log.setResult(rv);
d->addLog(log);
@@ -1023,6 +1031,7 @@ QVariant QmlExpression::value()
} else {
if(qmlDebugger()) {
QmlExpressionLog log;
+ log.setTime(engine()->d_func()->getUniqueId());
log.setExpression(expression());
log.setResult(rv);
d->addLog(log);
@@ -1421,7 +1430,8 @@ QmlExpressionLog::QmlExpressionLog()
}
QmlExpressionLog::QmlExpressionLog(const QmlExpressionLog &o)
-: m_expression(o.m_expression),
+: m_time(o.m_time),
+ m_expression(o.m_expression),
m_result(o.m_result),
m_warnings(o.m_warnings)
{
@@ -1433,12 +1443,22 @@ QmlExpressionLog::~QmlExpressionLog()
QmlExpressionLog &QmlExpressionLog::operator=(const QmlExpressionLog &o)
{
+ m_time = o.m_time;
m_expression = o.m_expression;
m_result = o.m_result;
m_warnings = o.m_warnings;
return *this;
}
+void QmlExpressionLog::setTime(quint32 time)
+{
+ m_time = time;
+}
+
+quint32 QmlExpressionLog::time() const
+{
+ return m_time;
+}
QString QmlExpressionLog::expression() const
{
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index 7d5176e..63df0ba 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -114,6 +114,11 @@ public:
QmlCompositeTypeManager typeManager;
QMap<QString,QString> nameSpacePaths;
+
+ mutable quint32 uniqueId;
+ quint32 getUniqueId() const {
+ return uniqueId++;
+ }
};
@@ -201,6 +206,9 @@ public:
QmlExpressionLog &operator=(const QmlExpressionLog &);
+ void setTime(quint32);
+ quint32 time() const;
+
QString expression() const;
void setExpression(const QString &);
@@ -211,6 +219,7 @@ public:
void setResult(const QVariant &);
private:
+ quint32 m_time;
QString m_expression;
QVariant m_result;
QStringList m_warnings;
@@ -233,6 +242,8 @@ public:
QObject *me;
bool trackChange;
+ quint32 id;
+
void addLog(const QmlExpressionLog &);
QList<QmlExpressionLog> *log;
};
diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp
index 40c9b0e..59d6b38 100644
--- a/src/declarative/qml/qmlmetaproperty.cpp
+++ b/src/declarative/qml/qmlmetaproperty.cpp
@@ -988,6 +988,18 @@ bool QmlMetaProperty::hasChangedNotifier() const
}
/*!
+ Returns true if the property needs a change notifier signal for bindings
+ to remain upto date, false otherwise.
+
+ Some properties, such as attached properties or those whose value never
+ changes, do not require a change notifier.
+*/
+bool QmlMetaProperty::needsChangedNotifier() const
+{
+ return type() & Property && !(type() & Attached);
+}
+
+/*!
Connects the property's change notifier signal to the
specified \a method of the \a dest object and returns
true. Returns false if this metaproperty does not
diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h
index 4836038..68b06e5 100644
--- a/src/declarative/qml/qmlmetaproperty.h
+++ b/src/declarative/qml/qmlmetaproperty.h
@@ -89,6 +89,7 @@ public:
void emitSignal();
bool hasChangedNotifier() const;
+ bool needsChangedNotifier() const;
bool connectNotifier(QObject *dest, const char *slot) const;
bool connectNotifier(QObject *dest, int method) const;
diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp
index 08a7a28..dd4e1eb 100644
--- a/src/declarative/util/qmlanimation.cpp
+++ b/src/declarative/util/qmlanimation.cpp
@@ -791,6 +791,7 @@ void QmlColorAnimation::prepare(QmlMetaProperty &p)
d->fromSourced = false;
d->value.QmlTimeLineValue::setValue(0.);
d->ca->setAnimValue(&d->value, QAbstractAnimation::KeepWhenStopped);
+ d->ca->setFromSourcedValue(&d->fromSourced);
}
QAbstractAnimation *QmlColorAnimation::qtAnimation()
@@ -1595,6 +1596,7 @@ void QmlNumericAnimation::prepare(QmlMetaProperty &p)
d->fromSourced = false;
d->value.QmlTimeLineValue::setValue(0.);
d->na->setAnimValue(&d->value, QAbstractAnimation::KeepWhenStopped);
+ d->na->setFromSourcedValue(&d->fromSourced);
}
QAbstractAnimation *QmlNumericAnimation::qtAnimation()
@@ -2152,6 +2154,7 @@ void QmlVariantAnimation::prepare(QmlMetaProperty &p)
d->fromSourced = false;
d->value.QmlTimeLineValue::setValue(0.);
d->va->setAnimValue(&d->value, QAbstractAnimation::KeepWhenStopped);
+ d->va->setFromSourcedValue(&d->fromSourced);
}
void QmlVariantAnimation::transition(QmlStateActions &actions,
diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h
index 06b7c08..00937a6 100644
--- a/src/declarative/util/qmlanimation_p.h
+++ b/src/declarative/util/qmlanimation_p.h
@@ -116,8 +116,7 @@ private:
class QmlTimeLineValueAnimator : public QVariantAnimation
{
public:
- QmlTimeLineValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), policy(KeepWhenStopped) {}
- QmlTimeLineValueAnimator(QmlTimeLineValue *value, QObject *parent = 0) : QVariantAnimation(parent), animValue(value), policy(KeepWhenStopped) {}
+ QmlTimeLineValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), fromSourced(0), policy(KeepWhenStopped) {}
void setAnimValue(QmlTimeLineValue *value, DeletionPolicy p)
{
if (state() == Running)
@@ -125,6 +124,10 @@ public:
animValue = value;
policy = p;
}
+ void setFromSourcedValue(bool *value)
+ {
+ fromSourced = value;
+ }
protected:
virtual void updateCurrentValue(const QVariant &value)
{
@@ -134,7 +137,11 @@ protected:
virtual void updateState(State oldState, State newState)
{
QVariantAnimation::updateState(oldState, newState);
- if (newState == Stopped && policy == DeleteWhenStopped) {
+ if (newState == Running) {
+ //check for new from every loop
+ if (fromSourced)
+ *fromSourced = false;
+ } else if (newState == Stopped && policy == DeleteWhenStopped) {
delete animValue;
animValue = 0;
}
@@ -142,6 +149,7 @@ protected:
private:
QmlTimeLineValue *animValue;
+ bool *fromSourced;
DeletionPolicy policy;
};
diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp
index 1cd2f69..8184bda 100644
--- a/src/declarative/util/qmllistmodel.cpp
+++ b/src/declarative/util/qmllistmodel.cpp
@@ -93,8 +93,7 @@ Q_DECLARE_METATYPE(QListModelInterface *);
}
\endcode
- Elements beginning with a capital are items. Elements beginning
- with lower-case are the data roles. The above example defines a
+ Item roles (properties) must begin with a lower-case letter. The above example defines a
ListModel containing three items, with the roles "name" and "cost".
The defined model can be used in views such as ListView:
@@ -102,15 +101,9 @@ Q_DECLARE_METATYPE(QListModelInterface *);
Component {
id: FruitDelegate
Item {
- width: 200
- height: 50
- Text {
- text: name
- }
- Text {
- text: '$'+cost
- anchors.right: parent.right
- }
+ width: 200; height: 50
+ Text { text: name }
+ Text { text: '$'+cost; anchors.right: parent.right }
}
}
@@ -120,6 +113,59 @@ Q_DECLARE_METATYPE(QListModelInterface *);
anchors.fill: parent
}
\endcode
+
+ It is possible for roles to contain list data. In the example below we create a list of fruit attributes:
+
+ \code
+ ListModel {
+ id: FruitModel
+ ListElement {
+ name: "Apple"
+ cost: 2.45
+ attributes: [
+ ListElement { description: "Core" },
+ ListElement { description: "Deciduous" }
+ ]
+ }
+ ListElement {
+ name: "Orange"
+ cost: 3.25
+ attributes: [
+ ListElement { description: "Citrus" }
+ ]
+ }
+ ListElement {
+ name: "Banana"
+ cost: 1.95
+ attributes: [
+ ListElement { description: "Tropical" }
+ ListElement { description: "Seedless" }
+ ]
+ }
+ }
+ \endcode
+
+ The delegate below will list all the fruit attributes:
+ \code
+ Component {
+ id: FruitDelegate
+ Item {
+ width: 200; height: 50
+ Text { id: Name; text: name }
+ Text { text: '$'+cost; anchors.right: parent.right }
+ HorizontalLayout {
+ anchors.top: Name.bottom
+ spacing: 5
+ Text { text: "Attributes:" }
+ Repeater {
+ dataSource: attributes
+ Component { Text { text: description } }
+ }
+ }
+ }
+ }
+ \endcode
+
*/
struct ModelNode;
diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp
index b588111..3f74ef6 100644
--- a/tools/qmlviewer/main.cpp
+++ b/tools/qmlviewer/main.cpp
@@ -60,7 +60,6 @@ int main(int argc, char ** argv)
char raster[] = "raster";
newargv[argc+1] = raster;
-
QApplication app(newargc, newargv);
app.setApplicationName("viewer");
diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp
index dbbe233..04054ec 100644
--- a/tools/qmlviewer/qmlviewer.cpp
+++ b/tools/qmlviewer/qmlviewer.cpp
@@ -53,7 +53,8 @@ QmlViewer::QmlViewer(QFxTestEngine::TestMode testMode, const QString &testDir, Q
setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_NoSystemBackground);
- createMenuBar();
+ if (!(flags & Qt::FramelessWindowHint))
+ createMenuBar();
canvas = new QFxView(this);
if(testMode != QFxTestEngine::NoTest)
@@ -79,12 +80,44 @@ void QmlViewer::createMenuBar()
connect(reloadAction, SIGNAL(triggered()), this, SLOT(reload()));
fileMenu->addAction(reloadAction);
+ QAction *quitAction = new QAction(tr("&Quit"), this);
+ quitAction->setShortcut(QKeySequence("Ctrl+Q"));
+ connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+ fileMenu->addSeparator();
+ fileMenu->addAction(quitAction);
+
+ /*QMenu *recordMenu = menuBar()->addMenu(tr("&Recording"));
+
+ QAction *snapshotAction = new QAction(tr("&Take Snapsot"), 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);*/
+
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
QAction *aboutAction = new QAction(tr("&About Qt..."), this);
connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
helpMenu->addAction(aboutAction);
}
+void QmlViewer::takeSnapShot()
+{
+ static int snapshotcount = 1;
+ QString snapFileName = QString(QLatin1String("snapshot%1.png")).arg(snapshotcount);
+ canvas->asImage().save(snapFileName);
+ qDebug() << "Wrote" << snapFileName;
+ ++snapshotcount;
+}
+
+void QmlViewer::toggleRecording()
+{
+ bool recording = recordTimer.isActive();
+ //recordAction->setText(recording ? tr("&Start Recording Video") : tr("&End Recording Video"));
+ setRecording(!recording);
+}
+
void QmlViewer::reload()
{
openQml(currentFileName);
@@ -297,10 +330,9 @@ void QmlViewer::keyPressEvent(QKeyEvent *event)
<< "device keys: 0=quit, 1..8=F1..F8"
;
} else if (event->key() == Qt::Key_F2 || (event->key() == Qt::Key_2 && devicemode)) {
- setRecording(!recordTimer.isActive());
+ toggleRecording();
} else if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_3 && devicemode)) {
- canvas->asImage().save("snapshot.png");
- qDebug() << "Wrote snapshot.png";
+ takeSnapShot();
} else if (event->key() == Qt::Key_F4 || (event->key() == Qt::Key_4 && devicemode)) {
canvas->dumpItems();
canvas->checkState();
@@ -398,7 +430,7 @@ void QmlViewer::setRecording(bool on)
args << "-delay" << QString::number(record_period/10);
args << inputs;
args << record_file;
- qDebug() << "Converting..." << 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
diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h
index b4117a2..405e8d9 100644
--- a/tools/qmlviewer/qmlviewer.h
+++ b/tools/qmlviewer/qmlviewer.h
@@ -48,6 +48,8 @@ public slots:
void openQml(const QString& fileName);
void open();
void reload();
+ void takeSnapShot();
+ void toggleRecording();
protected:
virtual void keyPressEvent(QKeyEvent *);
@@ -70,6 +72,7 @@ private:
int record_period;
int record_autotime;
bool devicemode;
+ QAction *recordAction;
QFxTestEngine *testEngine;
};