aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorSergio Ahumada <sergio.ahumada@digia.com>2013-08-05 10:42:21 +0200
committerSergio Ahumada <sergio.ahumada@digia.com>2013-08-05 10:42:21 +0200
commit1d3b9db5b54d8ae99c6b149c8d3d91eda19b5838 (patch)
tree9ffbf9d6d2ed6b0aef6155215767c56655ff405b /examples
parent45792359f25813af18b7416e4c18737ed4b20bff (diff)
parent0316506d9ddbc3ca9f26f880b9e7fb5d5b0fec36 (diff)
Merge branch 'stable' into dev
Conflicts: .qmake.conf Change-Id: I06f79bcbde13c7b12905492a17dbcbb4a594e557
Diffstat (limited to 'examples')
-rw-r--r--examples/quick/demos/tweetsearch/content/TweetDelegate.qml6
-rw-r--r--examples/quick/demos/tweetsearch/content/TweetsModel.qml96
-rw-r--r--examples/quick/demos/tweetsearch/content/tweetsearch.js61
-rw-r--r--examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc45
-rw-r--r--examples/quick/demos/tweetsearch/tweetsearch.pro5
-rw-r--r--examples/quick/demos/tweetsearch/tweetsearch.qml20
-rw-r--r--examples/quick/text/doc/src/text.qdoc2
7 files changed, 181 insertions, 54 deletions
diff --git a/examples/quick/demos/tweetsearch/content/TweetDelegate.qml b/examples/quick/demos/tweetsearch/content/TweetDelegate.qml
index 8cd22110d4..e8bfff437b 100644
--- a/examples/quick/demos/tweetsearch/content/TweetDelegate.qml
+++ b/examples/quick/demos/tweetsearch/content/TweetDelegate.qml
@@ -103,7 +103,7 @@ Item {
Text {
id: name
- text: Helper.realName(model.name)
+ text: model.name
anchors { left: avatar.right; leftMargin: 10; top: avatar.top; topMargin: -3 }
font.pixelSize: 12
font.bold: true
@@ -121,7 +121,7 @@ Item {
color: "#adebff"
linkColor: "white"
onLinkActivated: {
- var tag = link.split("http://search.twitter.com/search?q=%23")
+ var tag = link.split("https://twitter.com/search?q=%23")
var user = link.split("https://twitter.com/")
if (tag[1] != undefined) {
mainListView.positionViewAtBeginning()
@@ -166,7 +166,7 @@ Item {
Text {
id: username
- text: Helper.twitterName(model.name)
+ text: model.twitterName
x: 10; anchors { top: avatar2.top; topMargin: -3 }
font.pixelSize: 12
font.bold: true
diff --git a/examples/quick/demos/tweetsearch/content/TweetsModel.qml b/examples/quick/demos/tweetsearch/content/TweetsModel.qml
index cd91a787b7..7d813d18c8 100644
--- a/examples/quick/demos/tweetsearch/content/TweetsModel.qml
+++ b/examples/quick/demos/tweetsearch/content/TweetsModel.qml
@@ -39,53 +39,87 @@
****************************************************************************/
import QtQuick 2.0
-import QtQuick.XmlListModel 2.0
+import "tweetsearch.js" as Helper
Item {
id: wrapper
- property variant model: xmlModel
+ // Insert valid consumer key and secret tokens below
+ // See https://dev.twitter.com/apps
+//! [auth tokens]
+ property string consumerKey : ""
+ property string consumerSecret : ""
+//! [auth tokens]
+ property string bearerToken : ""
+
+ property variant model: tweets
property string from : ""
property string phrase : ""
- property string mode : "everyone"
- property int status: xmlModel.status
-
- function reload() { xmlModel.reload(); }
-
- property bool isLoading: status == XmlListModel.Loading
+ property int status: XMLHttpRequest.UNSENT
+ property bool isLoading: status === XMLHttpRequest.LOADING
property bool wasLoading: false
signal isLoaded
- XmlListModel {
- id: xmlModel
+ ListModel { id: tweets }
- onStatusChanged: {
- if (status == XmlListModel.Ready && wasLoading == true)
- wrapper.isLoaded()
- if (status == XmlListModel.Loading)
- wasLoading = true;
- else
- wasLoading = false;
- }
+ function encodePhrase(x) { return encodeURIComponent(x); }
- function encodePhrase(x) { return encodeURIComponent(x); }
+ function reload() {
+ tweets.clear()
- source: (from == "" && phrase == "") ? "" :
- 'http://search.twitter.com/search.atom?from='+from+"&rpp=10&phrase="+encodePhrase(phrase)
+ if (from == "" && phrase == "")
+ return;
- namespaceDeclarations: "declare default element namespace 'http://www.w3.org/2005/Atom'; " +
- "declare namespace twitter=\"http://api.twitter.com/\";";
+//! [requesting]
+ var req = new XMLHttpRequest;
+ req.open("GET", "https://api.twitter.com/1.1/search/tweets.json?from=" + from +
+ "&count=10&q=" + encodePhrase(phrase));
+ req.setRequestHeader("Authorization", "Bearer " + bearerToken);
+ req.onreadystatechange = function() {
+ status = req.readyState;
+ if (status === XMLHttpRequest.DONE) {
+ var objectArray = JSON.parse(req.responseText);
+ if (objectArray.errors !== undefined)
+ console.log("Error fetching tweets: " + objectArray.errors[0].message)
+ else {
+ for (var key in objectArray.statuses) {
+ var jsonObject = objectArray.statuses[key];
+ tweets.append(jsonObject);
+ }
+ }
+ if (wasLoading == true)
+ wrapper.isLoaded()
+ }
+ wasLoading = (status === XMLHttpRequest.LOADING);
+ }
+ req.send();
+//! [requesting]
+ }
- query: "/feed/entry"
+ onPhraseChanged: reload();
+ onFromChanged: reload();
- XmlRole { name: "id"; query: "id/string()" }
- XmlRole { name: "content"; query: "content/string()" }
- XmlRole { name: "published"; query: "published/string()" }
- XmlRole { name: "source"; query: "twitter:source/string()" }
- XmlRole { name: "name"; query: "author/name/string()" }
- XmlRole { name: "uri"; query: "author/uri/string()" }
- XmlRole { name: "image"; query: "link[@rel = 'image']/@href/string()" }
+ Component.onCompleted: {
+ if (consumerKey === "" || consumerSecret == "") {
+ bearerToken = encodeURIComponent(Helper.demoToken())
+ return;
+ }
+ var authReq = new XMLHttpRequest;
+ authReq.open("POST", "https://api.twitter.com/oauth2/token");
+ authReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
+ authReq.setRequestHeader("Authorization", "Basic " + Qt.btoa(consumerKey + ":" + consumerSecret));
+ authReq.onreadystatechange = function() {
+ if (authReq.readyState === XMLHttpRequest.DONE) {
+ var jsonResponse = JSON.parse(authReq.responseText);
+ if (jsonResponse.errors !== undefined)
+ console.log("Authentication error: " + jsonResponse.errors[0].message)
+ else
+ bearerToken = jsonResponse.access_token;
+ }
+ }
+ authReq.send("grant_type=client_credentials");
}
+
}
diff --git a/examples/quick/demos/tweetsearch/content/tweetsearch.js b/examples/quick/demos/tweetsearch/content/tweetsearch.js
index 9b8638f69e..42a76c99fc 100644
--- a/examples/quick/demos/tweetsearch/content/tweetsearch.js
+++ b/examples/quick/demos/tweetsearch/content/tweetsearch.js
@@ -1,19 +1,62 @@
.pragma library
-function twitterName(str)
+function formatDate(date)
{
- var s = str.split("(")
- return s[0]
+ var da = new Date(date)
+ return da.toDateString()
}
-function realName(str)
+function demoToken()
{
- var s = str.split("(")
- return s[1].substring(0, s[1].length-1)
+ var a = new Array(22).join('A')
+ return a + String.fromCharCode(0x44, 0x69, 0x4a, 0x52, 0x51, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x74, 0x2b, 0x72, 0x6a, 0x6c, 0x2b, 0x71,
+ 0x6d, 0x7a, 0x30, 0x72, 0x63, 0x79, 0x2b, 0x42, 0x62,
+ 0x75, 0x58, 0x42, 0x42, 0x73, 0x72, 0x55, 0x48, 0x47,
+ 0x45, 0x67, 0x3d, 0x71, 0x30, 0x45, 0x4b, 0x32, 0x61,
+ 0x57, 0x71, 0x51, 0x4d, 0x62, 0x31, 0x35, 0x67, 0x43,
+ 0x5a, 0x4e, 0x77, 0x5a, 0x6f, 0x39, 0x79, 0x71, 0x61,
+ 0x65, 0x30, 0x68, 0x70, 0x65, 0x32, 0x46, 0x44, 0x73,
+ 0x53, 0x39, 0x32, 0x57, 0x41, 0x75, 0x30, 0x67)
}
-function formatDate(date)
+function linkForEntity(entity)
{
- var da = new Date(date)
- return da.toDateString()
+ return (entity.url ? entity.url :
+ (entity.screen_name ? 'https://twitter.com/' + entity.screen_name :
+ 'https://twitter.com/search?q=%23' + entity.text))
+}
+
+function textForEntity(entity)
+{
+ return (entity.display_url ? entity.display_url :
+ (entity.screen_name ? entity.screen_name : entity.text))
+}
+
+function insertLinks(text, entities)
+{
+ if (typeof text !== 'string')
+ return "";
+
+ if (!entities)
+ return text;
+
+ // Add all links (urls, usernames and hashtags) to an array and sort them in
+ // descending order of appearance in text
+ var links = []
+ if (entities.urls)
+ links = entities.urls.concat(entities.hashtags, entities.user_mentions)
+ else if (entities.url)
+ links = entities.url.urls
+
+ links.sort(function(a, b) { return b.indices[0] - a.indices[0] })
+
+ for (var i = 0; i < links.length; i++) {
+ var offset = links[i].url ? 0 : 1
+ text = text.substring(0, links[i].indices[0] + offset) +
+ '<a href=\"' + linkForEntity(links[i]) + '\">' +
+ textForEntity(links[i]) + '</a>' +
+ text.substring(links[i].indices[1])
+ }
+ return text.replace(/\n/g, '<br>');
}
diff --git a/examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc b/examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc
index 9ba252fcb5..a56ed0d7e9 100644
--- a/examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc
+++ b/examples/quick/demos/tweetsearch/doc/src/tweetsearch.qdoc
@@ -32,5 +32,48 @@
\brief A Twitter search client with 3D effects.
\image qtquick-demo-tweetsearch-med-1.png
\image qtquick-demo-tweetsearch-med-2.png
-*/
+ \section1 Demo Introduction
+
+ The Tweet Search demo searches items posted to Twitter service
+ using a number of query parameters. Search can be done for tweets
+ from a specified user, a hashtag or a search phrase.
+
+ The search result is a list of items showing the contents of the
+ tweet as well as the name and image of the user who posted it.
+ Hashtags, names and links in the content are clickable. Clicking
+ on the image will flip the item to reveal more information.
+
+ \section1 Running the Demo
+
+ Tweet Search uses Twitter API v1.1 for running seaches.
+
+ \section2 Authentication
+
+ Each request must be authenticated on behalf of the application.
+ For demonstration purposes, the application uses a hard-coded
+ token for identifying itself to the Twitter service. However, this
+ token is subject to rate limits for the number of requests as well
+ as possible expiration.
+
+ If you are having authentication or rate limit problems running the
+ demo, obtain a set of application-specific tokens (consumer
+ key and consumer secret) by registering a new application on
+ \l{https://dev.twitter.com/apps}.
+
+ Type in the two token values in \e {TweetsModel.qml}:
+
+ \snippet demos/tweetsearch/content/TweetsModel.qml auth tokens
+
+ Rebuild and run the demo.
+
+ \section2 JSON Parsing
+
+ Search results are returned in JSON (JavaScript Object Notation)
+ format. \c TweetsModel uses an \l XMLHTTPRequest object to send
+ an HTTP GET request, and calls JSON.parse() on the returned text
+ string to convert it to a JavaScript object. Each object
+ representing a tweet is then added to a \l ListModel:
+
+ \snippet demos/tweetsearch/content/TweetsModel.qml requesting
+*/
diff --git a/examples/quick/demos/tweetsearch/tweetsearch.pro b/examples/quick/demos/tweetsearch/tweetsearch.pro
index b063cc4106..27c34bac5d 100644
--- a/examples/quick/demos/tweetsearch/tweetsearch.pro
+++ b/examples/quick/demos/tweetsearch/tweetsearch.pro
@@ -4,5 +4,10 @@ QT += quick qml
SOURCES += main.cpp
RESOURCES += tweetsearch.qrc
+OTHER_FILES = tweetsearch.qml \
+ content/*.qml \
+ content/*.js \
+ content/resources/*
+
target.path = $$[QT_INSTALL_EXAMPLES]/quick/demos/tweetsearch
INSTALLS += target
diff --git a/examples/quick/demos/tweetsearch/tweetsearch.qml b/examples/quick/demos/tweetsearch/tweetsearch.qml
index d7e77ceb4b..19d3b5e708 100644
--- a/examples/quick/demos/tweetsearch/tweetsearch.qml
+++ b/examples/quick/demos/tweetsearch/tweetsearch.qml
@@ -40,6 +40,7 @@
import QtQuick 2.0
import "content"
+import "content/tweetsearch.js" as Helper
Rectangle {
id: main
@@ -47,7 +48,6 @@ Rectangle {
height: 480
color: "#d6d6d6"
- property string searchTerms: ""
property int inAnimDur: 250
property int counter: 0
property alias isLoading: tweetsModel.isLoading
@@ -85,13 +85,15 @@ Rectangle {
onTriggered: {
main.counter--;
var id = tweetsModel.model.get(idx[main.counter]).id
- mainListView.add( { "statusText": tweetsModel.model.get(main.counter).content,
- "name": tweetsModel.model.get(main.counter).name,
- "userImage": tweetsModel.model.get(main.counter).image,
- "source": tweetsModel.model.get(main.counter).source,
- "id": id,
- "uri": tweetsModel.model.get(main.counter).uri,
- "published": tweetsModel.model.get(main.counter).published } );
+ var item = tweetsModel.model.get(main.counter)
+ mainListView.add( { "statusText": Helper.insertLinks(item.text, item.entities),
+ "twitterName": item.user.screen_name,
+ "name" : item.user.name,
+ "userImage": item.user.profile_image_url,
+ "source": item.source,
+ "id": id,
+ "uri": Helper.insertLinks(item.user.url, item.user.entities),
+ "published": item.created_at } );
ids.push(id)
}
}
@@ -107,7 +109,7 @@ Rectangle {
PropertyAction { property: "appear"; value: 250 }
}
- onDragEnded: if (header.refresh) { tweetsModel.model.reload() }
+ onDragEnded: if (header.refresh) { tweetsModel.reload() }
ListHeader {
id: header
diff --git a/examples/quick/text/doc/src/text.qdoc b/examples/quick/text/doc/src/text.qdoc
index c93d2db8aa..3a300fbcf3 100644
--- a/examples/quick/text/doc/src/text.qdoc
+++ b/examples/quick/text/doc/src/text.qdoc
@@ -50,7 +50,7 @@
or finally using a FontLoader and specifying a remote font file:
\snippet text/fonts/fonts.qml fontloaderremote
- 'Available Fonts' shows how to use the QML global Qt object and a list view
+ 'Available Fonts' shows how to use the QML \l{QtQml::Qt}{Qt} global object and a list view
to display all the fonts available on the system.
The ListView type uses the list of fonts available as its model:
\snippet text/fonts/availableFonts.qml model