Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeinclude.cpp
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 ** 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 #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
52 QT_BEGIN_NAMESPACE
53
54 QDeclarativeInclude::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
77 QDeclarativeInclude::~QDeclarativeInclude()
78 {
79     delete m_reply;
80 }
81
82 QScriptValue 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
94 QScriptValue QDeclarativeInclude::result() const
95 {
96     return m_result;
97 }
98
99 void QDeclarativeInclude::setCallback(const QScriptValue &c)
100 {
101     m_callback = c;
102 }
103
104 QScriptValue QDeclarativeInclude::callback() const
105 {
106     return m_callback;
107 }
108
109 #define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
110 void 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
166 void 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 */
178 QScriptValue 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
250 QScriptValue 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
310 QT_END_NAMESPACE