source: trunk/src/declarative/qml/qdeclarativeinclude.cpp@ 900

Last change on this file since 900 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 10.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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 QtDeclarative module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdeclarativeinclude_p.h"
43
44#include <QtScript/qscriptengine.h>
45#include <QtNetwork/qnetworkrequest.h>
46#include <QtNetwork/qnetworkreply.h>
47#include <QtCore/qfile.h>
48
49#include <private/qdeclarativeengine_p.h>
50#include <private/qdeclarativeglobalscriptclass_p.h>
51
52QT_BEGIN_NAMESPACE
53
54QDeclarativeInclude::QDeclarativeInclude(const QUrl &url,
55 QDeclarativeEngine *engine,
56 QScriptContext *ctxt)
57: QObject(engine), m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0)
58{
59 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
60 m_context = ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
61
62 m_scope[0] = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
63 m_scope[1] = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
64
65 m_scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
66 m_network = QDeclarativeScriptEngine::get(m_scriptEngine)->networkAccessManager();
67
68 m_result = resultValue(m_scriptEngine);
69
70 QNetworkRequest request;
71 request.setUrl(url);
72
73 m_reply = m_network->get(request);
74 QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
75}
76
77QDeclarativeInclude::~QDeclarativeInclude()
78{
79 delete m_reply;
80}
81
82QScriptValue QDeclarativeInclude::resultValue(QScriptEngine *engine, Status status)
83{
84 QScriptValue result = engine->newObject();
85 result.setProperty(QLatin1String("OK"), QScriptValue(engine, Ok));
86 result.setProperty(QLatin1String("LOADING"), QScriptValue(engine, Loading));
87 result.setProperty(QLatin1String("NETWORK_ERROR"), QScriptValue(engine, NetworkError));
88 result.setProperty(QLatin1String("EXCEPTION"), QScriptValue(engine, Exception));
89
90 result.setProperty(QLatin1String("status"), QScriptValue(engine, status));
91 return result;
92}
93
94QScriptValue QDeclarativeInclude::result() const
95{
96 return m_result;
97}
98
99void QDeclarativeInclude::setCallback(const QScriptValue &c)
100{
101 m_callback = c;
102}
103
104QScriptValue QDeclarativeInclude::callback() const
105{
106 return m_callback;
107}
108
109#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
110void QDeclarativeInclude::finished()
111{
112 m_redirectCount++;
113
114 if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
115 QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
116 if (redirect.isValid()) {
117 m_url = m_url.resolved(redirect.toUrl());
118 delete m_reply;
119
120 QNetworkRequest request;
121 request.setUrl(m_url);
122
123 m_reply = m_network->get(request);
124 QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
125 return;
126 }
127 }
128
129 if (m_reply->error() == QNetworkReply::NoError) {
130 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine);
131
132 QByteArray data = m_reply->readAll();
133
134 QString code = QString::fromUtf8(data);
135
136 QString urlString = m_url.toString();
137 QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(m_scriptEngine);
138 scriptContext->pushScope(ep->contextClass->newUrlContext(m_context, 0, urlString));
139 scriptContext->pushScope(m_scope[0]);
140
141 scriptContext->pushScope(m_scope[1]);
142 scriptContext->setActivationObject(m_scope[1]);
143 QDeclarativeScriptParser::extractPragmas(code);
144
145 m_scriptEngine->evaluate(code, urlString, 1);
146
147 m_scriptEngine->popContext();
148
149 if (m_scriptEngine->hasUncaughtException()) {
150 m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Exception));
151 m_result.setProperty(QLatin1String("exception"), m_scriptEngine->uncaughtException());
152 m_scriptEngine->clearExceptions();
153 } else {
154 m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Ok));
155 }
156 } else {
157 m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, NetworkError));
158 }
159
160 callback(m_scriptEngine, m_callback, m_result);
161
162 disconnect();
163 deleteLater();
164}
165
166void QDeclarativeInclude::callback(QScriptEngine *engine, QScriptValue &callback, QScriptValue &status)
167{
168 if (callback.isValid()) {
169 QScriptValue args = engine->newArray(1);
170 args.setProperty(0, status);
171 callback.call(QScriptValue(), args);
172 }
173}
174
175/*
176 Documented in qdeclarativeengine.cpp
177*/
178QScriptValue QDeclarativeInclude::include(QScriptContext *ctxt, QScriptEngine *engine)
179{
180 if (ctxt->argumentCount() == 0)
181 return engine->undefinedValue();
182
183 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
184
185 QUrl contextUrl = ep->contextClass->urlFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
186 if (contextUrl.isEmpty())
187 return ctxt->throwError(QLatin1String("Qt.include(): Can only be called from JavaScript files"));
188
189 QString urlString = ctxt->argument(0).toString();
190 QUrl url(urlString);
191 if (url.isRelative()) {
192 url = QUrl(contextUrl).resolved(url);
193 urlString = url.toString();
194 }
195
196 QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
197
198 QScriptValue func = ctxt->argument(1);
199 if (!func.isFunction())
200 func = QScriptValue();
201
202 QScriptValue result;
203 if (localFile.isEmpty()) {
204 QDeclarativeInclude *i =
205 new QDeclarativeInclude(url, QDeclarativeEnginePrivate::getEngine(engine), ctxt);
206
207 if (func.isValid())
208 i->setCallback(func);
209
210 result = i->result();
211 } else {
212
213 QFile f(localFile);
214 if (f.open(QIODevice::ReadOnly)) {
215 QByteArray data = f.readAll();
216 QString code = QString::fromUtf8(data);
217
218 QDeclarativeContextData *context =
219 ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
220
221 QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
222 scriptContext->pushScope(ep->contextClass->newUrlContext(context, 0, urlString));
223 scriptContext->pushScope(ep->globalClass->staticGlobalObject());
224 QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
225 scriptContext->pushScope(scope);
226 scriptContext->setActivationObject(scope);
227 QDeclarativeScriptParser::extractPragmas(code);
228
229 engine->evaluate(code, urlString, 1);
230
231 engine->popContext();
232
233 if (engine->hasUncaughtException()) {
234 result = resultValue(engine, Exception);
235 result.setProperty(QLatin1String("exception"), engine->uncaughtException());
236 engine->clearExceptions();
237 } else {
238 result = resultValue(engine, Ok);
239 }
240 callback(engine, func, result);
241 } else {
242 result = resultValue(engine, NetworkError);
243 callback(engine, func, result);
244 }
245 }
246
247 return result;
248}
249
250QScriptValue QDeclarativeInclude::worker_include(QScriptContext *ctxt, QScriptEngine *engine)
251{
252 if (ctxt->argumentCount() == 0)
253 return engine->undefinedValue();
254
255 QString urlString = ctxt->argument(0).toString();
256 QUrl url(ctxt->argument(0).toString());
257 if (url.isRelative()) {
258 QString contextUrl = QScriptDeclarativeClass::scopeChainValue(ctxt, -3).data().toString();
259 Q_ASSERT(!contextUrl.isEmpty());
260
261 url = QUrl(contextUrl).resolved(url);
262 urlString = url.toString();
263 }
264
265 QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
266
267 QScriptValue func = ctxt->argument(1);
268 if (!func.isFunction())
269 func = QScriptValue();
270
271 QScriptValue result;
272 if (!localFile.isEmpty()) {
273
274 QFile f(localFile);
275 if (f.open(QIODevice::ReadOnly)) {
276 QByteArray data = f.readAll();
277 QString code = QString::fromUtf8(data);
278
279 QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
280 QScriptValue urlContext = engine->newObject();
281 urlContext.setData(QScriptValue(engine, urlString));
282 scriptContext->pushScope(urlContext);
283
284 QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
285 scriptContext->pushScope(scope);
286 scriptContext->setActivationObject(scope);
287 QDeclarativeScriptParser::extractPragmas(code);
288
289 engine->evaluate(code, urlString, 1);
290
291 engine->popContext();
292
293 if (engine->hasUncaughtException()) {
294 result = resultValue(engine, Exception);
295 result.setProperty(QLatin1String("exception"), engine->uncaughtException());
296 engine->clearExceptions();
297 } else {
298 result = resultValue(engine, Ok);
299 }
300 callback(engine, func, result);
301 } else {
302 result = resultValue(engine, NetworkError);
303 callback(engine, func, result);
304 }
305 }
306
307 return result;
308}
309
310QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.