Docs - add missing images and code, clean up sections
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmltypeloader_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QQMLTYPELOADER_P_H
43 #define QQMLTYPELOADER_P_H
44
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists purely as an
50 // implementation detail.  This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55
56 #include <QtCore/qobject.h>
57 #include <QtCore/qatomic.h>
58 #include <QtNetwork/qnetworkreply.h>
59 #include <QtQml/qqmlerror.h>
60 #include <QtQml/qqmlengine.h>
61 #include <QtQml/qqmlfile.h>
62
63 #include <private/qv8_p.h>
64 #include <private/qhashedstring_p.h>
65 #include <private/qqmlscript_p.h>
66 #include <private/qqmlimport_p.h>
67 #include <private/qqmlcleanup_p.h>
68 #include <private/qqmldirparser_p.h>
69 #include <private/qqmlbundle_p.h>
70 #include <private/qflagpointer_p.h>
71
72 QT_BEGIN_NAMESPACE
73
74 class QQmlScriptData;
75 class QQmlScriptBlob;
76 class QQmlQmldirData;
77 class QQmlTypeLoader;
78 class QQmlCompiledData;
79 class QQmlComponentPrivate;
80 class QQmlTypeData;
81 class QQmlDataLoader;
82 class QQmlExtensionInterface;
83
84 class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
85 {
86 public:
87     enum Status {
88         Null,                    // Prior to QQmlDataLoader::load()
89         Loading,                 // Prior to data being received and dataReceived() being called
90         WaitingForDependencies,  // While there are outstanding addDependency()s
91         Complete,                // Finished
92         Error                    // Error
93     };
94
95     enum Type {
96         QmlFile,
97         JavaScriptFile,
98         QmldirFile
99     };
100
101     QQmlDataBlob(const QUrl &, Type);
102     virtual ~QQmlDataBlob();
103
104     Type type() const;
105
106     Status status() const;
107     bool isNull() const;
108     bool isLoading() const;
109     bool isWaiting() const;
110     bool isComplete() const;
111     bool isError() const;
112     bool isCompleteOrError() const;
113
114     qreal progress() const;
115
116     QUrl url() const;
117     QUrl finalUrl() const;
118     QString finalUrlString() const;
119
120     QList<QQmlError> errors() const;
121
122     class Data {
123     public:
124         inline const char *data() const;
125         inline int size() const;
126
127         inline QByteArray asByteArray() const;
128
129         inline bool isFile() const;
130         inline QQmlFile *asFile() const;
131
132     private:
133         friend class QQmlDataBlob;
134         friend class QQmlDataLoader;
135         inline Data();
136         Data(const Data &);
137         Data &operator=(const Data &);
138         QBiPointer<const QByteArray, QQmlFile> d;
139     };
140
141 protected:
142     // Can be called from within callbacks
143     void setError(const QQmlError &);
144     void setError(const QList<QQmlError> &errors);
145     void addDependency(QQmlDataBlob *);
146
147     // Callbacks made in load thread
148     virtual void dataReceived(const Data &) = 0;
149     virtual void done();
150     virtual void networkError(QNetworkReply::NetworkError);
151     virtual void dependencyError(QQmlDataBlob *);
152     virtual void dependencyComplete(QQmlDataBlob *);
153     virtual void allDependenciesDone();
154
155     // Callbacks made in main thread
156     virtual void downloadProgressChanged(qreal);
157     virtual void completed();
158 private:
159     friend class QQmlDataLoader;
160     friend class QQmlDataLoaderThread;
161
162     void tryDone();
163     void cancelAllWaitingFor();
164     void notifyAllWaitingOnMe();
165     void notifyComplete(QQmlDataBlob *);
166
167     struct ThreadData {
168         inline ThreadData();
169         inline QQmlDataBlob::Status status() const;
170         inline void setStatus(QQmlDataBlob::Status);
171         inline bool isAsync() const;
172         inline void setIsAsync(bool);
173         inline quint8 progress() const;
174         inline void setProgress(quint8);
175
176     private:
177         QAtomicInt _p;
178     };
179     ThreadData m_data;
180
181     // m_errors should *always* be written before the status is set to Error.
182     // We use the status change as a memory fence around m_errors so that locking
183     // isn't required.  Once the status is set to Error (or Complete), m_errors 
184     // cannot be changed.
185     QList<QQmlError> m_errors;
186
187     Type m_type;
188
189     QUrl m_url;
190     QUrl m_finalUrl;
191     mutable QString m_finalUrlString;
192
193     // List of QQmlDataBlob's that are waiting for me to complete.
194     QList<QQmlDataBlob *> m_waitingOnMe;
195
196     // List of QQmlDataBlob's that I am waiting for to complete.
197     QList<QQmlDataBlob *> m_waitingFor;
198
199     // Manager that is currently fetching data for me
200     QQmlDataLoader *m_manager;
201     int m_redirectCount:30;
202     bool m_inCallback:1;
203     bool m_isDone:1;
204 };
205
206 class QQmlDataLoaderThread;
207 class QQmlDataLoader
208 {
209 public:
210     QQmlDataLoader(QQmlEngine *);
211     ~QQmlDataLoader();
212
213     void lock();
214     void unlock();
215
216     bool isConcurrent() const { return true; }
217
218     enum Mode { PreferSynchronous, Asynchronous };
219
220     void load(QQmlDataBlob *, Mode = PreferSynchronous);
221     void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
222
223     QQmlEngine *engine() const;
224     void initializeEngine(QQmlExtensionInterface *, const char *);
225
226 protected:
227     void shutdownThread();
228
229 private:
230     friend class QQmlDataBlob;
231     friend class QQmlDataLoaderThread;
232     friend class QQmlDataLoaderNetworkReplyProxy;
233
234     void loadThread(QQmlDataBlob *);
235     void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
236     void networkReplyFinished(QNetworkReply *);
237     void networkReplyProgress(QNetworkReply *, qint64, qint64);
238     
239     typedef QHash<QNetworkReply *, QQmlDataBlob *> NetworkReplies;
240
241     void setData(QQmlDataBlob *, const QByteArray &);
242     void setData(QQmlDataBlob *, QQmlFile *);
243     void setData(QQmlDataBlob *, const QQmlDataBlob::Data &);
244
245     QQmlEngine *m_engine;
246     QQmlDataLoaderThread *m_thread;
247     NetworkReplies m_networkReplies;
248 };
249
250 class QQmlBundleData : public QQmlBundle,
251                        public QQmlRefCount
252 {
253 public:
254     QQmlBundleData(const QString &);
255     QString fileName;
256 };
257
258 class QQmlTypeLoader : public QQmlDataLoader
259 {
260     Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
261 public:
262     class Q_QML_PRIVATE_EXPORT Blob : public QQmlDataBlob
263     {
264     public:
265         Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader);
266         ~Blob();
267
268         QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
269         const QQmlImports &imports() const { return m_imports; }
270
271     protected:
272         bool addImport(const QQmlScript::Import &import, QList<QQmlError> *errors);
273
274         bool fetchQmldir(const QUrl &url, const QQmlScript::Import *import, int priority, QList<QQmlError> *errors);
275         bool updateQmldir(QQmlQmldirData *data, const QQmlScript::Import *import, QList<QQmlError> *errors);
276
277     private:
278         virtual bool qmldirDataAvailable(QQmlQmldirData *, QList<QQmlError> *);
279
280         virtual void scriptImported(QQmlScriptBlob *, const QQmlScript::Location &, const QString &, const QString &) {}
281
282         virtual void dependencyError(QQmlDataBlob *);
283         virtual void dependencyComplete(QQmlDataBlob *);
284
285     protected:
286         QQmlTypeLoader *m_typeLoader;
287         QQmlImports m_imports;
288         QHash<const QQmlScript::Import *, int> m_unresolvedImports;
289         QList<QQmlQmldirData *> m_qmldirs;
290     };
291
292     class QmldirContent
293     {
294     private:
295         friend class QQmlTypeLoader;
296         QmldirContent();
297
298         void setContent(const QString &location, const QString &content);
299         void setError(const QQmlError &);
300
301     public:
302         bool hasError() const;
303         QList<QQmlError> errors(const QString &uri) const;
304
305         QString typeNamespace() const;
306
307         QQmlDirComponents components() const;
308         QQmlDirScripts scripts() const;
309         QQmlDirPlugins plugins() const;
310
311         QString pluginLocation() const;
312
313     private:
314         QQmlDirParser m_parser;
315         QString m_location;
316     };
317
318     QQmlTypeLoader(QQmlEngine *);
319     ~QQmlTypeLoader();
320
321     enum Option {
322         None,
323         PreserveParser
324     };
325     Q_DECLARE_FLAGS(Options, Option)
326
327     QQmlImportDatabase *importDatabase();
328
329     QQmlTypeData *getType(const QUrl &url, Mode mode = PreferSynchronous);
330     QQmlTypeData *getType(const QByteArray &, const QUrl &url, Options = None);
331
332     QQmlScriptBlob *getScript(const QUrl &);
333     QQmlQmldirData *getQmldir(const QUrl &);
334
335     QQmlBundleData *getBundle(const QString &);
336     QQmlBundleData *getBundle(const QHashedStringRef &);
337     void addBundle(const QString &, const QString &);
338
339     QString absoluteFilePath(const QString &path);
340     bool directoryExists(const QString &path);
341
342     const QmldirContent *qmldirContent(const QString &filePath, const QString &uriHint);
343     void setQmldirContent(const QString &filePath, const QString &content);
344
345     void clearCache();
346     void trimCache();
347
348     bool isTypeLoaded(const QUrl &url) const;
349     bool isScriptLoaded(const QUrl &url) const;
350
351 private:
352     void addBundleNoLock(const QString &, const QString &);
353     QString bundleIdForQmldir(const QString &qmldir, const QString &uriHint);
354
355     template<typename T>
356     struct TypedCallback
357     {
358         TypedCallback(T *object, void (T::*func)(QQmlTypeData *)) : o(object), mf(func) {}
359
360         static void redirect(void *arg, QQmlTypeData *type)
361         {
362             TypedCallback<T> *self = reinterpret_cast<TypedCallback<T> *>(arg);
363             ((self->o)->*(self->mf))(type);
364         }
365
366     private:
367         T *o;
368         void (T::*mf)(QQmlTypeData *);
369     };
370
371     typedef QHash<QUrl, QQmlTypeData *> TypeCache;
372     typedef QHash<QUrl, QQmlScriptBlob *> ScriptCache;
373     typedef QHash<QUrl, QQmlQmldirData *> QmldirCache;
374     typedef QStringHash<bool> StringSet;
375     typedef QStringHash<StringSet*> ImportDirCache;
376     typedef QStringHash<QmldirContent *> ImportQmlDirCache;
377     typedef QStringHash<QQmlBundleData *> BundleCache;
378     typedef QStringHash<QString> QmldirBundleIdCache;
379
380     TypeCache m_typeCache;
381     ScriptCache m_scriptCache;
382     QmldirCache m_qmldirCache;
383     ImportDirCache m_importDirCache;
384     ImportQmlDirCache m_importQmlDirCache;
385     BundleCache m_bundleCache;
386     QmldirBundleIdCache m_qmldirBundleIdCache;
387 };
388
389 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlTypeLoader::Options)
390
391 class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
392 {
393 public:
394     struct TypeReference
395     {
396         TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0) {}
397
398         QQmlScript::Location location;
399         QQmlType *type;
400         int majorVersion;
401         int minorVersion;
402         QQmlTypeData *typeData;
403     };
404
405     struct ScriptReference
406     {
407         ScriptReference() : script(0) {}
408
409         QQmlScript::Location location;
410         QString qualifier;
411         QQmlScriptBlob *script;
412     };
413
414 private:
415     friend class QQmlTypeLoader;
416
417     QQmlTypeData(const QUrl &, QQmlTypeLoader::Options, QQmlTypeLoader *);
418
419 public:
420     ~QQmlTypeData();
421
422     const QQmlScript::Parser &parser() const;
423
424     const QList<TypeReference> &resolvedTypes() const;
425     const QList<ScriptReference> &resolvedScripts() const;
426     const QSet<QString> &namespaces() const;
427
428     QQmlCompiledData *compiledData() const;
429
430     // Used by QQmlComponent to get notifications
431     struct TypeDataCallback {
432         ~TypeDataCallback() {}
433         virtual void typeDataProgress(QQmlTypeData *, qreal) {}
434         virtual void typeDataReady(QQmlTypeData *) {}
435     };
436     void registerCallback(TypeDataCallback *);
437     void unregisterCallback(TypeDataCallback *);
438
439 protected:
440     virtual void done();
441     virtual void completed();
442     virtual void dataReceived(const Data &);
443     virtual void allDependenciesDone();
444     virtual void downloadProgressChanged(qreal);
445
446 private:
447     void resolveTypes();
448     void compile();
449
450     virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
451
452     QQmlTypeLoader::Options m_options;
453
454     QQmlScript::Parser scriptParser;
455
456     QList<ScriptReference> m_scripts;
457
458     QSet<QString> m_namespaces;
459
460     QList<TypeReference> m_types;
461     bool m_typesResolved:1;
462
463     QQmlCompiledData *m_compiledData;
464
465     QList<TypeDataCallback *> m_callbacks;
466
467     QQmlScript::Import *m_implicitImport;
468 };
469
470 // QQmlScriptData instances are created, uninitialized, by the loader in the 
471 // load thread.  The first time they are used by the VME, they are initialized which
472 // creates their v8 objects and they are referenced and added to the  engine's cleanup
473 // list.  During QQmlCleanup::clear() all v8 resources are destroyed, and the 
474 // reference that was created is released but final deletion only occurs once all the
475 // references as released.  This is all intended to ensure that the v8 resources are
476 // only created and destroyed in the main thread :)
477 class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup, public QQmlRefCount
478 {
479 private:
480     friend class QQmlTypeLoader;
481
482     QQmlScriptData();
483
484 public:
485     ~QQmlScriptData();
486
487     QUrl url;
488     QString urlString;
489     QQmlTypeNameCache *importCache;
490     QList<QQmlScriptBlob *> scripts;
491     QQmlScript::Object::ScriptBlock::Pragmas pragmas;
492
493     bool isInitialized() const { return hasEngine(); }
494     void initialize(QQmlEngine *);
495
496     bool hasError() const { return m_error.isValid(); }
497     void setError(const QQmlError &error) { m_error = error; }
498     QQmlError error() const { return m_error; }
499
500 protected:
501     virtual void clear(); // From QQmlCleanup
502
503 private:
504     friend class QQmlVME;
505     friend class QQmlScriptBlob;
506
507     bool m_loaded;
508     QByteArray m_programSource;
509     v8::Persistent<v8::Script> m_program;
510     v8::Persistent<v8::Object> m_value;
511     QQmlError m_error;
512 };
513
514 class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlTypeLoader::Blob
515 {
516 private:
517     friend class QQmlTypeLoader;
518
519     QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
520
521 public:
522     ~QQmlScriptBlob();
523
524     struct ScriptReference
525     {
526         ScriptReference() : script(0) {}
527
528         QQmlScript::Location location;
529         QString qualifier;
530         QString nameSpace;
531         QQmlScriptBlob *script;
532     };
533
534     QQmlScript::Object::ScriptBlock::Pragmas pragmas() const;
535
536     QQmlScriptData *scriptData() const;
537
538 protected:
539     virtual void dataReceived(const Data &);
540     virtual void done();
541
542 private:
543     virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
544
545     QString m_source;
546     QQmlScript::Parser::JavaScriptMetaData m_metadata;
547
548     QList<ScriptReference> m_scripts;
549     QQmlScriptData *m_scriptData;
550 };
551
552 class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
553 {
554 private:
555     friend class QQmlTypeLoader;
556
557     QQmlQmldirData(const QUrl &, QQmlTypeLoader *);
558
559 public:
560     const QString &content() const;
561
562     const QQmlScript::Import *import() const;
563     void setImport(const QQmlScript::Import *);
564
565     int priority() const;
566     void setPriority(int);
567
568 protected:
569     virtual void dataReceived(const Data &);
570
571 private:
572     QString m_content;
573     const QQmlScript::Import *m_import;
574     int m_priority;
575 };
576
577 QQmlDataBlob::Data::Data()
578 {
579 }
580
581 const char *QQmlDataBlob::Data::data() const
582 {
583     Q_ASSERT(!d.isNull());
584
585     if (d.isT1()) return d.asT1()->constData();
586     else return d.asT2()->data();
587 }
588
589 int QQmlDataBlob::Data::size() const
590 {
591     Q_ASSERT(!d.isNull());
592
593     if (d.isT1()) return d.asT1()->size();
594     else return d.asT2()->size();
595 }
596
597 bool QQmlDataBlob::Data::isFile() const
598 {
599     return d.isT2();
600 }
601
602 QByteArray QQmlDataBlob::Data::asByteArray() const
603 {
604     Q_ASSERT(!d.isNull());
605
606     if (d.isT1()) return *d.asT1();
607     else return d.asT2()->dataByteArray();
608 }
609
610 QQmlFile *QQmlDataBlob::Data::asFile() const
611 {
612     if (d.isT2()) return d.asT2();
613     else return 0;
614 }
615
616 QT_END_NAMESPACE
617
618 #endif // QQMLTYPELOADER_P_H