1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
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
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qdeclarativeinclude_p.h"
44 #include <QtScript/qscriptengine.h>
45 #include <QtNetwork/qnetworkrequest.h>
46 #include <QtNetwork/qnetworkreply.h>
47 #include <QtCore/qfile.h>
49 #include <private/qdeclarativeengine_p.h>
50 #include <private/qdeclarativeglobalscriptclass_p.h>
54 QDeclarativeInclude::QDeclarativeInclude(const QUrl &url,
55 QDeclarativeEngine *engine,
57 : QObject(engine), m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0)
59 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
60 m_context = ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
62 m_scope[0] = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
63 m_scope[1] = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
65 m_scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
66 m_network = QDeclarativeScriptEngine::get(m_scriptEngine)->networkAccessManager();
68 m_result = resultValue(m_scriptEngine);
70 QNetworkRequest request;
73 m_reply = m_network->get(request);
74 QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
77 QDeclarativeInclude::~QDeclarativeInclude()
82 QScriptValue QDeclarativeInclude::resultValue(QScriptEngine *engine, Status status)
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));
90 result.setProperty(QLatin1String("status"), QScriptValue(engine, status));
94 QScriptValue QDeclarativeInclude::result() const
99 void QDeclarativeInclude::setCallback(const QScriptValue &c)
104 QScriptValue QDeclarativeInclude::callback() const
109 #define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
110 void QDeclarativeInclude::finished()
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());
120 QNetworkRequest request;
121 request.setUrl(m_url);
123 m_reply = m_network->get(request);
124 QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
129 if (m_reply->error() == QNetworkReply::NoError) {
130 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine);
132 QByteArray data = m_reply->readAll();
134 QString code = QString::fromUtf8(data);
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]);
141 scriptContext->pushScope(m_scope[1]);
142 scriptContext->setActivationObject(m_scope[1]);
143 QDeclarativeScriptParser::extractPragmas(code);
145 m_scriptEngine->evaluate(code, urlString, 1);
147 m_scriptEngine->popContext();
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();
154 m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Ok));
157 m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, NetworkError));
160 callback(m_scriptEngine, m_callback, m_result);
166 void QDeclarativeInclude::callback(QScriptEngine *engine, QScriptValue &callback, QScriptValue &status)
168 if (callback.isValid()) {
169 QScriptValue args = engine->newArray(1);
170 args.setProperty(0, status);
171 callback.call(QScriptValue(), args);
176 Documented in qdeclarativeengine.cpp
178 QScriptValue QDeclarativeInclude::include(QScriptContext *ctxt, QScriptEngine *engine)
180 if (ctxt->argumentCount() == 0)
181 return engine->undefinedValue();
183 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
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"));
189 QString urlString = ctxt->argument(0).toString();
191 if (url.isRelative()) {
192 url = QUrl(contextUrl).resolved(url);
193 urlString = url.toString();
196 QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
198 QScriptValue func = ctxt->argument(1);
199 if (!func.isFunction())
200 func = QScriptValue();
203 if (localFile.isEmpty()) {
204 QDeclarativeInclude *i =
205 new QDeclarativeInclude(url, QDeclarativeEnginePrivate::getEngine(engine), ctxt);
208 i->setCallback(func);
210 result = i->result();
214 if (f.open(QIODevice::ReadOnly)) {
215 QByteArray data = f.readAll();
216 QString code = QString::fromUtf8(data);
218 QDeclarativeContextData *context =
219 ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
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);
229 engine->evaluate(code, urlString, 1);
231 engine->popContext();
233 if (engine->hasUncaughtException()) {
234 result = resultValue(engine, Exception);
235 result.setProperty(QLatin1String("exception"), engine->uncaughtException());
236 engine->clearExceptions();
238 result = resultValue(engine, Ok);
240 callback(engine, func, result);
242 result = resultValue(engine, NetworkError);
243 callback(engine, func, result);
250 QScriptValue QDeclarativeInclude::worker_include(QScriptContext *ctxt, QScriptEngine *engine)
252 if (ctxt->argumentCount() == 0)
253 return engine->undefinedValue();
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());
261 url = QUrl(contextUrl).resolved(url);
262 urlString = url.toString();
265 QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
267 QScriptValue func = ctxt->argument(1);
268 if (!func.isFunction())
269 func = QScriptValue();
272 if (!localFile.isEmpty()) {
275 if (f.open(QIODevice::ReadOnly)) {
276 QByteArray data = f.readAll();
277 QString code = QString::fromUtf8(data);
279 QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
280 QScriptValue urlContext = engine->newObject();
281 urlContext.setData(QScriptValue(engine, urlString));
282 scriptContext->pushScope(urlContext);
284 QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
285 scriptContext->pushScope(scope);
286 scriptContext->setActivationObject(scope);
287 QDeclarativeScriptParser::extractPragmas(code);
289 engine->evaluate(code, urlString, 1);
291 engine->popContext();
293 if (engine->hasUncaughtException()) {
294 result = resultValue(engine, Exception);
295 result.setProperty(QLatin1String("exception"), engine->uncaughtException());
296 engine->clearExceptions();
298 result = resultValue(engine, Ok);
300 callback(engine, func, result);
302 result = resultValue(engine, NetworkError);
303 callback(engine, func, result);