aboutsummaryrefslogtreecommitdiffstats
path: root/examples/demos
diff options
context:
space:
mode:
Diffstat (limited to 'examples/demos')
-rw-r--r--examples/demos/stockchart/README5
-rw-r--r--examples/demos/stockchart/com/nokia/StockChartExample/qmldir1
-rw-r--r--examples/demos/stockchart/model.cpp255
-rw-r--r--examples/demos/stockchart/model.h166
-rw-r--r--examples/demos/stockchart/plugin.cpp60
-rw-r--r--examples/demos/stockchart/stock.qml726
-rw-r--r--examples/demos/stockchart/stockchart.pro20
-rw-r--r--examples/demos/stockchart/stockchart.qmlproject16
-rw-r--r--examples/demos/twitterfriends/TwitterUser.qml294
-rw-r--r--examples/demos/twitterfriends/cache.js42
-rw-r--r--examples/demos/twitterfriends/friends.qml140
-rw-r--r--examples/demos/twitterfriends/twitterfriends.qmlproject16
12 files changed, 1741 insertions, 0 deletions
diff --git a/examples/demos/stockchart/README b/examples/demos/stockchart/README
new file mode 100644
index 0000000000..2652866ed6
--- /dev/null
+++ b/examples/demos/stockchart/README
@@ -0,0 +1,5 @@
+To run:
+
+ make install
+ QML_IMPORT_PATH=$PWD qmlscene stock.qml
+
diff --git a/examples/demos/stockchart/com/nokia/StockChartExample/qmldir b/examples/demos/stockchart/com/nokia/StockChartExample/qmldir
new file mode 100644
index 0000000000..4c60e556d4
--- /dev/null
+++ b/examples/demos/stockchart/com/nokia/StockChartExample/qmldir
@@ -0,0 +1 @@
+plugin qmlstockchartexampleplugin
diff --git a/examples/demos/stockchart/model.cpp b/examples/demos/stockchart/model.cpp
new file mode 100644
index 0000000000..42eb2d592f
--- /dev/null
+++ b/examples/demos/stockchart/model.cpp
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "model.h"
+
+#include <QtCore/QUrl>
+#include <QtCore/QDate>
+#include <QtCore/QList>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkReply>
+
+StockModel::StockModel(QObject *parent)
+ : QAbstractListModel(parent)
+ , _startDate(QDate(1995, 4, 25))
+ , _endDate(QDate::currentDate())
+ , _dataCycle(StockModel::Daily)
+ , _manager(0)
+ , _updating(false)
+{
+ QHash<int, QByteArray> roles;
+ roles[StockModel::DateRole] = "date";
+ roles[StockModel::SectionRole] = "year";
+ roles[StockModel::OpenPriceRole] = "openPrice";
+ roles[StockModel::ClosePriceRole] = "closePrice";
+ roles[StockModel::HighPriceRole] = "highPrice";
+ roles[StockModel::LowPriceRole] = "lowPrice";
+ roles[StockModel::VolumeRole] = "volume";
+ roles[StockModel::AdjustedPriceRole] = "adjustedPrice";
+ setRoleNames(roles);
+
+ connect(this, SIGNAL(stockNameChanged()), SLOT(requestData()));
+ connect(this, SIGNAL(startDateChanged()), SLOT(requestData()));
+ connect(this, SIGNAL(endDateChanged()), SLOT(requestData()));
+ connect(this, SIGNAL(dataCycleChanged()), SLOT(requestData()));
+
+ _manager = new QNetworkAccessManager(this);
+ connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(update(QNetworkReply*)));
+
+}
+
+int StockModel::rowCount(const QModelIndex & parent) const {
+ Q_UNUSED(parent);
+ return _prices.count();
+}
+
+StockPrice* StockModel::stockPriceAtIndex(int idx) const
+{
+ if (idx >=0 && idx < _prices.size()) {
+ return _prices[idx];
+ }
+ return 0;
+}
+
+
+void StockModel::requestData()
+{
+ if (!_updating) {
+ _updating = true;
+ QMetaObject::invokeMethod(this, "doRequest", Qt::QueuedConnection);
+ }
+}
+
+void StockModel::doRequest()
+{
+ /*
+ Fetch stock data from yahoo finance:
+ url: http://ichart.finance.yahoo.com/table.csv?s=NOK&a=5&b=11&c=2010&d=7&e=23&f=2010&g=d&ignore=.csv
+ s:stock name/id, a:start day, b:start month, c:start year default: 25 April 1995, oldest c= 1962
+ d:end day, e:end month, f:end year, default:today (data only available 3 days before today)
+ g:data cycle(d daily, w weekly, m monthly, v Dividend)
+ */
+ if (_manager && !_stockName.isEmpty() && _endDate > _startDate) {
+ QString query("http://ichart.finance.yahoo.com/table.csv?s=%1&a=%2&b=%3&c=%4&d=%5&e=%6&f=%7&g=%8&ignore=.csv");
+ query = query.arg(_stockName)
+ .arg(_startDate.day()).arg(_startDate.month()).arg(_startDate.year())
+ .arg(_endDate.day()).arg(_endDate.month()).arg(_endDate.year())
+ .arg(dataCycleString());
+
+ qDebug() << "request stock data:" << query;
+ QNetworkReply* reply = _manager->get(QNetworkRequest(QUrl(query)));
+ connect(reply, SIGNAL(downloadProgress(qint64,qint64)), SIGNAL(downloadProgress(qint64,qint64)));
+ }
+}
+
+void StockModel::update(QNetworkReply *reply)
+{
+ _updating = false;
+
+ if (reply) {
+ if (reply->error() == QNetworkReply::NoError) {
+ beginResetModel();
+
+ foreach (StockPrice* p, _prices) {
+ p->deleteLater();
+ }
+
+ _prices.clear();
+
+ while (!reply->atEnd()) {
+ QString line = reply->readLine();
+ QStringList fields = line.split(',');
+
+ //data format:Date,Open,High,Low,Close,Volume,Adjusted close price
+ //example: 2011-06-24,6.03,6.04,5.88,5.88,20465200,5.88
+ if (fields.size() == 7) {
+ StockPrice* price = new StockPrice(this);
+ price->setDate(QDate::fromString(fields[0], Qt::ISODate));
+ price->setOpenPrice(fields[1].toFloat());
+ price->setHighPrice(fields[2].toFloat());
+ price->setLowPrice(fields[3].toFloat());
+ price->setClosePrice(fields[4].toFloat());
+ price->setVolume(fields[5].toInt());
+ price->setAdjustedPrice(fields[6].toFloat());
+ _prices.prepend(price);
+ }
+ }
+ qDebug() << "get stock data successfully, total:" << _prices.count() << "records.";
+ } else {
+ qDebug() << "get stock data failed:" << reply->errorString();
+ }
+ reply->deleteLater();
+ endResetModel();
+ emit dataChanged(QModelIndex(), QModelIndex());
+ }
+}
+
+QVariant StockModel::data(const QModelIndex & index, int role) const {
+ if (index.row() < 0 || index.row() > _prices.count())
+ return QVariant();
+
+ const StockPrice* price = _prices[index.row()];
+ if (role == StockModel::DateRole)
+ return price->date();
+ else if (role == StockModel::OpenPriceRole)
+ return price->openPrice();
+ else if (role == StockModel::ClosePriceRole)
+ return price->closePrice();
+ else if (role == StockModel::HighPriceRole)
+ return price->highPrice();
+ else if (role == StockModel::LowPriceRole)
+ return price->lowPrice();
+ else if (role == StockModel::AdjustedPriceRole)
+ return price->adjustedPrice();
+ else if (role == StockModel::VolumeRole)
+ return price->volume();
+ else if (role == StockModel::SectionRole)
+ return price->date().year();
+ return QVariant();
+}
+
+QString StockModel::stockName() const
+{
+ return _stockName;
+}
+void StockModel::setStockName(const QString& name)
+{
+ if (_stockName != name) {
+ _stockName = name;
+ emit stockNameChanged();
+ }
+}
+
+QDate StockModel::startDate() const
+{
+ return _startDate;
+}
+void StockModel::setStartDate(const QDate& date)
+{
+ if (_startDate.isValid() && _startDate != date) {
+ _startDate = date;
+ emit startDateChanged();
+ }
+}
+
+QDate StockModel::endDate() const
+{
+ return _endDate;
+}
+void StockModel::setEndDate(const QDate& date)
+{
+ if (_endDate.isValid() && _endDate != date) {
+ _endDate = date;
+ emit endDateChanged();
+ }
+}
+
+StockModel::StockDataCycle StockModel::dataCycle() const
+{
+ return _dataCycle;
+}
+
+QString StockModel::dataCycleString() const
+{
+ switch (_dataCycle) {
+ case StockModel::Daily:
+ return QString('d');
+ break;
+ case StockModel::Weekly:
+ return QString('w');
+ case StockModel::Monthly:
+ return QString('m');
+ case StockModel::Dividend:
+ return QString('v');
+ }
+
+ return QString('d');
+}
+
+
+void StockModel::setDataCycle(StockModel::StockDataCycle cycle)
+{
+ if (_dataCycle != cycle) {
+ _dataCycle = cycle;
+ emit dataCycleChanged();
+ }
+}
diff --git a/examples/demos/stockchart/model.h b/examples/demos/stockchart/model.h
new file mode 100644
index 0000000000..95e6f4891c
--- /dev/null
+++ b/examples/demos/stockchart/model.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtCore/QAbstractListModel>
+#include <QtCore/QDate>
+
+class StockPrice : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QDate date READ date)
+ Q_PROPERTY(qreal openPrice READ openPrice)
+ Q_PROPERTY(qreal closePrice READ closePrice)
+ Q_PROPERTY(qreal highPrice READ highPrice)
+ Q_PROPERTY(qreal lowPrice READ lowPrice)
+ Q_PROPERTY(qint32 volume READ volume)
+ Q_PROPERTY(qreal adjustedPrice READ adjustedPrice)
+public:
+
+ StockPrice(QObject *parent = 0)
+ : QObject(parent)
+ , _openPrice(-1)
+ , _closePrice(-1)
+ , _highPrice(-1)
+ , _lowPrice(-1)
+ , _volume(-1)
+ , _adjustedPrice(-1)
+ {
+ }
+ QDate date() const {return _date;}
+ qreal openPrice() const {return _openPrice; }
+ qreal closePrice() const {return _closePrice;}
+ qreal highPrice() const {return _highPrice;}
+ qreal lowPrice() const{return _lowPrice;}
+ qreal adjustedPrice() const{return _adjustedPrice;}
+ qint32 volume() const{return _volume;}
+
+ void setDate(const QDate& date){_date = date;}
+ void setOpenPrice(qreal price){_openPrice = price;}
+ void setClosePrice(qreal price){_closePrice = price;}
+ void setHighPrice(qreal price){_highPrice = price;}
+ void setLowPrice(qreal price){_lowPrice = price;}
+ void setAdjustedPrice(qreal price) {_adjustedPrice = price;}
+ void setVolume(qint32 volume) {_volume = volume;}
+
+private:
+ QDate _date;
+ qreal _openPrice;
+ qreal _closePrice;
+ qreal _highPrice;
+ qreal _lowPrice;
+ qint32 _volume;
+ qreal _adjustedPrice;
+};
+
+class QNetworkReply;
+class QNetworkAccessManager;
+class StockModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString stockName READ stockName WRITE setStockName NOTIFY stockNameChanged)
+ Q_PROPERTY(QDate startDate READ startDate WRITE setStartDate NOTIFY startDateChanged)
+ Q_PROPERTY(QDate endDate READ endDate WRITE setEndDate NOTIFY endDateChanged)
+ Q_PROPERTY(StockDataCycle dataCycle READ dataCycle WRITE setDataCycle NOTIFY dataCycleChanged)
+
+ Q_ENUMS(StockDataCycle)
+public:
+ enum StockDataCycle {
+ Daily,
+ Weekly,
+ Monthly,
+ Dividend
+ };
+
+ enum StockModelRoles {
+ DateRole = Qt::UserRole + 1,
+ SectionRole,
+ OpenPriceRole,
+ ClosePriceRole,
+ HighPriceRole,
+ LowPriceRole,
+ VolumeRole,
+ AdjustedPriceRole
+ };
+
+ StockModel(QObject *parent = 0);
+
+ QString stockName() const;
+ void setStockName(const QString& name);
+
+ QDate startDate() const;
+ void setStartDate(const QDate& date);
+
+ QDate endDate() const;
+ void setEndDate(const QDate& date);
+
+ StockDataCycle dataCycle() const;
+ void setDataCycle(StockDataCycle cycle);
+
+ int rowCount(const QModelIndex & parent = QModelIndex()) const;
+
+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+
+signals:
+ void stockNameChanged();
+ void startDateChanged();
+ void endDateChanged();
+ void dataCycleChanged();
+ void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+
+public slots:
+ void requestData();
+ StockPrice* stockPriceAtIndex(int idx) const;
+private slots:
+ void doRequest();
+ void update(QNetworkReply* reply);
+private:
+ QString dataCycleString() const;
+ QList<StockPrice*> _prices;
+ QString _stockName;
+ QDate _startDate;
+ QDate _endDate;
+ StockDataCycle _dataCycle;
+ QNetworkAccessManager* _manager;
+ bool _updating;
+};
+
+
+
+
diff --git a/examples/demos/stockchart/plugin.cpp b/examples/demos/stockchart/plugin.cpp
new file mode 100644
index 0000000000..3b354e2b31
--- /dev/null
+++ b/examples/demos/stockchart/plugin.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/QQmlExtensionPlugin>
+#include <QtQml/qqml.h>
+#include <QtGui/QGuiApplication>
+#include "model.h"
+
+class QStockChartExampleQmlPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+public:
+ void registerTypes(const char *uri)
+ {
+ Q_ASSERT(uri == QLatin1String("com.nokia.StockChartExample"));
+ qmlRegisterType<StockModel>(uri, 1, 0, "StockModel");
+ qmlRegisterType<StockPrice>(uri, 1, 0, "StockPrice");
+ }
+};
+
+#include "plugin.moc"
+
+Q_EXPORT_PLUGIN2(qmlstockchartexampleplugin, QStockChartExampleQmlPlugin);
diff --git a/examples/demos/stockchart/stock.qml b/examples/demos/stockchart/stock.qml
new file mode 100644
index 0000000000..1c95fde2ce
--- /dev/null
+++ b/examples/demos/stockchart/stock.qml
@@ -0,0 +1,726 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import com.nokia.StockChartExample 1.0
+import "../contents"
+
+Rectangle {
+ id:container
+ width: 360; height: 600
+ color: "#343434";
+ Image { source: "contents/images/stripes.png"; fillMode: Image.Tile; anchors.fill: parent; opacity: 1 }
+
+
+ TitleBar {
+ id: titleBar
+ width: parent.width
+ anchors.top : container.top
+ height: 40
+ opacity: 0.9
+ }
+
+ StockModel {
+ id:stockModel
+ dataCycle: StockModel.Daily
+ function dataCycleName() {
+ if (dataCycle === StockModel.Weekly)
+ return "Weekly";
+ else if (dataCycle === StockModel.Monthly)
+ return "Monthly";
+ return "Daily";
+ }
+
+ onDataChanged: {
+ if (view.viewType == "chart") {
+ canvas.requestPaint();
+ }
+ }
+ onDownloadProgress: {
+ if (bytesReceived == bytesTotal && bytesTotal != -1) {
+ progress.opacity = 0;
+ } else {
+ progress.opacity = 0.8;
+ progress.text = "downloading " + stockModel.dataCycleName() + " data ..."+ Math.round(bytesReceived/1000) + " KB";
+ }
+ }
+
+ property string description:"";
+ }
+
+ Stocks {id:stocks}
+
+ Rectangle {
+ id: header
+ width: parent.width
+ height: 20
+ color: "steelblue"
+ opacity: 0
+ Row {
+ spacing: 2
+ Text {
+ id:t
+ font.pointSize:15
+ horizontalAlignment:Text.AlignHCenter
+ font.bold: true
+ font.underline:true
+ }
+ Rectangle {
+ height:20
+ width:50
+ Text {text:"Stock list"; font.pointSize:15; font.bold: true}
+ }
+ }
+ }
+
+ ListView {
+ id:stockList
+ width: parent.width
+ anchors.bottom: container.bottom
+ anchors.top : titleBar.bottom
+ focus: true
+ keyNavigationWraps: true
+ spacing:1
+ opacity: 1
+ model: stocks
+
+ Component.onCompleted: opacity = 0.9;
+ onOpacityChanged: {
+ titleBar.title = "Top 100 NASDAQ stocks"
+ }
+
+
+ delegate : Rectangle {
+ height: 30
+ width: view.width
+ color: {
+ if (ListView.isCurrentItem)
+ return focus ? "lightyellow" : "pink";
+ return index % 2 == 0 ? "lightblue" : "lightsteelblue"
+ }
+ Text {
+ font.pointSize:20
+ text: index + ". " + stockId + " \t(" + name + ")";
+ }
+ MouseArea {
+ anchors.fill: parent;
+ onDoubleClicked: {
+ stockList.opacity = 0;
+ stockModel.stockName = stockId;
+ stockModel.description = "NASDAQ:" + stockId + " (" + name + ")";
+ view.opacity = 1;
+ view.viewType = "chart";
+ canvas.opacity = 0.7;
+ }
+ onClicked: stockList.currentIndex = index
+ }//mousearea
+ }//delegate
+ }
+
+ ListView {
+ id:view
+ width: container.width
+ height: container.height - 50
+ anchors.bottom: container.bottom
+ focus: true
+ keyNavigationWraps: true
+
+ spacing:1
+ opacity: 0
+ model: stockModel
+ highlightFollowsCurrentItem: false
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ preferredHighlightBegin:50
+ preferredHighlightEnd : height - 50
+ highlight: listHighlight
+
+ //header : Text {}
+ delegate: listDelegate
+ snapMode: ListView.SnapToItem
+
+ property string viewType : "list"
+ property int topIndex:indexAt(0,contentY);
+ property int bottomIndex:indexAt(0, contentY+height);
+
+ onCountChanged: {
+
+ titleBar.title = stockModel.description + " " + Qt.formatDate(stockModel.startDate, "yyyy-MM-dd") + " - " +
+ Qt.formatDate(stockModel.endDate, "yyyy-MM-dd") + " " + stockModel.dataCycleName() +
+ " records:" + view.count;
+
+ }
+
+ Component {
+ id: listDelegate
+ Rectangle {
+ height: 20
+ width: view.width
+ border.color: "lightsteelblue"
+ border.width: 1
+ color: {
+ if (ListView.isCurrentItem)
+ return focus ? "lightyellow" : "pink";
+
+ return index % 2 == 0 ? "lightblue" : "lightsteelblue"
+ }
+ Text {
+ font.pointSize:13
+ text: index + ". " + Qt.formatDate(date, "yyyy-MM-dd")
+ + "\t " + Math.round(openPrice*100)/100
+ + "\t " + Math.round(highPrice*100)/100
+ + "\t " + Math.round(lowPrice*100)/100
+ + "\t " + Math.round(closePrice*100)/100
+ + "\t " + volume + "\t "
+ + Math.round(adjustedPrice*100)/100;
+ }
+ MouseArea {anchors.fill: parent; onClicked: view.currentIndex = index}
+ }
+ }
+
+ Component {
+ id: chartDelegate
+ Rectangle {
+ height: 20
+ width: view.width/view.count * canvas.scaleX
+ border.color: "lightsteelblue"
+ border.width: 1
+ color: {
+ if (ListView.isCurrentItem)
+ return focus ? "lightyellow" : "pink";
+
+ return index % 2 == 0 ? "lightblue" : "lightsteelblue"
+ }
+
+ Text {
+ anchors.bottom: parent.bottom
+ font.pointSize: {
+ if (parent.width <= 4)
+ return 1;
+ if (parent.width <= 50)
+ return parent.width/4;
+ return 15;
+ }
+ horizontalAlignment:Text.AlignHCenter
+ verticalAlignment:Text.AlignBottom
+ text:font.pointSize > 1 ? Qt.formatDate(date, "d/M/yy") : ""
+ }
+ MouseArea {anchors.fill: parent; onClicked: view.currentIndex = index}
+ }
+ }
+
+ Component {
+ id:chartHighlight
+ Rectangle { radius: 5; width:40; height: 20; color: "lightsteelblue" }
+ }
+
+ Component {
+ id:listHighlight
+ Rectangle { radius: 5; width:container.width; height: 20; color: "lightsteelblue" }
+ }
+
+
+
+
+ onViewTypeChanged : {
+ if (viewType == "list") {
+ view.orientation = ListView.Vertical;
+ view.delegate = listDelegate;
+// view.section.property = "year";
+// view.section.criteria = ViewSection.FullString;
+// view.section.delegate = sectionHeading;
+ view.highlight = listHighlight;
+ view.opacity = 1;
+ canvas.opacity = 0;
+ // comment.opacity = 0;
+
+ } else if (viewType == "chart") {
+ view.orientation = ListView.Horizontal;
+ view.delegate = chartDelegate;
+ //comment.opacity = 0.6;
+
+ view.opacity = 1;
+ view.height = 30
+
+ canvas.opacity = 0.7;
+ canvas.requestPaint();
+ } else {
+ viewType = "list";
+ }
+ }
+
+
+ onCurrentIndexChanged: {
+ //header.updateCurrent(stockModel.stockPriceAtIndex(view.currentIndex));
+ if (viewType == "chart") {
+ canvas.first = Math.round(view.currentIndex - view.currentIndex / canvas.scaleX);
+ canvas.last = Math.round(view.currentIndex + (view.count - view.currentIndex) / canvas.scaleX);
+
+ canvas.requestPaint();
+ }
+ }
+ onContentYChanged: { // keep "current" item visible
+ topIndex = indexAt(0,contentY);
+ bottomIndex = indexAt(0, contentY+height);
+
+ if (topIndex != -1 && currentIndex <= topIndex)
+ currentIndex = topIndex+1;
+ else if (bottomIndex != -1 && currentIndex >= bottomIndex)
+ currentIndex = bottomIndex-1;
+ if (viewType == "chart")
+ canvas.requestPaint();
+ }
+
+ onContentXChanged: { // keep "current" item visible
+ topIndex = indexAt(contentX,0);
+ bottomIndex = indexAt(contentX+width, 0);
+
+ if (topIndex != -1 && currentIndex <= topIndex)
+ currentIndex = topIndex+1;
+ else if (bottomIndex != -1 && currentIndex >= bottomIndex)
+ currentIndex = bottomIndex-1;
+ if (viewType == "chart")
+ canvas.requestPaint();
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onDoubleClicked: {
+ if (view.viewType == "list")
+ view.viewType = "chart";
+ else
+ view.viewType = "list";
+ }
+ }
+ }
+
+
+
+ Canvas {
+ id:canvas
+ anchors.top : titleBar.bottom
+ anchors.bottom : view.top
+ width:container.width;
+ opacity:0
+ renderTarget: Canvas.Image
+ renderStrategy: Canvas.Immediate
+ property bool running:false
+ property int frames:first
+ property int mouseX:0;
+ property int mouseY:0;
+ property int mousePressedX:0;
+ property int mousePressedY:0;
+ property int movedY:0
+ property real scaleX:1.0;
+ property real scaleY:1.0;
+ property int first:0;
+ property int last:view.count - 1;
+
+ onOpacityChanged: {
+ if (opacity > 0)
+ requestPaint();
+ }
+ Text {
+ id:comment
+ x:100
+ y:50
+ font.pointSize: 20
+ color:"white"
+ opacity: 0.7
+ focus:false
+ text: stockModel.description
+ function updateCurrent(price)
+ {
+ if (price !== undefined) {
+ text =stockModel.description + "\n"
+ + Qt.formatDate(price.date, "yyyy-MM-dd") + " OPEN:"
+ + Math.round(price.openPrice*100)/100 + " HIGH:"
+ + Math.round(price.highPrice*100)/100 + " LOW:"
+ + Math.round(price.lowPrice*100)/100 + " CLOSE:"
+ + Math.round(price.closePrice*100)/100 + " VOLUME:"
+ + price.volume;
+ }
+ }
+ }
+
+ Text {
+ id:priceAxis
+ x:25
+ y:25
+ font.pointSize: 15
+ color:"yellow"
+ opacity: 0.7
+ focus: false
+ }
+ Text {
+ id:volumeAxis
+ x:canvas.width - 200
+ y:25
+ font.pointSize: 15
+ color:"yellow"
+ opacity: 0.7
+ }
+
+ Rectangle {
+ id:progress
+ x:canvas.width/2 - 100
+ y:canvas.height/2
+ width:childrenRect.width
+ height: childrenRect.height
+ opacity: 0
+ color:"white"
+ property string text;
+ Text {
+ text:parent.text
+ font.pointSize: 20
+ }
+ }
+
+ Button {
+ id:runButton
+ text:"Run this chart"
+ y:0
+ x:canvas.width/2 - 50
+ opacity: 0.5
+ onClicked: {
+ if (canvas.running) {
+ canvas.running = false;
+ canvas.frames = canvas.first;
+ canvas.requestPaint();
+ text = "Run this chart";
+ comment.text = stockModel.description;
+ } else {
+ text = " Stop running ";
+ canvas.runChart();
+ }
+ }
+ }
+ Button {
+ id:returnButton
+ text:"Stocks"
+ y:0
+ anchors.left : runButton.right
+ anchors.leftMargin : 20
+ opacity: 0.5
+ onClicked: {
+ stockList.opacity = 1;
+ canvas.opacity = 0;
+ }
+ }
+ PinchArea {
+ anchors.fill: parent
+ onPinchUpdated : {
+ var current = pinch.center;
+ var scale = pinch.scale;
+ console.log("center:" + pinch.center + " scale:" + pinch.scale);
+ //canvas.requestPaint();
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onDoubleClicked: {
+ if (stockModel.dataCycle == StockModel.Daily)
+ stockModel.dataCycle = StockModel.Weekly;
+ else if (stockModel.dataCycle == StockModel.Weekly)
+ stockModel.dataCycle = StockModel.Monthly;
+ else
+ stockModel.dataCycle = StockModel.Daily;
+ }
+
+ onPositionChanged: {
+ if (mouse.modifiers & Qt.ControlModifier) {
+ if (canvas.mouseX == 0 && canvas.mouseY == 0) {
+ canvas.mouseX = mouse.x;
+ canvas.mouseY = mouse.y;
+ }
+ } else{
+ var w = (view.width/view.count)*canvas.scaleX;
+
+ //canvas.movedY += Math.round((canvas.mousePressedY - mouse.y)/2);
+
+ var movedX = Math.round((canvas.mousePressedX - mouse.x)/w);
+ if (movedX != 0 || canvas.movedY != 0) {
+ if (canvas.first + movedX >= 0 && canvas.last + movedX < view.count) {
+ canvas.first += movedX;
+ canvas.last += movedX;
+ }
+ canvas.requestPaint();
+ }
+ }
+ }
+
+ onPressed: {
+ canvas.mousePressedX = mouse.x;
+ canvas.mousePressedY = mouse.y;
+ }
+
+ onReleased : {
+ if (mouse.modifiers & Qt.ControlModifier) {
+ var sx = mouse.x - canvas.mouseX;
+ var sy = canvas.mouseY - mouse.y;
+
+ if (Math.abs(sx) < 50) sx = 0;
+ if (Math.abs(sy) < 50) sy = 0;
+
+ if (sx > 0)
+ canvas.scaleX *= sx/100 +1;
+ else
+ canvas.scaleX *= 1/(-sx/100 + 1);
+
+ if (sy > 0)
+ canvas.scaleY *= sy/100 +1;
+ else
+ canvas.scaleY *= 1/(-sy/100 + 1);
+
+ if (canvas.scaleX < 1)
+ canvas.scaleX = 1;
+
+ //console.log("scaleX:" + canvas.scaleX + ", scaleY:" + canvas.scaleY);
+
+ canvas.first = Math.round(view.currentIndex - view.currentIndex / canvas.scaleX);
+ canvas.last = Math.round(view.currentIndex + (view.count - view.currentIndex) / canvas.scaleX);
+
+ canvas.mouseX = 0;
+ canvas.mouseY = 0;
+ canvas.mousePressedX = 0;
+ canvas.mousePressedY = 0;
+ canvas.requestPaint();
+ }
+ }
+ }
+
+ function runChart() {
+ canvas.running = true;
+ requestPaint();
+ }
+
+ function showPriceAt(x) {
+ var w = (view.width/view.count)*canvas.scaleX;
+ //header.updateCurrent(stockModel.stockPriceAtIndex(canvas.first + Math.round(x/w)));
+ //console.log("x:" + x + " w:" + w + " index:" + (canvas.first + Math.round(x/w)));
+ }
+
+ function drawPrice(ctx, from, to, color, price, points, highest)
+ {
+ ctx.globalAlpha = 0.7;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+
+ //price x axis
+ priceAxis.text = "price:" + Math.round(highest);
+ ctx.font = "bold 12px sans-serif";
+
+ ctx.strokeText("price", 25, 25);
+ for (var j = 1; j < 30; j++) {
+ var val = (highest * j) / 30;
+ val = canvas.height * (1 - val/highest);
+ ctx.beginPath();
+
+ ctx.moveTo(10, val);
+ if (j % 5)
+ ctx.lineTo(15, val);
+ else
+ ctx.lineTo(20, val);
+ ctx.stroke();
+ }
+
+ ctx.beginPath();
+ ctx.moveTo(10, 0);
+ ctx.lineTo(10, canvas.height);
+ ctx.stroke();
+
+
+ var w = canvas.width/points.length;
+ var end = canvas.running? canvas.frames - canvas.first :points.length;
+ for (var i = 0; i < end; i++) {
+ var x = points[i].x;
+ var y = points[i][price];
+ y += canvas.movedY;
+
+ y = canvas.height * (1 - y/highest);
+ if (i == 0) {
+ ctx.moveTo(x+w/2, y);
+ } else {
+ ctx.lineTo(x+w/2, y);
+ }
+ }
+ ctx.stroke();
+ }
+
+ function drawKLine(ctx, from, to, points, highest)
+ {
+ ctx.globalAlpha = 0.4;
+ ctx.lineWidth = 2;
+ var end = canvas.running? canvas.frames - canvas.first :points.length;
+ for (var i = 0; i < end; i++) {
+ var x = points[i].x;
+ var open = canvas.height * (1 - points[i].open/highest) - canvas.movedY;
+ var close = canvas.height * (1 - points[i].close/highest) - canvas.movedY;
+ var high = canvas.height * (1 - points[i].high/highest) - canvas.movedY;
+ var low = canvas.height * (1 - points[i].low/highest) - canvas.movedY;
+
+ var top, bottom;
+ if (close <= open) {
+ ctx.fillStyle = Qt.rgba(1, 0, 0, 1);
+ ctx.strokeStyle = Qt.rgba(1, 0, 0, 1);
+ top = close;
+ bottom = open;
+ } else {
+ ctx.fillStyle = Qt.rgba(0, 1, 0, 1);
+ ctx.strokeStyle = Qt.rgba(0, 1, 0, 1);
+ top = open;
+ bottom = close;
+ }
+
+ var w1, w2;
+ w1 = canvas.width/points.length;
+ w2 = w1 > 10 ? w1/2 : w1;
+
+ ctx.fillRect(x + (w1 - w2)/2, top, w2, bottom - top);
+ ctx.beginPath();
+ ctx.moveTo(x+w1/2, high);
+ ctx.lineTo(x+w1/2, low);
+ ctx.stroke();
+ }
+ ctx.globalAlpha = 1;
+
+ }
+
+ function drawVolume(ctx, from, to, color, price, points, highest)
+ {
+ ctx.fillStyle = color;
+ ctx.globalAlpha = 0.6;
+ ctx.strokeStyle = Qt.rgba(0.8, 0.8, 0.8, 1);
+ ctx.lineWidth = 1;
+
+ //volume x axis
+ volumeAxis.text = "volume:" + Math.round(highest/(1000*100)) + "M";
+ for (var j = 1; j < 30; j++) {
+ var val = (highest * j) / 30;
+ val = canvas.height * (1 - val/highest);
+ ctx.beginPath();
+ if (j % 5)
+ ctx.moveTo(canvas.width - 15, val);
+ else
+ ctx.moveTo(canvas.width - 20, val);
+ ctx.lineTo(canvas.width - 10, val);
+ ctx.stroke();
+ }
+
+ ctx.beginPath();
+ ctx.moveTo(canvas.width - 10, 0);
+ ctx.lineTo(canvas.width - 10, canvas.height);
+ ctx.stroke();
+
+ var end = canvas.running? canvas.frames - canvas.first :points.length;
+ for (var i = 0; i < end; i++) {
+ var x = points[i].x;
+ var y = points[i][price];
+ y = canvas.height * (1 - y/highest);
+ ctx.fillRect(x, y, canvas.width/points.length, canvas.height - y);
+ }
+ }
+/*
+ onPainted : {
+ if (canvas.running) {
+ if (frames >= last) {
+ canvas.running = false;
+ canvas.frames = first;
+ runButton.text = "Run this chart";
+ comment.text = stockModel.description;
+ requestPaint();
+ } else {
+ frames += Math.round(view.count / 100);
+ if (frames > last) frames = last;
+ var price = stockModel.stockPriceAtIndex(frames);
+ if (price) {
+ comment.updateCurrent(price);
+ }
+
+ requestPaint();
+ }
+ }
+ }
+*/
+ onPaint: {
+ if (view.currentIndex <= 0)
+ first = 0;
+ if (last >= view.count)
+ last = view.count - 1;
+
+ //console.log("painting... first:" + first + ", last:" + last + " current:" + view.currentIndex);
+ var ctx = canvas.getContext("2d");
+ ctx.save();
+
+ ctx.globalCompositeOperation = "source-over";
+ ctx.lineWidth = 1;
+ ctx.lineJoin = "round";
+ ctx.fillStyle = "rgba(0,0,0,0)";
+
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+
+
+ var highestPrice = 500/canvas.scaleY;
+ var highestValume = 600 * 1000 * 1000/canvas.scaleY;
+ var points = [];
+ for (var i = 0; i <= last - first; i++) {
+ var price = stockModel.stockPriceAtIndex(i + first);
+ points.push({
+ x: i*canvas.width/(last-first+1),
+ open: price.openPrice,
+ close: price.closePrice,
+ high:price.highPrice,
+ low:price.lowPrice,
+ volume:price.volume
+ });
+ }
+
+ drawPrice(ctx, first, last, Qt.rgba(1, 0, 0, 1),"high", points, highestPrice);
+ drawPrice(ctx, first, last, Qt.rgba(0, 1, 0, 1),"low", points, highestPrice);
+ drawPrice(ctx, first, last, Qt.rgba(0, 0, 1, 1),"open", points, highestPrice);
+ drawPrice(ctx, first, last, Qt.rgba(0.5, 0.5, 0.5, 1),"close", points, highestPrice);
+ drawVolume(ctx, first, last, Qt.rgba(0.3, 0.5, 0.7, 1),"volume", points, highestValume);
+ drawKLine(ctx, first, last, points, highestPrice);
+ ctx.restore();
+ }
+ }
+}
diff --git a/examples/demos/stockchart/stockchart.pro b/examples/demos/stockchart/stockchart.pro
new file mode 100644
index 0000000000..e368746db5
--- /dev/null
+++ b/examples/demos/stockchart/stockchart.pro
@@ -0,0 +1,20 @@
+TEMPLATE = lib
+CONFIG += qt plugin
+QT += qml network
+
+DESTDIR = com/nokia/StockChartExample
+TARGET = qmlstockchartexampleplugin
+
+SOURCES += model.cpp plugin.cpp
+HEADERS += model.h
+qdeclarativesources.files += \
+ com/nokia/StockChartExample/qmldir \
+ stock.qml
+
+qdeclarativesources.path += $$[QT_INSTALL_EXAMPLES]/qtdeclarative/qml/plugins/com/nokia/StockChartExample
+
+sources.files += stockchart.pro model.h model.cpp plugin.cpp README
+sources.path += $$[QT_INSTALL_EXAMPLES]/qtdeclarative/qml/plugins
+target.path += $$[QT_INSTALL_EXAMPLES]/qtdeclarative/qml/plugins/com/nokia/StockChartExample
+
+INSTALLS += qdeclarativesources sources target
diff --git a/examples/demos/stockchart/stockchart.qmlproject b/examples/demos/stockchart/stockchart.qmlproject
new file mode 100644
index 0000000000..5f2b9094b3
--- /dev/null
+++ b/examples/demos/stockchart/stockchart.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.1
+
+Project {
+ mainFile: "stock.qml"
+
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+} \ No newline at end of file
diff --git a/examples/demos/twitterfriends/TwitterUser.qml b/examples/demos/twitterfriends/TwitterUser.qml
new file mode 100644
index 0000000000..8b906216ef
--- /dev/null
+++ b/examples/demos/twitterfriends/TwitterUser.qml
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id:twitterUser
+ property variant friends : [];
+ property string name : "";
+ property string twitterId : "";
+ property string image : "";
+ property string url : "";
+ property string desc : "";
+ width : 0;
+ height : 0;
+ property int posX:0;
+ property int posY:0;
+ property bool hasFocus : false;
+ property variant canvas;
+ property variant manager;
+ property variant linkColor;
+ property bool selected : false;
+
+ Rectangle {
+ id:twitterStatus
+ x:twitterUser.width
+ y:twitterUser.height
+ width:250
+ height:60
+ opacity: 0
+ border.color:"steelblue"
+ border.width:3
+ Column {
+ spacing:2
+ Text {color:"steelblue"; font.pointSize:15; width:250; height:30; text:twitterUser.name; wrapMode: Text.WrapAnywhere}
+ Text {color:"steelblue"; font.pointSize:8; width:250; height:30; text:twitterUser.url; wrapMode: Text.WrapAnywhere}
+ }
+ }
+
+ function moved() {
+ twitterUser.posX = twitterUser.x;
+ twitterUser.posY = twitterUser.y;
+ twitterUser.canvas.requestPaint();
+ }
+
+ onXChanged: moved();
+ onYChanged: moved();
+
+ MouseArea {
+ anchors.fill:parent
+ drag.target : twitterUser
+ drag.axis : Drag.XandYAxis
+
+ onClicked: {
+ if (!twitterUser.selected) {
+ twitterUser.selected = true;
+ twitterStatus.opacity = 1;
+ twitterStatus.visible = true;
+ } else {
+ twitterUser.selected = false;
+ twitterStatus.opacity = 0;
+ }
+ }
+
+ onDoubleClicked : {
+ twitterStatus.opacity = 0;
+ twitterUser.selected = false;
+ twitterUser.hasFocus = true;
+ twitterUser.canvas.twitterName = twitterUser.name;
+ twitterUser.canvas.twitterId = twitterUser.twitterId;
+ twitterUser.canvas.loading = true;
+ twitterUser.createFriends();
+ }
+ }
+
+ function show(ctx, layoutChanged) {
+ var w = canvas.width;
+ var h = canvas.height;
+ if (twitterUser.hasFocus) {
+ twitterUser.width = 60
+ twitterUser.height = 60
+ twitterUser.posX = w/2;
+ twitterUser.posY = h/2;
+ } else {
+ twitterUser.width = 40
+ twitterUser.height = 40
+ }
+
+
+ if (twitterUser.hasFocus) {
+ if (layoutChanged)
+ twitterUser.layoutFriends();
+ twitterUser.linkFriends(ctx);
+ twitterUser.showFriends(ctx);
+ ctx.shadowOffsetX = 5;
+ ctx.shadowOffsetY = 5;
+ ctx.shadowBlur = 7;
+ ctx.shadowColor = "blue";
+ ctx.globalAlpha = 1;
+ } else {
+ ctx.shadowOffsetX = 5;
+ ctx.shadowOffsetY = 5;
+ ctx.shadowBlur = 7;
+ ctx.shadowColor = twitterUser.linkColor;
+ ctx.globalAlpha = 0.6;
+ }
+
+ if (twitterUser.canvas.isImageLoaded(twitterUser.image)) {
+ ctx.drawImage(twitterUser.image, twitterUser.posX, twitterUser.posY, twitterUser.width, twitterUser.height);
+ }
+// ctx.font = "15px";
+// var nameSize = ctx.measureText(twitterUser.name).width;
+// ctx.fillText(twitterUser.name, twitterUser.posX + nameSize/2 - twitterUser.width/2, twitterUser.posY + twitterUser.height/2 + 10);
+ }
+ function dump() {
+ console.log("name:" + twitterUser.name
+ + " x:" + twitterUser.posX
+ + " y:" + twitterUser.posY
+ + " width:" + twitterUser.width
+ + " height:" + twitterUser.height
+ + " id:" + twitterUser.twitterId
+ + " image:" + twitterUser.image
+ + " url:" + twitterUser.url + "\n" + twitterUser.desc);
+ }
+
+ function layoutFriends() {
+ var w = canvas.width;
+ var h = canvas.height;
+ for (var i=0; i < twitterUser.friends.length; i++) {
+ var friend = manager.getById(twitterUser.friends[i]);
+ if (friend) {
+ friend.x = Math.random() *w;
+ friend.y = Math.random() *h;
+ }
+ }
+ }
+
+ function showFriends(ctx) {
+ var w = canvas.width;
+ var h = canvas.height;
+ for (var i=0; i < twitterUser.friends.length && i < 15; i++) {
+ var friend = manager.getById(twitterUser.friends[i]);
+ if (friend && twitterUser.canvas.isImageLoaded(friend.image)) {
+ friend.hasFocus = false;
+ friend.show(ctx, false);
+ }
+ }
+ }
+
+ function linkFriends(ctx) {
+ var w = canvas.width;
+ var h = canvas.height;
+ for (var i=0; i < twitterUser.friends.length && i < 15; i++) {
+ var friend = manager.getById(twitterUser.friends[i]);
+ if (friend && twitterUser.canvas.isImageLoaded(friend.image)) {
+ if (!friend.linkColor)
+ friend.linkColor = Qt.rgba( ((Math.random() * 200) +55)/255
+ , ((Math.random() * 200) +55)/255
+ , ((Math.random() * 200) +55)/255, 0.8);
+ ctx.strokeStyle = friend.linkColor;
+ ctx.lineWidth = 8;
+ ctx.beginPath();
+ ctx.moveTo(twitterUser.posX + twitterUser.width/2, twitterUser.posY + twitterUser.height/2);
+ ctx.lineTo(friend.x + friend.width/2, friend.y + friend.height/2);
+ ctx.stroke();
+ }
+ }
+ }
+
+
+ function create(url) {
+ var x = new XMLHttpRequest;
+ x.open("GET", url);
+
+ x.onreadystatechange = function() {
+ if (x.readyState == XMLHttpRequest.DONE) {
+ var user = eval('(' + x.responseText +')')[0];
+ twitterUser.name = user.name;
+ twitterUser.twitterId = user.id;
+ twitterUser.image = user.profile_image_url;
+ twitterUser.canvas.loadImage(twitterUser.image);
+ twitterUser.url = user.url;
+ twitterUser.desc = user.description;
+ twitterUser.createFriends();
+ }
+ }
+ x.send();
+ }
+
+ function createByName(name) {
+ if (twitterUser.name === "" && twitterUser.twitterId === "") {
+ twitterUser.name = name;
+ var userUrl = "http://api.twitter.com/1/users/lookup.json?stringify_ids=true&screen_name=" + name;
+ twitterUser.create(userUrl);
+ }
+ }
+
+ function createById(id) {
+ if (twitterUser.name === "" && twitterUser.twitterId === "") {
+ twitterUser.twitterId = id;
+ var userUrl = "http://api.twitter.com/1/users/lookup.json?stringify_ids=true&user_id=" + id;
+ twitterUser.create(userUrl);
+ }
+ }
+
+ function createFriends() {
+ if (twitterUser.friends.length === 0) {
+ var x = new XMLHttpRequest;
+ var friendsUrl = "https://api.twitter.com/1/friends/ids.json?cursor=-1&stringify_ids=true&user_id=" + twitterUser.twitterId;
+ x.open("GET", friendsUrl);
+
+ x.onreadystatechange = function() {
+ if (x.readyState == XMLHttpRequest.DONE) {
+ twitterUser.friends = eval('(' + x.responseText +')').ids;
+ var doRequest = false;
+ var userUrl = "http://api.twitter.com/1/users/lookup.json?stringify_ids=true&user_id=";
+
+ for (var i=0; i<twitterUser.friends.length && i < 100; i++) {
+ var friend = manager.getById(twitterUser.friends[i]);
+ if (!friend) {
+ userUrl += "," + twitterUser.friends[i];
+ doRequest = true;
+ }
+ }
+
+ if (!doRequest) return;
+
+ var xx = new XMLHttpRequest;
+ xx.open("GET", userUrl);
+ xx.onreadystatechange = function() {
+ if (xx.readyState == XMLHttpRequest.DONE) {
+ var friendUsers = eval('(' + xx.responseText +')');
+ for(var i=0; i<friendUsers.length; i++) {
+ var friend = manager.createTwitterUser(twitterUser.canvas);
+ friend.name = friendUsers[i].name;
+ friend.twitterId = friendUsers[i].id;
+ friend.image = friendUsers[i].profile_image_url ? friendUsers[i].profile_image_url : "";
+ friend.url = friendUsers[i].url ? friendUsers[i].url : "";
+ friend.desc = friendUsers[i].description ? friendUsers[i].description : "";
+ friend.manager = twitterUser.manager;
+ twitterUser.canvas.loadImage(friend.image);
+ }
+
+ if (twitterUser.hasFocus && twitterUser.canvas) {
+ twitterUser.canvas.layoutChanged = true;
+ twitterUser.canvas.loading = false;
+ twitterUser.canvas.requestPaint();
+ }
+ }
+ }
+ xx.send();
+ }
+ }
+ x.send();
+ }
+ }
+} \ No newline at end of file
diff --git a/examples/demos/twitterfriends/cache.js b/examples/demos/twitterfriends/cache.js
new file mode 100644
index 0000000000..6c8a1cd71a
--- /dev/null
+++ b/examples/demos/twitterfriends/cache.js
@@ -0,0 +1,42 @@
+var UserCache = function() {
+ this._users = [];
+}
+
+
+UserCache.prototype.getById = function(id){
+ for (var i=0; i < this._users.length; i++){
+ var user = this._users[i];
+ if (user.twitterId == id) {
+ return user;
+ }
+ }
+}
+UserCache.prototype.getByName = function(name){
+ for (var i=0; i < this._users.length; i++){
+ var user = this._users[i];
+ if (user.name == name)
+ return user;
+ }
+}
+
+UserCache.prototype.add = function(user){
+ this._users[this._users.length] = user;
+}
+
+
+var cache = new UserCache;
+
+function getById(id) {
+ return cache.getById(id);
+}
+
+function getByName(name) {
+ return cache.getByName(name);
+}
+
+function createTwitterUser(canvas) {
+ var user = Qt.createQmlObject("import QtQuick 2.0; TwitterUser{}", canvas);
+ user.canvas = canvas;
+ cache.add(user);
+ return user;
+}
diff --git a/examples/demos/twitterfriends/friends.qml b/examples/demos/twitterfriends/friends.qml
new file mode 100644
index 0000000000..841b8bd2e1
--- /dev/null
+++ b/examples/demos/twitterfriends/friends.qml
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import "cache.js" as TwitterUserCache
+Rectangle {
+ width:360
+ height:600
+ color:"black"
+ QtObject {
+ id:twitterManager
+ function getById(id) {
+ return TwitterUserCache.cache.getById(id);
+ }
+
+ function getByName(name) {
+ return TwitterUserCache.cache.getByName(name);
+ }
+
+ function createTwitterUser(canvas) {
+ return TwitterUserCache.createTwitterUser(canvas);
+ }
+ }
+ Rectangle {
+ id:inputContainer
+ width:parent.width-4
+ height:40
+ anchors.top:parent.top
+ anchors.topMargin:4
+ anchors.horizontalCenter:parent.horizontalCenter
+ radius:8
+ border.color:"steelblue"
+ Text {
+ text:inputName.text == "" ? "Enter your twitter name..." : ""
+ id:inputLabel
+ anchors.centerIn:parent
+ font.pointSize:12
+ opacity:.5
+ color:"steelblue"
+ }
+ TextInput {
+ id:inputName
+ anchors.centerIn:parent
+ font.pointSize : 20
+ opacity:1
+ color:"steelblue"
+ width:parent.width-6
+ height:parent.height-6
+ text:""
+ autoScroll:true
+ focus:true
+ selectByMouse:true
+ onAccepted : {canvas.twitterName = text; canvas.requestPaint();}
+ }
+ }
+ Canvas {
+ id:canvas
+ width:parent.width
+ anchors.top :inputContainer.bottom
+ anchors.bottom : parent.bottom
+ smooth:true
+ renderTarget:Canvas.Image
+ renderStrategy: Canvas.Immediate
+
+ property bool layoutChanged:true
+ property string twitterName:""
+ property string twitterId:""
+ property bool loading:false
+
+ onLoadingChanged: requestPaint();
+ onWidthChanged: { layoutChanged = true; requestPaint();}
+ onHeightChanged: { layoutChanged = true; requestPaint();}
+ onTwitterNameChanged: inputName.text = twitterName;
+ onImageLoaded:requestPaint();
+ onPaint: {
+ var ctx = canvas.getContext('2d');
+ ctx.save();
+ ctx.fillStyle="black";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ if (canvas.twitterName != "" || canvas.twitterId != "") {
+ var user = canvas.twitterId ? TwitterUserCache.getById(canvas.twitterId) : TwitterUserCache.getByName(canvas.twitterName);
+ if (!user) {
+ user = TwitterUserCache.createTwitterUser(canvas);
+ user.hasFocus = true;
+ user.manager = twitterManager;
+ user.createByName(canvas.twitterName);
+ canvas.loading = true;
+ }
+
+ if (canvas.loading) {
+ ctx.font = "40px";
+ ctx.fillStyle = "steelblue";
+ ctx.fillText("Loading...", canvas.width/2 - 80, canvas.height/2);
+ } else {
+ user.show(ctx, layoutChanged);
+ }
+ layoutChanged = false;
+ }
+ ctx.restore();
+ }
+ }
+}
diff --git a/examples/demos/twitterfriends/twitterfriends.qmlproject b/examples/demos/twitterfriends/twitterfriends.qmlproject
new file mode 100644
index 0000000000..e841dee105
--- /dev/null
+++ b/examples/demos/twitterfriends/twitterfriends.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.1
+
+Project {
+ mainFile: "friends.qml"
+
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+} \ No newline at end of file