|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the examples of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 /* |
|
43 rsslisting.cpp |
|
44 |
|
45 Provides a widget for displaying news items from RDF news sources. |
|
46 RDF is an XML-based format for storing items of information (see |
|
47 http://www.w3.org/RDF/ for details). |
|
48 |
|
49 The widget itself provides a simple user interface for specifying |
|
50 the URL of a news source, and controlling the downloading of news. |
|
51 |
|
52 The widget downloads and parses the XML asynchronously, feeding the |
|
53 data to an XML reader in pieces. This allows the user to interrupt |
|
54 its operation, and also allows very large data sources to be read. |
|
55 */ |
|
56 |
|
57 |
|
58 #include <QtCore> |
|
59 #include <QtGui> |
|
60 #include <QtNetwork> |
|
61 |
|
62 #include "rsslisting.h" |
|
63 |
|
64 |
|
65 /* |
|
66 Constructs an RSSListing widget with a simple user interface, and sets |
|
67 up the XML reader to use a custom handler class. |
|
68 |
|
69 The user interface consists of a line edit, two push buttons, and a |
|
70 list view widget. The line edit is used for entering the URLs of news |
|
71 sources; the push buttons start and abort the process of reading the |
|
72 news. |
|
73 */ |
|
74 |
|
75 RSSListing::RSSListing(QWidget *parent) |
|
76 : QWidget(parent) |
|
77 { |
|
78 lineEdit = new QLineEdit(this); |
|
79 lineEdit->setText("http://labs.qt.nokia.com/blogs/feed"); |
|
80 |
|
81 fetchButton = new QPushButton(tr("Fetch"), this); |
|
82 abortButton = new QPushButton(tr("Abort"), this); |
|
83 abortButton->setEnabled(false); |
|
84 |
|
85 treeWidget = new QTreeWidget(this); |
|
86 connect(treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*, int)), |
|
87 this, SLOT(itemActivated(QTreeWidgetItem*))); |
|
88 QStringList headerLabels; |
|
89 headerLabels << tr("Title") << tr("Link"); |
|
90 treeWidget->setHeaderLabels(headerLabels); |
|
91 treeWidget->header()->setResizeMode(QHeaderView::ResizeToContents); |
|
92 |
|
93 connect(&http, SIGNAL(readyRead(const QHttpResponseHeader &)), |
|
94 this, SLOT(readData(const QHttpResponseHeader &))); |
|
95 |
|
96 connect(&http, SIGNAL(requestFinished(int, bool)), |
|
97 this, SLOT(finished(int, bool))); |
|
98 |
|
99 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(fetch())); |
|
100 connect(fetchButton, SIGNAL(clicked()), this, SLOT(fetch())); |
|
101 connect(abortButton, SIGNAL(clicked()), &http, SLOT(abort())); |
|
102 |
|
103 QVBoxLayout *layout = new QVBoxLayout(this); |
|
104 |
|
105 QHBoxLayout *hboxLayout = new QHBoxLayout; |
|
106 |
|
107 hboxLayout->addWidget(lineEdit); |
|
108 hboxLayout->addWidget(fetchButton); |
|
109 hboxLayout->addWidget(abortButton); |
|
110 |
|
111 layout->addLayout(hboxLayout); |
|
112 layout->addWidget(treeWidget); |
|
113 |
|
114 setWindowTitle(tr("RSS listing example")); |
|
115 resize(640,480); |
|
116 } |
|
117 |
|
118 /* |
|
119 Starts fetching data from a news source specified in the line |
|
120 edit widget. |
|
121 |
|
122 The line edit is made read only to prevent the user from modifying its |
|
123 contents during the fetch; this is only for cosmetic purposes. |
|
124 The fetch button is disabled, and the abort button is enabled to allow |
|
125 the user to interrupt processing. The list view is cleared, and we |
|
126 define the last list view item to be 0, meaning that there are no |
|
127 existing items in the list. |
|
128 |
|
129 The HTTP handler is supplied with the raw contents of the line edit and |
|
130 a fetch is initiated. We keep the ID value returned by the HTTP handler |
|
131 for future reference. |
|
132 */ |
|
133 |
|
134 void RSSListing::fetch() |
|
135 { |
|
136 lineEdit->setReadOnly(true); |
|
137 fetchButton->setEnabled(false); |
|
138 abortButton->setEnabled(true); |
|
139 treeWidget->clear(); |
|
140 |
|
141 xml.clear(); |
|
142 |
|
143 QUrl url(lineEdit->text()); |
|
144 |
|
145 http.setHost(url.host()); |
|
146 connectionId = http.get(url.path()); |
|
147 } |
|
148 |
|
149 /* |
|
150 Reads data received from the RDF source. |
|
151 |
|
152 We read all the available data, and pass it to the XML |
|
153 stream reader. Then we call the XML parsing function. |
|
154 |
|
155 If parsing fails for any reason, we abort the fetch. |
|
156 */ |
|
157 |
|
158 void RSSListing::readData(const QHttpResponseHeader &resp) |
|
159 { |
|
160 if (resp.statusCode() != 200) |
|
161 http.abort(); |
|
162 else { |
|
163 xml.addData(http.readAll()); |
|
164 parseXml(); |
|
165 } |
|
166 } |
|
167 |
|
168 /* |
|
169 Finishes processing an HTTP request. |
|
170 |
|
171 The default behavior is to keep the text edit read only. |
|
172 |
|
173 If an error has occurred, the user interface is made available |
|
174 to the user for further input, allowing a new fetch to be |
|
175 started. |
|
176 |
|
177 If the HTTP get request has finished, we make the |
|
178 user interface available to the user for further input. |
|
179 */ |
|
180 |
|
181 void RSSListing::finished(int id, bool error) |
|
182 { |
|
183 if (error) { |
|
184 qWarning("Received error during HTTP fetch."); |
|
185 lineEdit->setReadOnly(false); |
|
186 abortButton->setEnabled(false); |
|
187 fetchButton->setEnabled(true); |
|
188 } |
|
189 else if (id == connectionId) { |
|
190 lineEdit->setReadOnly(false); |
|
191 abortButton->setEnabled(false); |
|
192 fetchButton->setEnabled(true); |
|
193 } |
|
194 } |
|
195 |
|
196 |
|
197 /* |
|
198 Parses the XML data and creates treeWidget items accordingly. |
|
199 */ |
|
200 void RSSListing::parseXml() |
|
201 { |
|
202 while (!xml.atEnd()) { |
|
203 xml.readNext(); |
|
204 if (xml.isStartElement()) { |
|
205 if (xml.name() == "item") |
|
206 linkString = xml.attributes().value("rss:about").toString(); |
|
207 currentTag = xml.name().toString(); |
|
208 } else if (xml.isEndElement()) { |
|
209 if (xml.name() == "item") { |
|
210 |
|
211 QTreeWidgetItem *item = new QTreeWidgetItem; |
|
212 item->setText(0, titleString); |
|
213 item->setText(1, linkString); |
|
214 treeWidget->addTopLevelItem(item); |
|
215 |
|
216 titleString.clear(); |
|
217 linkString.clear(); |
|
218 } |
|
219 |
|
220 } else if (xml.isCharacters() && !xml.isWhitespace()) { |
|
221 if (currentTag == "title") |
|
222 titleString += xml.text().toString(); |
|
223 else if (currentTag == "link") |
|
224 linkString += xml.text().toString(); |
|
225 } |
|
226 } |
|
227 if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { |
|
228 qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString(); |
|
229 http.abort(); |
|
230 } |
|
231 } |
|
232 |
|
233 /* |
|
234 Open the link in the browser |
|
235 */ |
|
236 void RSSListing::itemActivated(QTreeWidgetItem * item) |
|
237 { |
|
238 QDesktopServices::openUrl(QUrl(item->text(1))); |
|
239 } |