summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrik Hartz <henrik.hartz@nokia.com>2009-06-15 14:08:42 +0200
committerHenrik Hartz <henrik.hartz@nokia.com>2009-06-15 14:08:42 +0200
commitf7da31f66ed183c77b896aef2719a6f38fc4b843 (patch)
tree5a3d54ab51a1be17954134cd020610175c1038b7
parent23e90c3d691282b08b339ab19974d4bc4e214588 (diff)
Two WebKit examples demonstrating mixing native and web environments
using Qt
-rw-r--r--twitterview/BUGS7
-rw-r--r--twitterview/README20
-rw-r--r--twitterview/images/loading.gifbin0 -> 847 bytes
-rw-r--r--twitterview/login.html68
-rw-r--r--twitterview/main.cpp38
-rw-r--r--twitterview/mainwindow.cpp89
-rw-r--r--twitterview/mainwindow.h54
-rw-r--r--twitterview/mainwindow.ui258
-rw-r--r--twitterview/transforms/followers.xsl57
-rw-r--r--twitterview/transforms/friends.xsl58
-rw-r--r--twitterview/transforms/multiuser.xsl102
-rw-r--r--twitterview/transforms/public.xsl88
-rw-r--r--twitterview/transforms/singleuser.xsl85
-rw-r--r--twitterview/transforms/twitterview.xsl188
-rw-r--r--twitterview/twitter.cpp156
-rw-r--r--twitterview/twitter.h90
-rw-r--r--twitterview/twitter.html37
-rw-r--r--twitterview/twitterview.cpp183
-rw-r--r--twitterview/twitterview.h53
-rw-r--r--twitterview/twitterview.pro19
-rw-r--r--twitterview/twitterview.qrc13
-rw-r--r--videofeed/.DS_Storebin0 -> 6148 bytes
-rw-r--r--videofeed/README17
-rw-r--r--videofeed/html/json2.js478
-rw-r--r--videofeed/html/loading.gifbin0 -> 847 bytes
-rw-r--r--videofeed/html/next.pngbin0 -> 948 bytes
-rw-r--r--videofeed/html/prev.pngbin0 -> 945 bytes
-rw-r--r--videofeed/html/settings.js102
-rw-r--r--videofeed/html/videoplayer.html336
-rw-r--r--videofeed/main.cpp38
-rw-r--r--videofeed/mainwindow.cpp250
-rw-r--r--videofeed/mainwindow.h87
-rw-r--r--videofeed/mainwindow.ui147
-rw-r--r--videofeed/rss/ted.ini6
-rw-r--r--videofeed/rss/ted.xq12
-rw-r--r--videofeed/rss/youtube.xq11
-rw-r--r--videofeed/rss/youtube_qtstudios.ini5
-rw-r--r--videofeed/rss/youtube_recently_added.ini5
-rw-r--r--videofeed/rss/youtube_recently_featured.ini5
-rw-r--r--videofeed/rss/youtube_topfav.ini5
-rw-r--r--videofeed/teddemo.qrc19
-rw-r--r--videofeed/videofeed.pro14
42 files changed, 3200 insertions, 0 deletions
diff --git a/twitterview/BUGS b/twitterview/BUGS
new file mode 100644
index 0000000..ed7349e
--- /dev/null
+++ b/twitterview/BUGS
@@ -0,0 +1,7 @@
+1. xsl:include does not work in 4.5. As a result, the template
+ processText is copy/pasted.
+
+2. xsl:analyze-string is not supported for 4.5. When it works we
+ can do more fancy string parsing.
+
+3. XSL encoding error.
diff --git a/twitterview/README b/twitterview/README
new file mode 100644
index 0000000..fa66609
--- /dev/null
+++ b/twitterview/README
@@ -0,0 +1,20 @@
+TwitterView displays Twitter messages from your friends, followers and
+the public.
+
+Twitter provides a REST API [1]. Responses may be received in XML, JSON,
+RSS or ATOM. This example receives responses from Twitter in XML and
+translates the XML into HTML using XSL-T.
+
+The demonstration makes use of the new XSL-T 2.0 support in Qt 4.5.
+Support for XSLT 2.0 is provided through the class QXmlQuery and
+is part of QtXmlPatterns module. The HTML is displayed using
+Qt/WebKit.
+
+The programs displays the background image, background color, text color,
+link color as customized by the user on the Twitter website.
+
+Portions of the HTML are dynamically created and inserted into the main
+HTML. For example, the list of friends is queried and the XML response
+is translated into a HTML fragement which is inserted into the main HTML.
+
+[1]. http://apiwiki.twitter.com/REST+API+Documentation
diff --git a/twitterview/images/loading.gif b/twitterview/images/loading.gif
new file mode 100644
index 0000000..c1545eb
--- /dev/null
+++ b/twitterview/images/loading.gif
Binary files differ
diff --git a/twitterview/login.html b/twitterview/login.html
new file mode 100644
index 0000000..ca3ac0d
--- /dev/null
+++ b/twitterview/login.html
@@ -0,0 +1,68 @@
+<html>
+
+<head>
+<style>
+ #login_failed_div {
+ color: red;
+ display: none;
+ }
+</style>
+<script>
+ function init() {
+ twitter.credentialsVerified.connect(credentialsVerified);
+ }
+
+ function login() {
+ var userName = login_form.login_edit.value;
+ var password = login_form.password_edit.value;
+
+ twitter.userName = userName;
+ twitter.password = password;
+
+ document.getElementById('login_failed_div').style.display = 'none';
+ login_form.login_button.disabled = true;
+
+ twitter.verifyCredentials();
+ }
+
+ function credentialsVerified(success) {
+ if (success) {
+ window.location.href = "twitter.html";
+ } else {
+ login_form.password_edit.value = '';
+ document.getElementById('login_failed_div').style.display = 'block';
+ login_form.login_button.disabled = false;
+ }
+ }
+</script>
+</head>
+
+<body onload="init()">
+ <h1> Login to Twitter </h1>
+
+ <form name="login_form" action="" onsubmit="login(); return false">
+ <table>
+ <tr>
+ <td> Login: </td>
+ <td> <input type="text" name="login_edit" id="login_edit"> </td>
+ </tr>
+
+ <tr>
+ <td> Password: </td>
+ <td> <input type="password" name="password_edit" id="password_edit"> </td>
+ </tr>
+
+ <tr>
+ <td></td>
+ <td> <input type="submit" name="login_button" value="Login"> </input> </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td> <div id="login_failed_div"> Login failed, please try again </div> </td>
+ </tr>
+ </table>
+ </form>
+
+</body>
+
+</html>
diff --git a/twitterview/main.cpp b/twitterview/main.cpp
new file mode 100644
index 0000000..bc33665
--- /dev/null
+++ b/twitterview/main.cpp
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtGui>
+#include <QtWebKit>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ MainWindow *mainWindow = new MainWindow;
+ mainWindow->show();
+
+ return app.exec();
+}
+
diff --git a/twitterview/mainwindow.cpp b/twitterview/mainwindow.cpp
new file mode 100644
index 0000000..c09f48c
--- /dev/null
+++ b/twitterview/mainwindow.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtGui>
+#include <QtNetwork>
+
+#include "mainwindow.h"
+#include "twitterview.h"
+#include "twitter.h"
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+{
+ ui.setupUi(this);
+ connect(ui.action_Quit, SIGNAL(triggered()), qApp, SLOT(quit()));
+ connect(ui.actionAbout_TwitterView, SIGNAL(triggered()), this, SLOT(about()));
+ connect(ui.actionAbout_Qt, SIGNAL(triggered()), this, SLOT(aboutQt()));
+ connect(ui.loginButton, SIGNAL(clicked()), this, SLOT(login()));
+
+ m_movie = new QMovie(this);
+ m_movie->setFileName(":/images/loading.gif");
+ m_movie->start();
+ ui.progressLabel->setText(QString());
+
+ m_twitter = new Twitter(this);
+ connect(m_twitter, SIGNAL(credentialsVerified(bool, QString)),
+ this, SLOT(credentialsVerified(bool, QString)));
+
+ statusBar()->showMessage(tr("Ready."));
+}
+
+MainWindow::~MainWindow()
+{
+}
+
+void MainWindow::login()
+{
+ ui.loginButton->setEnabled(false);
+ ui.progressLabel->setText(QString());
+ ui.progressLabel->setMovie(m_movie);
+ m_twitter->setUserName(ui.userNameEdit->text());
+ m_twitter->setPassword(ui.passwordEdit->text());
+ m_twitter->verifyCredentials();
+ statusBar()->showMessage(tr("Logging in"));
+}
+
+void MainWindow::credentialsVerified(bool success, const QString &msg)
+{
+ if (success) {
+ statusBar()->showMessage(tr("Logged in"));
+ setCentralWidget(new TwitterView(m_twitter));
+ } else {
+ ui.progressLabel->setText(tr("Login failed!"));
+ statusBar()->showMessage(tr("Login failed - %1").arg(msg));
+ ui.loginButton->setEnabled(true);
+ }
+}
+
+void MainWindow::about()
+{
+ QMessageBox::about(this, tr("TwitterView Demo"),
+ tr("Demonstrates the use of QtXmlPatterns/XSLT with WebKit"));
+}
+
+void MainWindow::aboutQt()
+{
+ QMessageBox::aboutQt(this);
+}
+
diff --git a/twitterview/mainwindow.h b/twitterview/mainwindow.h
new file mode 100644
index 0000000..48d94f6
--- /dev/null
+++ b/twitterview/mainwindow.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QMovie>
+#include "ui_mainwindow.h"
+
+class Twitter;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+private slots:
+ void about();
+ void aboutQt();
+ void login();
+ void credentialsVerified(bool success, const QString &msg);
+
+private:
+ Ui::MainWindow ui;
+ Twitter *m_twitter;
+ QMovie *m_movie;
+};
+
+#endif // MAINWINDOW_H
+
diff --git a/twitterview/mainwindow.ui b/twitterview/mainwindow.ui
new file mode 100644
index 0000000..134be05
--- /dev/null
+++ b/twitterview/mainwindow.ui
@@ -0,0 +1,258 @@
+<ui version="4.0" >
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Twitter View</string>
+ </property>
+ <widget class="QWidget" name="centralwidget" >
+ <layout class="QGridLayout" name="gridLayout_2" >
+ <item row="0" column="1" >
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>253</width>
+ <height>179</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" >
+ <spacer name="horizontalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>254</width>
+ <height>150</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" >
+ <layout class="QGridLayout" name="gridLayout" >
+ <property name="sizeConstraint" >
+ <enum>QLayout::SetFixedSize</enum>
+ </property>
+ <item row="0" column="0" colspan="3" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
+p, li { white-space: pre-wrap; }
+&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+&lt;p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&lt;span style=" font-size:14pt; font-weight:600;">Login to Twitter&lt;/span>&lt;/p>&lt;/body>&lt;/html></string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <spacer name="verticalSpacer_3" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Maximum</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>44</width>
+ <height>17</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>&amp;User Name:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy" >
+ <cstring>passwordEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" colspan="2" >
+ <widget class="QLineEdit" name="userNameEdit" />
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>&amp;Password:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy" >
+ <cstring>userNameEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2" >
+ <widget class="QLineEdit" name="passwordEdit" >
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLabel" name="progressLabel" >
+ <property name="minimumSize" >
+ <size>
+ <width>105</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="styleSheet" >
+ <string notr="true" >QLabel { color: red; font-weight: bold; min-width: 15ex; }</string>
+ </property>
+ <property name="text" >
+ <string>Login Progress.....</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2" >
+ <widget class="QPushButton" name="loginButton" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Maximum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>&amp;Login</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="2" >
+ <spacer name="horizontalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>254</width>
+ <height>150</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" >
+ <spacer name="verticalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>253</width>
+ <height>179</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>30</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menu_File" >
+ <property name="title" >
+ <string>&amp;File</string>
+ </property>
+ <addaction name="action_Quit" />
+ </widget>
+ <widget class="QMenu" name="menu_Help" >
+ <property name="title" >
+ <string>&amp;Help</string>
+ </property>
+ <addaction name="actionAbout_TwitterView" />
+ <addaction name="separator" />
+ <addaction name="actionAbout_Qt" />
+ </widget>
+ <addaction name="menu_File" />
+ <addaction name="menu_Help" />
+ </widget>
+ <widget class="QStatusBar" name="statusbar" />
+ <action name="action_Quit" >
+ <property name="text" >
+ <string>&amp;Quit</string>
+ </property>
+ </action>
+ <action name="actionAbout_TwitterView" >
+ <property name="text" >
+ <string>About TwitterView</string>
+ </property>
+ </action>
+ <action name="actionAbout_Qt" >
+ <property name="text" >
+ <string>About &amp;Qt</string>
+ </property>
+ </action>
+ </widget>
+ <tabstops>
+ <tabstop>userNameEdit</tabstop>
+ <tabstop>passwordEdit</tabstop>
+ <tabstop>loginButton</tabstop>
+ </tabstops>
+ <resources>
+ <include location="twitterview.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>userNameEdit</sender>
+ <signal>returnPressed()</signal>
+ <receiver>loginButton</receiver>
+ <slot>click()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>384</x>
+ <y>296</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>485</x>
+ <y>358</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>passwordEdit</sender>
+ <signal>returnPressed()</signal>
+ <receiver>loginButton</receiver>
+ <slot>click()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>366</x>
+ <y>335</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>508</x>
+ <y>370</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/twitterview/transforms/followers.xsl b/twitterview/transforms/followers.xsl
new file mode 100644
index 0000000..e11cb18
--- /dev/null
+++ b/twitterview/transforms/followers.xsl
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of TwitterView**
+ *
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
+ *
+ * Contact: Qt Software Information (qt-info@nokia.com)**
+ *
+ * Commercial Usage
+ * Licensees holding valid Qt Commercial licenses may use this file in
+ * accordance with the Qt Commercial License Agreement provided with the
+ * Software or, alternatively, in accordance with the terms contained in
+ * a written agreement between you and Nokia.
+ *
+ * GNU Lesser General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU Lesser General Public License version 2.1 only as published by the
+ * Free Software Foundation and appearing in the file LICENSE.LGPL included
+ * in the packaging of this file. Please review the following information
+ * to ensure the GNU Lesser General Public License version 2.1 requirements
+ * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * GNU General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU General Public License version 3.0 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file. Please review the following information to ensure
+ * the GNU General Public License version 3.0 requirements will be
+ * met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * If you are unsure which license is appropriate for your use, please contact
+ * the sales department at qt-sales@nokia.com.
+-->
+
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method='html' version='2.0' encoding='UTF-8' indent='yes'/>
+
+<xsl:template match="/users">
+
+<ul>
+<xsl:for-each select="user">
+ <li style="display:inline; margin: 1px">
+ <a>
+ <xsl:attribute name="href">#follower_<xsl:value-of select="screen_name"/></xsl:attribute>
+ <xsl:attribute name="title"><xsl:value-of select="name"/></xsl:attribute>
+ <img style="margin: 2px 5px">
+ <xsl:attribute name="width"><xsl:value-of select="20 + min((50, followers_count))"/></xsl:attribute>
+ <xsl:attribute name="height"><xsl:value-of select="20 + min((50, followers_count))"/></xsl:attribute>
+ <xsl:attribute name="src"><xsl:value-of select="profile_image_url"/></xsl:attribute>
+ </img>
+ </a>
+ </li>
+</xsl:for-each>
+</ul>
+
+</xsl:template>
+</xsl:stylesheet>
diff --git a/twitterview/transforms/friends.xsl b/twitterview/transforms/friends.xsl
new file mode 100644
index 0000000..b517c46
--- /dev/null
+++ b/twitterview/transforms/friends.xsl
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * This file is part of TwitterView**
+ *
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
+ *
+ * Contact: Qt Software Information (qt-info@nokia.com)**
+ *
+ * Commercial Usage
+ * Licensees holding valid Qt Commercial licenses may use this file in
+ * accordance with the Qt Commercial License Agreement provided with the
+ * Software or, alternatively, in accordance with the terms contained in
+ * a written agreement between you and Nokia.
+ *
+ * GNU Lesser General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU Lesser General Public License version 2.1 only as published by the
+ * Free Software Foundation and appearing in the file LICENSE.LGPL included
+ * in the packaging of this file. Please review the following information
+ * to ensure the GNU Lesser General Public License version 2.1 requirements
+ * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * GNU General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU General Public License version 3.0 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file. Please review the following information to ensure
+ * the GNU General Public License version 3.0 requirements will be
+ * met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * If you are unsure which license is appropriate for your use, please contact
+ * the sales department at qt-sales@nokia.com.
+-->
+
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method='html' version='2.0' encoding='UTF-8' indent='yes'/>
+
+<xsl:template match="/users">
+
+<ul>
+<xsl:for-each select="user">
+<xsl:sort select="followers_count"/>
+ <li>
+ <a>
+ <xsl:attribute name="href">#friend_<xsl:value-of select="screen_name"/></xsl:attribute>
+ <xsl:attribute name="title"><xsl:value-of select="name"/></xsl:attribute>
+ <img width="32" height="32" style="vertical-align: middle; margin-right: 10px">
+ <xsl:attribute name="src"><xsl:value-of select="profile_image_url"/></xsl:attribute>
+ </img>
+ <xsl:value-of select="name"/>
+ </a>
+ </li>
+</xsl:for-each>
+</ul>
+
+</xsl:template>
+</xsl:stylesheet>
diff --git a/twitterview/transforms/multiuser.xsl b/twitterview/transforms/multiuser.xsl
new file mode 100644
index 0000000..56d5421
--- /dev/null
+++ b/twitterview/transforms/multiuser.xsl
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * This file is part of TwitterView**
+ *
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
+ *
+ * Contact: Qt Software Information (qt-info@nokia.com)**
+ *
+ * Commercial Usage
+ * Licensees holding valid Qt Commercial licenses may use this file in
+ * accordance with the Qt Commercial License Agreement provided with the
+ * Software or, alternatively, in accordance with the terms contained in
+ * a written agreement between you and Nokia.
+ *
+ * GNU Lesser General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU Lesser General Public License version 2.1 only as published by the
+ * Free Software Foundation and appearing in the file LICENSE.LGPL included
+ * in the packaging of this file. Please review the following information
+ * to ensure the GNU Lesser General Public License version 2.1 requirements
+ * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * GNU General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU General Public License version 3.0 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file. Please review the following information to ensure
+ * the GNU General Public License version 3.0 requirements will be
+ * met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * If you are unsure which license is appropriate for your use, please contact
+ * the sales department at qt-sales@nokia.com.
+-->
+
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:fb="http://www.forwardbias.in">
+<xsl:output method='html' version='2.0' encoding='UTF-8' indent='yes'/>
+
+<xsl:template name="processText">
+ <xsl:param name="text"/>
+ <xsl:param name="in_reply_to"/>
+
+ <xsl:choose>
+ <xsl:when test="$in_reply_to = ''">
+ <xsl:value-of select="$text"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <a>
+ <xsl:attribute name="href">#friend_<xsl:value-of select="$in_reply_to"/></xsl:attribute>
+ <xsl:value-of select="$in_reply_to"/>
+ </a>
+ <span> : <xsl:value-of select="substring-after(string($text), concat('@', $in_reply_to))"/> </span>
+ </xsl:otherwise>
+ </xsl:choose>
+
+</xsl:template>
+
+<xsl:template match="/">
+
+<form style="margin-bottom: 10px" onsubmit="view.setStatus(document.getElementById('status').value); return false;">
+ <input type="text" value="What are you doing..." style="width: 450px" id="status" onfocus="this.value=''"></input>
+ <input style="vertical-align: middle" type="submit" value="Update"/>
+</form>
+
+<table border="0" width="100%" cellspacing="0">
+<xsl:for-each select="statuses/status">
+<tr>
+ <xsl:if test="position() mod 2 = 1">
+ <xsl:attribute name="style">background: #DDFFCC</xsl:attribute>
+ </xsl:if>
+
+ <td rowspan="2" width="200px">
+ <img style="float: left; margin: 3px; margin-right: 10px" width="50" height="50"><xsl:attribute name="src"><xsl:value-of select="user/profile_image_url"/></xsl:attribute></img>
+ <a style="margin-right: 10px; font-weight: bold">
+ <xsl:attribute name="href">#friend_<xsl:value-of select="user/screen_name"/></xsl:attribute>
+ <xsl:value-of select="user/name"/>
+ </a>
+ </td>
+
+ <td>
+ <xsl:call-template name="processText">
+ <xsl:with-param name="text" select="text"/>
+ <xsl:with-param name="in_reply_to" select="in_reply_to_screen_name"/>
+ </xsl:call-template>
+ </td>
+</tr>
+<tr>
+ <xsl:if test="position() mod 2 = 1">
+ <xsl:attribute name="style">background: #DDFFCC</xsl:attribute>
+ </xsl:if>
+
+ <td valign="bottom" style="font-size: 8pt; font-style: italic">
+ <div> <xsl:value-of select="created_at"/> </div>
+ </td>
+</tr>
+</xsl:for-each>
+</table>
+
+</xsl:template>
+</xsl:stylesheet>
diff --git a/twitterview/transforms/public.xsl b/twitterview/transforms/public.xsl
new file mode 100644
index 0000000..08d1ae3
--- /dev/null
+++ b/twitterview/transforms/public.xsl
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+* This file is part of TwitterView**
+*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
+*
+* Contact: Qt Software Information (qt-info@nokia.com)**
+*
+* Commercial Usage
+* Licensees holding valid Qt Commercial licenses may use this file in
+* accordance with the Qt Commercial License Agreement provided with the
+* Software or, alternatively, in accordance with the terms contained in
+* a written agreement between you and Nokia.
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this file may be used under the terms of the
+* GNU Lesser General Public License version 2.1 only as published by the
+* Free Software Foundation and appearing in the file LICENSE.LGPL included
+* in the packaging of this file. Please review the following information
+* to ensure the GNU Lesser General Public License version 2.1 requirements
+* will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+*
+* GNU General Public License Usage
+* Alternatively, this file may be used under the terms of the
+* GNU General Public License version 3.0 as published by the Free Software
+* Foundation and appearing in the file LICENSE.GPL included in the
+* packaging of this file. Please review the following information to ensure
+* the GNU General Public License version 3.0 requirements will be
+* met: http://www.gnu.org/copyleft/gpl.html.
+*
+* If you are unsure which license is appropriate for your use, please contact
+* the sales department at qt-sales@nokia.com.
+-->
+
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:fb="http://www.forwardbias.in">
+<xsl:output method='html' version='2.0' encoding='UTF-8' indent='yes'/>
+
+<xsl:template name="processText">
+ <xsl:param name="text"/>
+
+ <xsl:value-of select="$text"/>
+</xsl:template>
+
+<xsl:template match="/">
+
+<form style="margin-bottom: 10px" onsubmit="view.setStatus(document.getElementById('status').value); return false;">
+ <input type="text" value="What are you doing..." style="width: 450px" id="status" onfocus="this.value=''"></input>
+ <input style="vertical-align: middle" type="submit" value="Update"/>
+</form>
+
+<table border="0" width="100%" cellspacing="0">
+<xsl:for-each select="statuses/status">
+<tr>
+ <xsl:if test="position() mod 2 = 1">
+ <xsl:attribute name="style">background: #DDFFCC</xsl:attribute>
+ </xsl:if>
+
+ <td rowspan="2" width="200px">
+ <img style="float: left; margin: 3px; margin-right: 10px" width="50" height="50"><xsl:attribute name="src"><xsl:value-of select="user/profile_image_url"/></xsl:attribute></img>
+ <a style="margin-right: 10px; font-weight: bold">
+ <xsl:attribute name="href">#friend_<xsl:value-of select="user/screen_name"/></xsl:attribute>
+ <xsl:value-of select="user/name"/>
+ </a>
+ </td>
+
+ <td>
+ <xsl:call-template name="processText">
+ <xsl:with-param name="text" select="text"/>
+ </xsl:call-template>
+ </td>
+</tr>
+<tr>
+ <xsl:if test="position() mod 2 = 1">
+ <xsl:attribute name="style">background: #DDFFCC</xsl:attribute>
+ </xsl:if>
+
+ <td valign="bottom" style="font-size: 8pt; font-style: italic">
+ <div> <xsl:value-of select="created_at"/> </div>
+ </td>
+</tr>
+</xsl:for-each>
+</table>
+
+</xsl:template>
+</xsl:stylesheet>
diff --git a/twitterview/transforms/singleuser.xsl b/twitterview/transforms/singleuser.xsl
new file mode 100644
index 0000000..36d7e4a
--- /dev/null
+++ b/twitterview/transforms/singleuser.xsl
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * This file is part of TwitterView**
+ *
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
+ *
+ * Contact: Qt Software Information (qt-info@nokia.com)**
+ *
+ * Commercial Usage
+ * Licensees holding valid Qt Commercial licenses may use this file in
+ * accordance with the Qt Commercial License Agreement provided with the
+ * Software or, alternatively, in accordance with the terms contained in
+ * a written agreement between you and Nokia.
+ *
+ * GNU Lesser General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU Lesser General Public License version 2.1 only as published by the
+ * Free Software Foundation and appearing in the file LICENSE.LGPL included
+ * in the packaging of this file. Please review the following information
+ * to ensure the GNU Lesser General Public License version 2.1 requirements
+ * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * GNU General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU General Public License version 3.0 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file. Please review the following information to ensure
+ * the GNU General Public License version 3.0 requirements will be
+ * met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * If you are unsure which license is appropriate for your use, please contact
+ * the sales department at qt-sales@nokia.com.
+-->
+
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method='html' version='2.0' encoding='UTF-8' indent='yes'/>
+
+<xsl:template name="processText">
+ <xsl:param name="text"/>
+ <xsl:param name="in_reply_to"/>
+
+ <xsl:choose>
+ <xsl:when test="$in_reply_to = ''">
+ <xsl:value-of select="$text"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <a>
+ <xsl:attribute name="href">#friend_<xsl:value-of select="$in_reply_to"/></xsl:attribute>
+ <xsl:value-of select="$in_reply_to"/>
+ </a>
+ <span> : <xsl:value-of select="substring-after(string($text), concat('@', $in_reply_to))"/> </span>
+ </xsl:otherwise>
+ </xsl:choose>
+
+</xsl:template>
+
+<xsl:template match="/">
+
+<table border="0" width="100%" cellpadding="5" style="border-spacing: 5px">
+<xsl:for-each select="statuses/status">
+<tr style="margin-bottom: 10px; padding: 2px;">
+ <td>
+ <xsl:if test="position() mod 2 = 1">
+ <xsl:attribute name="style">background-color: #DDFFCC</xsl:attribute>
+ </xsl:if>
+
+ <div>
+ <xsl:if test="position() = 1">
+ <xsl:attribute name="style"> font-size: 16pt </xsl:attribute>
+ </xsl:if>
+ <xsl:call-template name="processText">
+ <xsl:with-param name="text" select="text"/>
+ <xsl:with-param name="in_reply_to" select="in_reply_to_screen_name"/>
+ </xsl:call-template>
+ </div>
+
+ <div style="font-size: 8pt; font-style: italic; margin-top: 10px"> <xsl:value-of select="created_at"/> </div>
+ </td>
+</tr>
+</xsl:for-each>
+</table>
+
+</xsl:template>
+</xsl:stylesheet>
diff --git a/twitterview/transforms/twitterview.xsl b/twitterview/transforms/twitterview.xsl
new file mode 100644
index 0000000..a682f5a
--- /dev/null
+++ b/twitterview/transforms/twitterview.xsl
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * This file is part of TwitterView**
+ *
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
+ *
+ * Contact: Qt Software Information (qt-info@nokia.com)**
+ *
+ * Commercial Usage
+ * Licensees holding valid Qt Commercial licenses may use this file in
+ * accordance with the Qt Commercial License Agreement provided with the
+ * Software or, alternatively, in accordance with the terms contained in
+ * a written agreement between you and Nokia.
+ *
+ * GNU Lesser General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU Lesser General Public License version 2.1 only as published by the
+ * Free Software Foundation and appearing in the file LICENSE.LGPL included
+ * in the packaging of this file. Please review the following information
+ * to ensure the GNU Lesser General Public License version 2.1 requirements
+ * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * GNU General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU General Public License version 3.0 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file. Please review the following information to ensure
+ * the GNU General Public License version 3.0 requirements will be
+ * met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * If you are unsure which license is appropriate for your use, please contact
+ * the sales department at qt-sales@nokia.com.
+-->
+
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method='html' version='2.0' encoding='UTF-8' indent='yes'/>
+<xsl:template match="user">
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+
+body {
+ background-color: #<xsl:value-of select="profile_background_color"/>;
+ background-image: url(<xsl:value-of select="profile_background_image_url"/>);
+ background-position: top left;
+ background-attachment: fixed;
+ <xsl:choose>
+ <xsl:when test="profile_background_tile = 'true'">
+ background-repeat: repeat;
+ </xsl:when>
+ <xsl:otherwise>
+ background-repeat: no-repeat;
+ </xsl:otherwise>
+ </xsl:choose>
+}
+
+* {
+ color: #<xsl:value-of select="profile_text_color"/>;
+}
+
+a {
+ color: #<xsl:value-of select="profile_link_color"/>;
+}
+
+header, nav, article, section, footer {
+ display: block;
+}
+
+header {
+ width: 100%;
+ margin-bottom: 30px;
+}
+
+nav {
+ margin: 0;
+ padding: 0;
+ float: left;
+ width: 200px;
+ background-color: #<xsl:value-of select="profile_sidebar_fill_color"/>;
+ border: 1px solid #<xsl:value-of select="profile_sidebar_border_color"/>;
+}
+
+section {
+ margin-left: 210px;
+}
+
+footer {
+ margin-top: 30px;
+ text-align: center;
+ color: darkgray;
+}
+
+.navheader {
+ padding: 3px 10px;
+ font-size: 14pt;
+ font-weight: bold;
+}
+
+nav ul {
+ margin: 0;
+ margin-bottom: 10px;
+ padding: 0;
+ padding-left: 10px;
+}
+
+nav li {
+ list-style-type: none;
+ margin-bottom: 5px;
+}
+
+img {
+ border: 1px solid black;
+}
+
+#welcome {
+ font-size: 16pt;
+ font-weight: bold;
+ display: inline;
+}
+
+#profile_image {
+ float: left;
+ margin-right: 10px;
+ vertical-align: middle;
+}
+
+</style>
+
+<title> Twitter Client Demo (using <abbr> XSLT </abbr> and <abbr> HTML5 </abbr> </title>
+</head>
+
+<body>
+ <header>
+ <a id="profile_image">
+ <xsl:attribute name="href">http://twitter.com/<xsl:value-of select="screen_name"/></xsl:attribute>
+ <img width="50" height="50">
+ <xsl:attribute name="src"><xsl:value-of select="profile_image_url"/></xsl:attribute>
+ </img>
+ </a>
+
+ <h1 id="welcome"> Welcome <xsl:value-of select="name"/> </h1>
+
+ <div id="count"> You have <xsl:value-of select="friends_count"/> friends and <xsl:value-of select="followers_count"/> followers. </div>
+ </header>
+
+ <nav id="navigation">
+ <div>
+ <div class="navheader"> Messages </div>
+ <ul>
+ <li> <a href="#meAndMyFriendsStatus"> Me and My friends </a> </li>
+ <li> <a href="#myStatus"> Me </a> </li>
+ <li> <a href="#publicStatus"> Everyone </a> </li>
+ </ul>
+ </div>
+ <div> <div class="navheader"> Friends </div> <div id="friends"> Loading... </div> </div>
+ <div> <div class="navheader"> Followers </div> <div id="followers"> Loading... </div> </div>
+ </nav>
+
+ <section>
+ <div id="central"><h3>Loading...</h3>Please wait...</div>
+ </section>
+
+ <footer> Twitter Client Demo (using <abbr> XSLT </abbr> and <abbr> HTML5 </abbr>) </footer>
+</body>
+
+<script>
+ function setCentralHtml(html, title) {
+ html = '<h3> ' + title + ' </h3>' + html;
+ document.getElementById('central').innerHTML = html;
+ }
+
+ function setFriendsHtml(html) {
+ var friends = document.getElementById('friends');
+ friends.innerHTML = html;
+ }
+
+ function setFollowersHtml(html) {
+ var followers = document.getElementById('followers');
+ followers.innerHTML = html;
+ }
+
+</script>
+</html>
+
+</xsl:template>
+</xsl:stylesheet>
diff --git a/twitterview/twitter.cpp b/twitterview/twitter.cpp
new file mode 100644
index 0000000..5b2d5fb
--- /dev/null
+++ b/twitterview/twitter.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtWebKit>
+#include <QtNetwork>
+#include <QtGui>
+#include <QtXmlPatterns>
+
+#include "twitter.h"
+
+const QUrl Twitter::LOGIN_URL("http://twitter.com/account/verify_credentials.xml");
+const QUrl Twitter::GET_FRIENDS_URL("http://twitter.com/statuses/friends.xml");
+const QUrl Twitter::GET_FOLLOWERS_URL("http://twitter.com/statuses/followers.xml");
+const QUrl Twitter::GET_PUBLIC_STATUS_URL("http://twitter.com/statuses/public_timeline.xml");
+const QUrl Twitter::GET_FRIENDS_STATUS_URL("http://twitter.com/statuses/friends_timeline.xml"); // same as /home
+const QUrl Twitter::GET_MY_STATUS_URL("http://twitter.com/statuses/user_timeline.xml");
+const QString Twitter::GET_USER_STATUS_URL("http://twitter.com/statuses/user_timeline/%1.xml");
+const QUrl Twitter::UPDATE_STATUS_URL("http://twitter.com/statuses/update.xml");
+
+Twitter::Twitter(QObject *parent)
+ : QObject(parent)
+{
+ m_nam = new QNetworkAccessManager(this);
+ connect(m_nam, SIGNAL(finished(QNetworkReply *)), this, SIGNAL(finished(QNetworkReply *)));
+}
+
+Twitter::~Twitter()
+{
+}
+
+QString Twitter::userName() const
+{
+ return m_userName;
+}
+
+void Twitter::setUserName(const QString &userName)
+{
+ m_userName = userName;
+}
+
+QString Twitter::password() const
+{
+ return m_password;
+}
+
+void Twitter::setPassword(const QString &password)
+{
+ m_password = password;
+}
+
+void Twitter::applyCredentials(QNetworkRequest *request)
+{
+ QString userpass = QString("%1:%2").arg(m_userName).arg(m_password);
+ QByteArray auth("Basic " + userpass.toUtf8().toBase64());
+ request->setRawHeader("Authorization", auth);
+}
+
+QNetworkReply *Twitter::get(const QUrl &url, const QString &requestType)
+{
+ QNetworkRequest request(url);
+ applyCredentials(&request);
+ QNetworkReply *reply = m_nam->get(request);
+ reply->setProperty("requestType", requestType);
+ connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));
+ return reply;
+}
+
+QByteArray Twitter::credentialsXml() const
+{
+ return m_credentialsXml;
+}
+
+void Twitter::verifyCredentials()
+{
+ connect(get(LOGIN_URL, "login"), SIGNAL(finished()), this, SLOT(handleLoginReply()));
+}
+
+void Twitter::handleLoginReply()
+{
+ QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
+ m_credentialsXml = reply->readAll();
+ QString error;
+ if (!m_credentialsXml.isEmpty()) {
+ QBuffer buffer(&m_credentialsXml);
+ buffer.open(QIODevice::ReadOnly);
+
+ QXmlQuery query;
+ query.setFocus(&buffer);
+ query.setQuery("data(/hash/error)");
+ QString error;
+ query.evaluateTo(&error);
+ } else {
+ error = reply->errorString();
+ }
+ emit credentialsVerified(reply->error() == QNetworkReply::NoError, error);
+}
+
+QNetworkReply *Twitter::getFriends()
+{
+ return get(GET_FRIENDS_URL, "getFriends");
+}
+
+QNetworkReply *Twitter::getFollowers()
+{
+ return get(GET_FOLLOWERS_URL, "getFollowers");
+}
+
+QNetworkReply *Twitter::getPublicStatus()
+{
+ return get(GET_PUBLIC_STATUS_URL, "getPublicStatus");
+}
+
+QNetworkReply *Twitter::getFriendsStatus()
+{
+ return get(GET_FRIENDS_STATUS_URL, "getFriendsStatus");
+}
+
+QNetworkReply *Twitter::getMyStatus()
+{
+ return get(GET_MY_STATUS_URL, "getMyStatus");
+}
+
+QNetworkReply *Twitter::getUserStatus(const QString &id)
+{
+ return get(QUrl(GET_USER_STATUS_URL.arg(id)), "getUserStatus_" + id);
+}
+
+QNetworkReply *Twitter::setStatus(const QString &status)
+{
+ QNetworkRequest request(UPDATE_STATUS_URL);
+ applyCredentials(&request);
+ QNetworkReply *reply = m_nam->post(request, QByteArray("status=" + QUrl::toPercentEncoding(status.left(140))));
+ reply->setProperty("requestType", "setStatus");
+ return reply;
+}
+
diff --git a/twitterview/twitter.h b/twitterview/twitter.h
new file mode 100644
index 0000000..059b253
--- /dev/null
+++ b/twitterview/twitter.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef TWITTER_H
+#define TWITTER_H
+
+#include <QObject>
+#include <QUrl>
+
+class QNetworkAccessManager;
+class QNetworkReply;
+class QNetworkRequest;
+
+class Twitter : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString userName READ userName WRITE setUserName)
+ Q_PROPERTY(QString password READ password WRITE setPassword)
+
+public:
+ Twitter(QObject *parent = 0);
+ ~Twitter();
+
+ static const QUrl LOGIN_URL;
+ static const QUrl GET_FRIENDS_URL;
+ static const QUrl GET_FOLLOWERS_URL;
+ static const QUrl GET_PUBLIC_STATUS_URL;
+ static const QUrl GET_FRIENDS_STATUS_URL;
+ static const QUrl GET_MY_STATUS_URL;
+ static const QUrl UPDATE_STATUS_URL;
+ static const QString GET_USER_STATUS_URL;
+
+ QString userName() const;
+ void setUserName(const QString &userName);
+
+ QString password() const;
+ void setPassword(const QString &password);
+
+ QByteArray credentialsXml() const;
+
+public slots:
+ void verifyCredentials();
+ QNetworkReply *getFriends();
+ QNetworkReply *getFollowers();
+ QNetworkReply *getPublicStatus();
+ QNetworkReply *getFriendsStatus();
+ QNetworkReply *getMyStatus();
+ QNetworkReply *getUserStatus(const QString &userId);
+
+ QNetworkReply *setStatus(const QString &userId);
+
+signals:
+ void credentialsVerified(bool success, const QString &message);
+ void finished(QNetworkReply *reply);
+
+private slots:
+ void handleLoginReply();
+
+private:
+ QNetworkReply *get(const QUrl &url, const QString &requestType);
+ void applyCredentials(QNetworkRequest *request);
+
+ QNetworkAccessManager *m_nam;
+ QString m_userName;
+ QString m_password;
+ QByteArray m_credentialsXml;
+};
+
+#endif // TWITTER_H
+
diff --git a/twitterview/twitter.html b/twitterview/twitter.html
new file mode 100644
index 0000000..1f2df27
--- /dev/null
+++ b/twitterview/twitter.html
@@ -0,0 +1,37 @@
+<html>
+<head>
+<style>
+ #header_div {
+ background: red;
+ }
+
+ #left_pane_div {
+ background: green;
+ float: left;
+ width: 20%
+ }
+
+ #central_div {
+ background: blue;
+ }
+</style>
+
+<script>
+ function init() {
+ var html = twitter.transform(twitter.credentialsXml(), "credentials.xsl");
+ }
+</script>
+</head>
+
+<body onload="init()">
+ <div id="header_div"> This is the header </div>
+
+ <div>
+ <div id="left_pane_div"> This is the left pane </div>
+
+ <div id="central_div"> This is the central widget </div>
+ </div>
+
+</body>
+
+</html>
diff --git a/twitterview/twitterview.cpp b/twitterview/twitterview.cpp
new file mode 100644
index 0000000..ef474c1
--- /dev/null
+++ b/twitterview/twitterview.cpp
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtGui>
+#include <QtWebKit>
+#include <QtXmlPatterns>
+
+#include "twitterview.h"
+#include "twitter.h"
+
+TwitterView::TwitterView(Twitter *twitter, QWidget *parent)
+ : QWebView(parent),
+ m_twitter(twitter)
+{
+ connect(page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
+ this, SLOT(registerObjects()));
+
+ page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
+ connect(page(), SIGNAL(linkClicked(QUrl)), this, SLOT(handleLinkClicked(QUrl)));
+
+ connect(m_twitter, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleReply(QNetworkReply *)));
+
+ showTwitter();
+}
+
+TwitterView::~TwitterView()
+{
+}
+
+void TwitterView::showTwitter()
+{
+ QXmlQuery query(QXmlQuery::XSLT20);
+ QByteArray ba(m_twitter->credentialsXml());
+ QBuffer xml(&ba);
+ xml.open(QIODevice::ReadOnly);
+ query.setFocus(&xml);
+ query.setQuery(QUrl("qrc:transforms/twitterview.xsl"));
+
+ QByteArray html;
+ QBuffer buffer(&html);
+ buffer.open(QIODevice::WriteOnly);
+ query.evaluateTo(&buffer);
+ buffer.close();
+
+ setHtml(html);
+
+ m_twitter->getFriendsStatus();
+ m_twitter->getFriends();
+ m_twitter->getFollowers();
+}
+
+void TwitterView::setStatus(const QString &status)
+{
+ connect(m_twitter->setStatus(status), SIGNAL(finished()), m_twitter, SLOT(getFriendsStatus()));
+}
+
+void TwitterView::registerObjects()
+{
+ page()->mainFrame()->addToJavaScriptWindowObject("twitter", m_twitter);
+ page()->mainFrame()->addToJavaScriptWindowObject("view", this);
+}
+
+void TwitterView::handleLinkClicked(const QUrl &url)
+{
+ QString anchor = QString::fromLatin1(url.encodedFragment());
+ if (anchor == "meAndMyFriendsStatus") {
+ m_twitter->getFriendsStatus();
+ } else if (anchor == "myStatus") {
+ m_twitter->getMyStatus();
+ } else if (anchor == "publicStatus") {
+ m_twitter->getPublicStatus();
+ } else if (anchor.startsWith("friend_")) {
+ m_twitter->getUserStatus(anchor.mid(7));
+ } else if (anchor.startsWith("follower_")) {
+ m_twitter->getUserStatus(anchor.mid(9));
+ } else if (url.toString().startsWith("http://")) {
+ QDesktopServices::openUrl(url);
+ }
+
+ page()->mainFrame()->evaluateJavaScript("setCentralHtml('Please wait...', 'Loading...')");
+}
+
+static QString jsEscape(const QString &str, bool escapeSingleQuote = true)
+{
+ QString string = str;
+
+ string.replace('\\', "\\\\");
+ if (escapeSingleQuote) {
+ string.replace('\'', "\\\'");
+ } else {
+ string.replace('"', "\\\"");
+ }
+ string.replace('\t', "\\t");
+ string.replace('\f', "\\f");
+ string.replace('\r', "\\r");
+ string.replace('\b', "\\b");
+ string.replace('\n', "\\n");
+
+ return string;
+}
+
+void TwitterView::handleReply(QNetworkReply *reply)
+{
+ const QString requestType = reply->property("requestType").toString();
+
+ QString html;
+ QByteArray response(reply->readAll());
+ QBuffer xml(&response);
+ xml.open(QIODevice::ReadOnly);
+
+ if (reply->error() != QNetworkReply::NoError) {
+ QXmlQuery query;
+ query.setFocus(&xml);
+ query.setQuery("data(/hash/error)");
+ QString error;
+ query.evaluateTo(&error);
+ html = QString("Error. Request:%1- NetworkError:%2 ServerError:%3")
+ .arg(requestType).arg(reply->errorString()).arg(error.trimmed()).toUtf8();
+ } else {
+ QXmlQuery query(QXmlQuery::XSLT20);
+ query.setFocus(&xml);
+ QUrl input;
+ if (requestType == "getMyStatus") {
+ input = QUrl("qrc:transforms/singleuser.xsl");
+ } else if (requestType == "getPublicStatus") {
+ input = QUrl("qrc:transforms/public.xsl");
+ } else if (requestType == "getFriends") {
+ input = QUrl("qrc:transforms/friends.xsl");
+ } else if (requestType == "getFollowers") {
+ input = QUrl("qrc:transforms/followers.xsl");
+ } else if (requestType == "getFriendsStatus") {
+ input = QUrl("qrc:transforms/multiuser.xsl");
+ } else if (requestType.startsWith("getUserStatus_")) {
+ input = QUrl("qrc:transforms/singleuser.xsl");
+ }
+ query.setQuery(input);
+
+ QByteArray ba;
+ QBuffer buffer(&ba);
+ buffer.open(QIODevice::WriteOnly);
+ query.evaluateTo(&buffer);
+ buffer.close();
+ html = QString::fromUtf8(ba);
+ }
+
+ html = jsEscape(html);
+
+ if (requestType == "getMyStatus") {
+ page()->mainFrame()->evaluateJavaScript("setCentralHtml('" + html + "', 'Messages from Me')");
+ } else if (requestType == "getPublicStatus") {
+ page()->mainFrame()->evaluateJavaScript("setCentralHtml('" + html + "', 'Messages from Everyone')");
+ } else if (requestType == "getFriends") {
+ page()->mainFrame()->evaluateJavaScript("setFriendsHtml('" + html + "')");
+ } else if (requestType == "getFollowers") {
+ page()->mainFrame()->evaluateJavaScript("setFollowersHtml('" + html + "')");
+ } else if (requestType == "getFriendsStatus") {
+ page()->mainFrame()->evaluateJavaScript("setCentralHtml('" + html + "', 'Messages from Me and My Friends')");
+ } else if (requestType.startsWith("getUserStatus_")) {
+ QString user = requestType.mid(14);
+ page()->mainFrame()->evaluateJavaScript("setCentralHtml(\'" + html + "', '" + user + "')");
+ }
+}
+
diff --git a/twitterview/twitterview.h b/twitterview/twitterview.h
new file mode 100644
index 0000000..8ed6f64
--- /dev/null
+++ b/twitterview/twitterview.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef TWITTERVIEW_H
+#define TWITTERVIEW_H
+
+#include <QWebView>
+
+class Twitter;
+
+class TwitterView : public QWebView
+{
+ Q_OBJECT
+
+public:
+ TwitterView(Twitter *twitter, QWidget *parent = 0);
+ ~TwitterView();
+
+public slots:
+ void setStatus(const QString &status);
+
+private slots:
+ void registerObjects();
+ void showTwitter();
+ void handleLinkClicked(const QUrl &url);
+
+ void handleReply(QNetworkReply *reply);
+
+private:
+ Twitter *m_twitter;
+};
+
+#endif // TWITTERVIEW_H
diff --git a/twitterview/twitterview.pro b/twitterview/twitterview.pro
new file mode 100644
index 0000000..95ae8a1
--- /dev/null
+++ b/twitterview/twitterview.pro
@@ -0,0 +1,19 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+MOC_DIR = build
+OBJECTS_DIR = build
+RCC_DIR = build
+UI_DIR = build
+
+# Input
+HEADERS += twitter.h twitterview.h mainwindow.h
+SOURCES += main.cpp twitter.cpp twitterview.cpp mainwindow.cpp
+
+FORMS += mainwindow.ui
+
+RESOURCES += twitterview.qrc
+
+QT += webkit network xmlpatterns
diff --git a/twitterview/twitterview.qrc b/twitterview/twitterview.qrc
new file mode 100644
index 0000000..6d48bce
--- /dev/null
+++ b/twitterview/twitterview.qrc
@@ -0,0 +1,13 @@
+<RCC>
+ <qresource prefix="/">
+ <file>images/loading.gif</file>
+
+ <file>transforms/followers.xsl</file>
+ <file>transforms/friends.xsl</file>
+ <file>transforms/twitterview.xsl</file>
+ <file>transforms/singleuser.xsl</file>
+ <file>transforms/multiuser.xsl</file>
+ <file>transforms/public.xsl</file>
+
+ </qresource>
+</RCC>
diff --git a/videofeed/.DS_Store b/videofeed/.DS_Store
new file mode 100644
index 0000000..7cbac50
--- /dev/null
+++ b/videofeed/.DS_Store
Binary files differ
diff --git a/videofeed/README b/videofeed/README
new file mode 100644
index 0000000..a0871bc
--- /dev/null
+++ b/videofeed/README
@@ -0,0 +1,17 @@
+VideoFeed displays videos from user customizable feeds.
+
+Various video websites like YouTube, Google Videos, TED provide
+the list of videos as RSS, Atom. The demo extracts contents from the
+RSS using XQuery. The list of feeds and the XQuery used to extract
+contents is read in dynamically through configuration files.
+
+The demonstration makes use of the following features of Qt/WebKit
+new in Qt 4.5
+1. Ability to display NPAPI plugins. The videos displayed are currently
+flash content.
+2. Animations and transitions - Animations of the title, description,
+history buttons is carried out using WebKit's CSS animation.
+3. Offline Storage - WebKit implements offline storage feature of HTML5.
+The demo remembers the list of videos watched by user across executions
+and saves/restores it using HTML5 Offline Storage feature.
+
diff --git a/videofeed/html/json2.js b/videofeed/html/json2.js
new file mode 100644
index 0000000..241a271
--- /dev/null
+++ b/videofeed/html/json2.js
@@ -0,0 +1,478 @@
+/*
+ http://www.JSON.org/json2.js
+ 2008-11-19
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the object holding the key.
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+*/
+
+/*jslint evil: true */
+
+/*global JSON */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+*/
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (!this.JSON) {
+ JSON = {};
+}
+(function () {
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ?
+ '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+})();
diff --git a/videofeed/html/loading.gif b/videofeed/html/loading.gif
new file mode 100644
index 0000000..c1545eb
--- /dev/null
+++ b/videofeed/html/loading.gif
Binary files differ
diff --git a/videofeed/html/next.png b/videofeed/html/next.png
new file mode 100644
index 0000000..6d98f50
--- /dev/null
+++ b/videofeed/html/next.png
Binary files differ
diff --git a/videofeed/html/prev.png b/videofeed/html/prev.png
new file mode 100644
index 0000000..37ba0c4
--- /dev/null
+++ b/videofeed/html/prev.png
Binary files differ
diff --git a/videofeed/html/settings.js b/videofeed/html/settings.js
new file mode 100644
index 0000000..1434e82
--- /dev/null
+++ b/videofeed/html/settings.js
@@ -0,0 +1,102 @@
+/** This file is part of VideoFeed**
+ *
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
+ *
+ * Contact: Qt Software Information (qt-info@nokia.com)**
+ *
+ * Commercial Usage
+ * Licensees holding valid Qt Commercial licenses may use this file in
+ * accordance with the Qt Commercial License Agreement provided with the
+ * Software or, alternatively, in accordance with the terms contained in
+ * a written agreement between you and Nokia.
+ *
+ * GNU Lesser General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU Lesser General Public License version 2.1 only as published by the
+ * Free Software Foundation and appearing in the file LICENSE.LGPL included
+ * in the packaging of this file. Please review the following information
+ * to ensure the GNU Lesser General Public License version 2.1 requirements
+ * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * GNU General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU General Public License version 3.0 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file. Please review the following information to ensure
+ * the GNU General Public License version 3.0 requirements will be
+ * met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * If you are unsure which license is appropriate for your use, please contact
+ * the sales department at qt-sales@nokia.com.
+ */
+
+function Settings(name) {
+ this.data = [];
+ this.db = openDatabase(name, "1.0", name + " Settings", 200000);
+ this.db.transaction(function (tx) {
+ tx.executeSql("CREATE TABLE IF NOT EXISTS Settings(key TEXT UNIQUE, value TEXT)", []);
+ });
+ var self = this;
+ this.db.transaction(function (tx) {
+ tx.executeSql("SELECT key, value FROM Settings", [],
+ function(tx, result) { self.processResult(tx, result); },
+ function() { self.readError(tx, error); });
+ });
+
+ return this;
+}
+
+Settings.prototype = {
+ onready : function(data) {
+ },
+
+ processResult : function(tx, result) {
+ this.data = [];
+ for (var i = 0; i < result.rows.length; i++) {
+ var row = result.rows.item(i);
+ this.data[row['key']] = row['value'];
+ }
+ this.onready(this.data);
+ },
+
+ readError : function(tx, error) {
+ alert('Failed to read database : ' + error.message);
+ }
+};
+
+Settings.prototype.value = function(key) {
+ return this.data[key];
+}
+
+Settings.prototype.setValue = function(key, value) {
+ this.data[key] = value;
+}
+
+Settings.prototype.remove = function(key) {
+ delete this.data[key];
+}
+
+Settings.prototype.removeAll = function() {
+ this.data = [];
+}
+
+Settings.prototype.clearDatabase = function() {
+ this.db.transaction(function (tx) {
+ tx.executeSql("DELETE FROM Settings", []);
+ });
+}
+
+Settings.prototype.insert = function(key, value) {
+ alert(key + ' ' + value);
+}
+
+Settings.prototype.commit = function() {
+ this.clearDatabase();
+ var self = this;
+
+ this.db.transaction(function (tx) {
+ for (var key in self.data)
+ tx.executeSql("INSERT INTO Settings (key, value) VALUES (?, ?)", [key, self.data[key]]);
+ });
+}
+
diff --git a/videofeed/html/videoplayer.html b/videofeed/html/videoplayer.html
new file mode 100644
index 0000000..fcf7414
--- /dev/null
+++ b/videofeed/html/videoplayer.html
@@ -0,0 +1,336 @@
+<!--
+/** This file is part of VideoFeed**
+ *
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
+ *
+ * Contact: Qt Software Information (qt-info@nokia.com)**
+ *
+ * Commercial Usage
+ * Licensees holding valid Qt Commercial licenses may use this file in
+ * accordance with the Qt Commercial License Agreement provided with the
+ * Software or, alternatively, in accordance with the terms contained in
+ * a written agreement between you and Nokia.
+ *
+ * GNU Lesser General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU Lesser General Public License version 2.1 only as published by the
+ * Free Software Foundation and appearing in the file LICENSE.LGPL included
+ * in the packaging of this file. Please review the following information
+ * to ensure the GNU Lesser General Public License version 2.1 requirements
+ * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * GNU General Public License Usage
+ * Alternatively, this file may be used under the terms of the
+ * GNU General Public License version 3.0 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file. Please review the following information to ensure
+ * the GNU General Public License version 3.0 requirements will be
+ * met: http://www.gnu.org/copyleft/gpl.html.
+ *
+ * If you are unsure which license is appropriate for your use, please contact
+ * the sales department at qt-sales@nokia.com.
+ */
+!-->
+
+<html>
+<head>
+<style>
+ body {
+ background-color: #ffffea;
+ margin: 0px;
+ border: 2px solid #B0C4DE;
+ padding: 3px;
+ }
+
+ #central_widget > * { display: none; }
+
+ #loading {
+ text-align: center;
+ }
+
+ #title {
+ text-align: center;
+ font-size: 14pt;
+ font-weight: bold;
+ color: #800000;
+
+ /* ideally, this is relative and we just float the navbar, but floating
+ breaks animations for some reason. */
+ position: absolute;
+ top: 10;
+ left: 30%;
+ }
+
+ #description {
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ }
+
+ #author, #publisheddate, #duration {
+ display: none;
+ }
+
+ .centered {
+ position: absolute;
+ top: 25%;
+ left: 25%;
+ width: 50%;
+ height: 50%;
+ }
+
+
+ #nextButton, #prevButton {
+ border: none;
+ background-repeat: no-repeat;
+ background-position: top left;
+ width: 32px;
+ height: 32px;
+ opacity: 0.5;
+
+ -webkit-transition-property: opacity;
+ -webkit-transition-duration: 0.5s;
+ -webkit-transition-timing-function: linear;
+ }
+
+ #nextButton { background: url(next.png); }
+ #prevButton { background: url(prev.png); }
+
+ #nextButton:hover, #prevButton:hover {
+ opacity: 1.0;
+ }
+
+ #nextButton:disabled, #prevButton:disabled {
+ opacity: 0.1;
+ }
+
+ #clearButton {
+ display: none;
+ }
+
+ /* example of how we can do opacity animation using keyframes */
+ @-webkit-keyframes 'diagonal-slide' {
+ from {
+ opacity: 1;
+ -webkit-animation-timing-function: linear;
+ }
+
+ 50% { opacity: 0.2 }
+ to { opacity: 1; }
+ }
+
+ #loading {
+ -webkit-animation-name: 'diagonal-slide';
+ -webkit-animation-duration: 1s;
+ -webkit-animation-iteration-count: infinite;
+ position: relative;
+ }
+</style>
+<script type="text/javascript" src="json2.js"></script>
+<script type="text/javascript" src="settings.js"></script>
+<script>
+ function setCentralDiv(divId) {
+ var cw = document.getElementById('central_widget');
+ var children = cw.children;
+ for (var i = 0; i < children.length; i++) {
+ if (children[i].id == undefined)
+ continue;
+ if (children[i].id == divId) {
+ children[i].style.display = 'block';
+ } else {
+ children[i].style.display = 'none';
+ }
+ }
+ }
+
+ function showWelcome() {
+ setCentralDiv('welcome');
+ }
+
+ function showLoading(preloadDesc) {
+ hideTitle(1);
+ hideDescription(1);
+ setTimeout(function() {
+ document.getElementById('description').innerHTML = preloadDesc;
+ }, 600);
+ document.getElementById('embed-video-here').innerHTML = '';
+ document.getElementById('loading').style.display = 'block';
+ }
+
+ function showLoadError() {
+ setCentralDiv('loadError');
+ }
+
+ function hideTitle(secs) {
+ var title = document.getElementById('title');
+ title.style.webkitTransition = 'top ' + secs + 's ease-in';
+ title.style.top = "-100px";
+ }
+
+ function showTitle(text, secs) {
+ var title = document.getElementById('title');
+ title.innerHTML = text;
+ title.style.webkitTransition = 'top ' + secs + 's ease-in';
+ title.style.top = "10px";
+ }
+
+ function showDescription(text, secs) {
+ var desc = document.getElementById('description');
+ if (desc.innerHTML != text)
+ desc.innerHTML = text;
+ desc.style.webkitTransition = '-webkit-transform ' + secs + 's ease-in, opacity ' + secs + 's ease-in';
+ desc.style.webkitTransformOrigin = desc.offsetWidth/2 + " " + desc.offsetHeight/2;
+ desc.style.webkitTransform = 'skew(0deg, 0deg) scale(1)';
+ desc.style.opacity = '1';
+ }
+
+ function hideDescription(secs) {
+ var desc = document.getElementById('description');
+ desc.style.webkitTransition = '-webkit-transform ' + secs + 's ease-in, opacity ' + secs + 's ease-in';
+ desc.style.webkitTransformOrigin = desc.offsetWidth/2 + " " + desc.offsetHeight/2;
+ desc.style.webkitTransform = 'skew(0deg, 0deg) scale(0)';
+ desc.style.opacity = '0';
+ }
+
+ function showVideo(video) {
+ document.getElementById('loading').style.display = 'none';
+ hideTitle(0.5);
+ hideDescription(0.5);
+ setTimeout(function() {
+ setCentralDiv('videoPlayer');
+ showTitle(video.title, 0.5);
+ showDescription(video.description, 0.5);
+ document.getElementById('author').innerHTML = video.author;
+ document.getElementById('duration').innerHTML = video.duration;
+ document.getElementById('publisheddate').innerHTML = video.publishedDate;
+ document.getElementById('embed-video-here').innerHTML = video.html;
+ }, 510);
+ }
+
+ var settings = null;
+ var videoHistory = [];
+ var curIndex = -1;
+ var nextButton = null, prevButton = null, clearButon = null;
+
+ function addVideo(title, author, desc, pubDate, duration, html) {
+ videoHistory.length = curIndex + 1;
+ var video = {
+ 'title': title,
+ 'author': author,
+ 'description': desc,
+ 'publishedDate': pubDate,
+ 'duration': duration,
+ 'html': html
+ };
+ videoHistory.push(video);
+ ++curIndex;
+ showVideo(video);
+ updateButtons();
+ checkpoint();
+ }
+
+ function setCurrentVideo(index) {
+ if (index >= 0 && index < videoHistory.length) {
+ curIndex = index;
+ showVideo(videoHistory[curIndex]);
+ }
+ updateButtons();
+ checkpoint();
+ }
+
+ function previousVideo() {
+ setCurrentVideo(curIndex - 1);
+ }
+
+ function nextVideo() {
+ setCurrentVideo(curIndex + 1);
+ }
+
+ function clearHistory() {
+ videoHistory = [];
+ curIndex = -1;
+ updateButtons();
+ checkpoint();
+ }
+
+ function updateButtons() {
+ clearButton.disabled = (videoHistory.length == 0);
+ prevButton.disabled = (curIndex <= 0);
+ nextButton.disabled = (videoHistory.length-1 == curIndex);
+ }
+
+ function checkpoint() {
+ settings.removeAll();
+ settings.setValue('historySize', videoHistory.length);
+ for (var i = 0; i < videoHistory.length; i++) {
+ settings.setValue('video' + i, JSON.stringify(videoHistory[i]));
+ }
+ settings.setValue('curIndex', curIndex);
+ settings.commit();
+ }
+
+ function restoreHistory(data) {
+ if (data['curIndex'] != undefined)
+ curIndex = parseInt(data['curIndex']);
+ var historySize = 0;
+ if (data['historySize'] != undefined)
+ historySize = parseInt(data['historySize']);
+
+ for (var i = 0; i < historySize; i++) {
+ videoHistory[i] = JSON.parse(data['video'+i]);
+ }
+
+ setCurrentVideo(curIndex);
+ }
+
+ function onLoad() {
+ showWelcome();
+ prevButton = document.getElementById('prevButton');
+ nextButton = document.getElementById('nextButton');
+ clearButton = document.getElementById('clearButton');
+ settings = new Settings("Video Feed");
+ settings.onready = restoreHistory;
+ }
+</script>
+</head>
+
+<body onload="onLoad()">
+
+ <div id="navbar">
+ <input type="button" id="prevButton" value="" onclick="previousVideo()"/>
+ <input type="button" id="nextButton" value="" onclick="nextVideo()"/>
+ <input type="button" id="clearButton" value="Clear" onclick="clearHistory()"/>
+ </div>
+
+ <div id="title"></div>
+
+ <div id="central_widget" style="margin-top: 15px">
+ <h2 id="welcome" class="centered"> Activate any video to your left to play it. You can choose a different feed from the 'Feed' menu. </h2> <h2 id="loadError" class="centered"> Something bad happened, enjoy the animation instead...</h2>
+
+ <div id="videoPlayer">
+ <table align="center" cellspacing=10 cellpadding=5>
+ <tr>
+ <td>
+ <div id="description"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div id="embed-video-here"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <h2 id="loading"> Loading video, please wait... </h2>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+
+ <div id="author"></div>
+ <div id="publisheddate"></div>
+ <div id="duration"></div>
+</body>
+
+</html>
diff --git a/videofeed/main.cpp b/videofeed/main.cpp
new file mode 100644
index 0000000..04de3ca
--- /dev/null
+++ b/videofeed/main.cpp
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtGui>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ MainWindow w;
+ w.resize(750, 550);
+ w.show();
+
+ return a.exec();
+}
+
diff --git a/videofeed/mainwindow.cpp b/videofeed/mainwindow.cpp
new file mode 100644
index 0000000..b59fe6f
--- /dev/null
+++ b/videofeed/mainwindow.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include <QtGui>
+#include <QtNetwork>
+#include <QtWebKit>
+#include <QtXmlPatterns>
+
+#include "mainwindow.h"
+
+MainWindow::MainWindow(QWidget *parent, Qt::WFlags flags)
+ : QMainWindow(parent, flags), m_view(0)
+{
+ statusBar()->showMessage(tr("Ready"));
+
+ ui.setupUi(this);
+ connect(ui.action_Quit, SIGNAL(triggered()), qApp, SLOT(quit()));
+ connect(ui.action_About, SIGNAL(triggered()), this, SLOT(about()));
+ connect(ui.actionAbout_Qt, SIGNAL(triggered()), this, SLOT(aboutQt()));
+
+ QWebSettings *defaultSettings = QWebSettings::globalSettings();
+ defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, true);
+ defaultSettings->setAttribute(QWebSettings::PluginsEnabled, true);
+ QWebSettings::setOfflineStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
+ QWebSettings::setOfflineStorageDefaultQuota(500000);
+
+ m_rssModel = new QStandardItemModel(this);
+
+ populateFeedsMenu();
+ m_feedGroup->actions().last()->setChecked(true);
+ QTimer::singleShot(0, this, SLOT(changeFeed()));
+
+ m_view = new QWebView(this);
+ m_view->move(-1000, -1000);
+
+ ui.webView->page()->mainFrame()->load(QUrl("qrc:/html/videoplayer.html"));
+
+ QSortFilterProxyModel *filterModel = new QSortFilterProxyModel(this);
+ filterModel->setSourceModel(m_rssModel);
+ filterModel->setDynamicSortFilter(true);
+ filterModel->setFilterRole(SearchRole);
+ filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ filterModel->setFilterKeyColumn(0);
+ connect(ui.searchEdit, SIGNAL(textChanged(QString)), filterModel, SLOT(setFilterFixedString(QString)));
+
+ ui.treeView->setModel(filterModel);
+ ui.treeView->header()->hide();
+ connect(ui.treeView, SIGNAL(activated(QModelIndex)), this, SLOT(loadVideo(QModelIndex)));
+
+ QShortcut *clearHistoryShortcut = new QShortcut(QKeySequence(tr("Ctrl+Alt+X", "Clear history")), this);
+ connect(clearHistoryShortcut, SIGNAL(activated()), this, SLOT(clearHistory()));
+}
+
+MainWindow::~MainWindow()
+{
+}
+
+void MainWindow::about()
+{
+ QMessageBox::about(this, tr("About %1").arg(windowTitle()),
+ tr("Demo of Qt/WebKit flash support"));
+}
+
+void MainWindow::aboutQt()
+{
+ QMessageBox::aboutQt(this);
+}
+
+void MainWindow::clearHistory()
+{
+ ui.webView->page()->mainFrame()->evaluateJavaScript("clearHistory()");
+ statusBar()->showMessage(tr("History cleared"));
+}
+
+void MainWindow::populateFeedsMenu()
+{
+ QDirIterator it(":/rss", QStringList("*.ini"));
+ m_feedGroup = new QActionGroup(this);
+ m_feedGroup->setExclusive(true);
+ while (it.hasNext()) {
+ QString fileName = it.next();
+ QSettings settings(fileName, QSettings::IniFormat);
+ QAction *action = new QAction(m_feedGroup);
+ action->setText(settings.value("feed/name").toString());
+ action->setCheckable(true);
+ FeedInfo fi;
+ fi.name = settings.value("feed/name").toString();
+ fi.uri = settings.value("feed/uri").toString();
+ fi.titleFilter = settings.value("feed/titleFilter").toString();
+ QFile query(it.path() + "/" + settings.value("feed/query").toString());
+ query.open(QFile::ReadOnly);
+ fi.query = query.readAll();
+ fi.embedDiv = settings.value("feed/embedDiv").toString();
+ QVariant variant;
+ variant.setValue<FeedInfo>(fi);
+ action->setData(variant);
+ m_feedGroup->addAction(action);
+ }
+ ui.menu_Feeds->addActions(m_feedGroup->actions());
+ connect(m_feedGroup, SIGNAL(triggered(QAction *)), this, SLOT(changeFeed()));
+}
+
+MainWindow::FeedInfo MainWindow::currentFeedInfo() const
+{
+ QAction *action = m_feedGroup->checkedAction();
+ return action->data().value<FeedInfo>();
+}
+
+void MainWindow::changeFeed()
+{
+ loadFeed(currentFeedInfo());
+}
+
+void MainWindow::loadFeed(const MainWindow::FeedInfo &fi)
+{
+ m_rssModel->clear();
+ QStandardItem *root = m_rssModel->invisibleRootItem();
+ QStandardItem *item = new QStandardItem(tr("Loading feed, please wait..."));
+ item->setFlags(Qt::NoItemFlags);
+ root->appendRow(item);
+
+ QXmlQuery query;
+ const QString uri = fi.uri.toString();
+ const QString DELIMITER = " %%QT_DEMO_DELIM%% ";
+ query.bindVariable("uri", QVariant(uri));
+ query.setQuery(fi.query);
+ QStringList result;
+ // ##: evaluteTo loads the URI with its own event loop. This means that we will
+ // hit some rescursion with signals/slots. We ignore such bugs in this example.
+ // To avoid it we will have to load the uro ourselves.
+ query.evaluateTo(&result);
+ statusBar()->showMessage(tr("Feed has %1 items").arg(result.count()));
+
+ m_rssModel->clear();
+ root = m_rssModel->invisibleRootItem();
+
+ for (int i = 0; i < result.size(); i++) {
+ QStandardItem *item = new QStandardItem;
+
+ QStringList arr = result.at(i).split(DELIMITER);
+ QString titleStr = arr.at(0);
+ titleStr.remove(QRegExp(fi.titleFilter));
+ item->setText(titleStr);
+
+ item->setData(arr.at(0), TitleRole);
+ item->setData(arr.at(1), AuthorRole);
+ item->setData(arr.at(2), DescriptionRole);
+ item->setData(arr.at(3), SubTitleRole);
+ item->setData(arr.at(4), PageLinkRole);
+ item->setData(arr.at(5), DownloadRole);
+ item->setData(arr.at(6), PublishedDateRole);
+ item->setData(arr.at(7), DurationRole);
+ item->setData(arr.at(0) + " " + arr.at(1) + " " + arr.at(2) + " " + arr.at(3), SearchRole);
+
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ root->appendRow(item);
+ }
+
+ setWindowTitle(tr("VideoFeed - %1").arg(fi.name));
+}
+
+static QString jsEscape(const QString &str, bool escapeSingleQuote = true)
+{
+ QString string = str;
+
+ string.replace('\\', "\\\\");
+ if (escapeSingleQuote) {
+ string.replace('\'', "\\\'");
+ } else {
+ string.replace('"', "\\\"");
+ }
+ string.replace('\t', "\\t");
+ string.replace('\f', "\\f");
+ string.replace('\r', "\\r");
+ string.replace('\b', "\\b");
+ string.replace('\n', "\\n");
+
+ return string;
+}
+
+void MainWindow::loadVideo(const QModelIndex &index)
+{
+ m_loadingIndex = index;
+ statusBar()->showMessage(tr("Loading video - %1").arg(index.data(TitleRole).toString()));
+ QString desc = index.data(DescriptionRole).toString();
+ ui.webView->page()->mainFrame()->evaluateJavaScript("showLoading('" + jsEscape(desc) + "')");
+ m_view->page()->mainFrame()->setUrl(QUrl(index.data(PageLinkRole).toString()));
+ disconnect(m_view, 0, this, 0);
+ connect(m_view, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
+}
+
+void MainWindow::loadFinished(bool ok)
+{
+ disconnect(m_view, 0, this, 0);
+
+ if (ok) {
+ statusBar()->showMessage(tr("Showing video"));
+ QString script = QString("document.getElementById('%1').innerHTML").arg(currentFeedInfo().embedDiv);
+ QString videoHtml = jsEscape(m_view->page()->mainFrame()->evaluateJavaScript(script).toString());
+ m_view->page()->mainFrame()->evaluateJavaScript("window.location.href='about:blank'");
+
+ QString title = jsEscape(m_loadingIndex.data(TitleRole).toString());
+ QString author = jsEscape(m_loadingIndex.data(AuthorRole).toString());
+ QString desc = jsEscape(m_loadingIndex.data(DescriptionRole).toString());
+ QString pubDate = jsEscape(m_loadingIndex.data(PublishedDateRole).toString());
+ QString duration = jsEscape(m_loadingIndex.data(DurationRole).toString());
+
+#if 0
+ qDebug() << title;
+ qDebug() << author;
+ qDebug() << desc;
+ qDebug() << pubDate;
+ qDebug() << duration;
+ qDebug() << videoHtml;
+#endif
+ ui.webView->page()->mainFrame()->evaluateJavaScript( // ###: pass JSON
+ QString("addVideo('%1', '%2', '%3', '%4', '%5', '%6')")
+ .arg(title)
+ .arg(author)
+ .arg(desc)
+ .arg(pubDate)
+ .arg(duration)
+ .arg(videoHtml)
+ );
+ } else {
+ statusBar()->showMessage(tr("Something bad happened"));
+ ui.webView->page()->mainFrame()->evaluateJavaScript("showLoadError()");
+ }
+}
+
diff --git a/videofeed/mainwindow.h b/videofeed/mainwindow.h
new file mode 100644
index 0000000..3ec5ce7
--- /dev/null
+++ b/videofeed/mainwindow.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Graphics Dojo project on Qt Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 or 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QStandardItemModel>
+#include <QActionGroup>
+
+#include "ui_mainwindow.h"
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = 0, Qt::WFlags flags = 0);
+ ~MainWindow();
+
+ struct FeedInfo {
+ QString name;
+ QUrl uri;
+ QString query;
+ QString embedDiv;
+ QString titleFilter;
+ };
+
+ FeedInfo currentFeedInfo() const;
+
+private slots:
+ void about();
+ void aboutQt();
+
+ void clearHistory();
+ void changeFeed();
+ void loadFinished(bool ok);
+ void loadVideo(const QModelIndex &index);
+
+private:
+ QActionGroup *m_feedGroup;
+ QModelIndex m_loadingIndex;
+
+ void populateFeedsMenu();
+ void loadFeed(const FeedInfo &fi) ;
+
+ Ui::MainWindow ui;
+ QWebView *m_view;
+ QStandardItemModel *m_rssModel;
+
+ enum {
+ TitleRole = Qt::UserRole + 1,
+ AuthorRole,
+ DescriptionRole,
+ SubTitleRole,
+ PageLinkRole,
+ DownloadRole,
+ PublishedDateRole,
+ DurationRole,
+ SearchRole
+ };
+};
+
+Q_DECLARE_METATYPE(MainWindow::FeedInfo);
+
+#endif // MAINWINDOW_H
+
diff --git a/videofeed/mainwindow.ui b/videofeed/mainwindow.ui
new file mode 100644
index 0000000..7a2b70e
--- /dev/null
+++ b/videofeed/mainwindow.ui
@@ -0,0 +1,147 @@
+<ui version="4.0" >
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>634</width>
+ <height>427</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>VideoFeed</string>
+ </property>
+ <widget class="QWidget" name="centralWidget" >
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QSplitter" name="splitter" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QWidget" name="layoutWidget" >
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>&amp;Search:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>searchEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="searchEdit" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QTreeView" name="treeView" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>250</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="cursor" stdset="0" >
+ <cursorShape>ArrowCursor</cursorShape>
+ </property>
+ <property name="alternatingRowColors" >
+ <bool>true</bool>
+ </property>
+ <property name="rootIsDecorated" >
+ <bool>false</bool>
+ </property>
+ <property name="itemsExpandable" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWebView" name="webView" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="url" >
+ <url>
+ <string>about:blank</string>
+ </url>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QStatusBar" name="statusBar" />
+ <widget class="QMenuBar" name="menuBar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>634</width>
+ <height>30</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menu_File" >
+ <property name="title" >
+ <string>&amp;File</string>
+ </property>
+ <addaction name="action_Quit" />
+ </widget>
+ <widget class="QMenu" name="menu_Help" >
+ <property name="title" >
+ <string>&amp;Help</string>
+ </property>
+ <addaction name="action_About" />
+ <addaction name="separator" />
+ <addaction name="actionAbout_Qt" />
+ </widget>
+ <widget class="QMenu" name="menu_Feeds" >
+ <property name="title" >
+ <string>&amp;Feeds</string>
+ </property>
+ </widget>
+ <addaction name="menu_File" />
+ <addaction name="menu_Feeds" />
+ <addaction name="menu_Help" />
+ </widget>
+ <action name="action_Quit" >
+ <property name="text" >
+ <string>&amp;Quit</string>
+ </property>
+ </action>
+ <action name="action_About" >
+ <property name="text" >
+ <string>&amp;About </string>
+ </property>
+ </action>
+ <action name="actionAbout_Qt" >
+ <property name="text" >
+ <string>About &amp;Qt</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <customwidgets>
+ <customwidget>
+ <class>QWebView</class>
+ <extends>QWidget</extends>
+ <header>QtWebKit/QWebView</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/videofeed/rss/ted.ini b/videofeed/rss/ted.ini
new file mode 100644
index 0000000..0cd52e5
--- /dev/null
+++ b/videofeed/rss/ted.ini
@@ -0,0 +1,6 @@
+[feed]
+name = TED Videos
+uri = http://www.ted.com/talks/rss
+query = ted.xq
+embedDiv = videoPlayerSwf
+titleFilter = ^TEDTalks\\s*:\\s*
diff --git a/videofeed/rss/ted.xq b/videofeed/rss/ted.xq
new file mode 100644
index 0000000..514c99a
--- /dev/null
+++ b/videofeed/rss/ted.xq
@@ -0,0 +1,12 @@
+declare namespace itunes="http://www.itunes.com/dtds/podcast-1.0.dtd";
+for $i in doc($uri)/rss/channel/item
+ return fn:string-join( (
+ $i/title/string(),
+ $i/itunes:author/string(),
+ $i/description/string(),
+ $i/itunes:subtitle/string(),
+ $i/link/string(),
+ $i/guid/string(),
+ $i/pubDate/string(),
+ $i/itunes:duration/string()
+ ), " %%QT_DEMO_DELIM%% ")
diff --git a/videofeed/rss/youtube.xq b/videofeed/rss/youtube.xq
new file mode 100644
index 0000000..9c14002
--- /dev/null
+++ b/videofeed/rss/youtube.xq
@@ -0,0 +1,11 @@
+for $i in doc($uri)/rss/channel/item
+ return fn:string-join( (
+ $i/title/string(),
+ "author",
+ $i/description/string(),
+ "subtitle",
+ $i/link/string(),
+ $i/guid/string(),
+ $i/pubDate/string(),
+ "duration"
+ ), " %%QT_DEMO_DELIM%% ")
diff --git a/videofeed/rss/youtube_qtstudios.ini b/videofeed/rss/youtube_qtstudios.ini
new file mode 100644
index 0000000..fa080e3
--- /dev/null
+++ b/videofeed/rss/youtube_qtstudios.ini
@@ -0,0 +1,5 @@
+[feed]
+name = YouTube - Qt Software
+uri = http://gdata.youtube.com/feeds/base/users/QtStudios/uploads?client=ytapi-youtube-browse&alt=rss
+query = youtube.xq
+embedDiv = watch-player-div
diff --git a/videofeed/rss/youtube_recently_added.ini b/videofeed/rss/youtube_recently_added.ini
new file mode 100644
index 0000000..0ad9818
--- /dev/null
+++ b/videofeed/rss/youtube_recently_added.ini
@@ -0,0 +1,5 @@
+[feed]
+name = YouTube Recently Added
+uri = http://gdata.youtube.com/feeds/base/standardfeeds/most_recent?client=ytapi-youtube-browse&alt=rss
+query = youtube.xq
+embedDiv = watch-player-div
diff --git a/videofeed/rss/youtube_recently_featured.ini b/videofeed/rss/youtube_recently_featured.ini
new file mode 100644
index 0000000..a22915e
--- /dev/null
+++ b/videofeed/rss/youtube_recently_featured.ini
@@ -0,0 +1,5 @@
+[feed]
+name = YouTube Recently Featured
+uri = http://gdata.youtube.com/feeds/base/standardfeeds/recently_featured?client=ytapi-youtube-browse&alt=rss
+query = youtube.xq
+embedDiv = watch-player-div
diff --git a/videofeed/rss/youtube_topfav.ini b/videofeed/rss/youtube_topfav.ini
new file mode 100644
index 0000000..46d08ab
--- /dev/null
+++ b/videofeed/rss/youtube_topfav.ini
@@ -0,0 +1,5 @@
+[feed]
+name = YouTube All Time Top Favorites
+uri = http://gdata.youtube.com/feeds/base/standardfeeds/top_favorites?client=ytapi-youtube-browse&alt=rss
+query = youtube.xq
+embedDiv = watch-player-div
diff --git a/videofeed/teddemo.qrc b/videofeed/teddemo.qrc
new file mode 100644
index 0000000..1bed7cf
--- /dev/null
+++ b/videofeed/teddemo.qrc
@@ -0,0 +1,19 @@
+<RCC>
+ <qresource prefix="/">
+ <file>html/videoplayer.html</file>
+ <file>html/settings.js</file>
+ <file>html/json2.js</file>
+
+ <file>html/loading.gif</file>
+ <file>html/next.png</file>
+ <file>html/prev.png</file>
+
+ <file>rss/ted.ini</file>
+ <file>rss/ted.xq</file>
+ <file>rss/youtube_topfav.ini</file>
+ <file>rss/youtube_recently_added.ini</file>
+ <file>rss/youtube_recently_featured.ini</file>
+ <file>rss/youtube_qtstudios.ini</file>
+ <file>rss/youtube.xq</file>
+ </qresource>
+</RCC>
diff --git a/videofeed/videofeed.pro b/videofeed/videofeed.pro
new file mode 100644
index 0000000..327154b
--- /dev/null
+++ b/videofeed/videofeed.pro
@@ -0,0 +1,14 @@
+QT += network webkit xml xmlpatterns
+
+TARGET = videofeed
+TEMPLATE = app
+
+
+SOURCES += main.cpp \
+ mainwindow.cpp
+
+HEADERS += mainwindow.h
+
+RESOURCES += teddemo.qrc
+
+FORMS += mainwindow.ui