Qt 4.8
qdeclarativecontext.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qdeclarativecontext.h"
43 #include "private/qdeclarativecontext_p.h"
44 
45 #include "private/qdeclarativecomponent_p.h"
46 #include "private/qdeclarativeexpression_p.h"
47 #include "private/qdeclarativeengine_p.h"
48 #include "qdeclarativeengine.h"
49 #include "private/qdeclarativecompiledbindings_p.h"
50 #include "qdeclarativeinfo.h"
51 #include "private/qdeclarativeglobalscriptclass_p.h"
52 
53 #include <qscriptengine.h>
54 #include <QtCore/qvarlengtharray.h>
55 #include <QtCore/qdebug.h>
56 
57 #include <private/qscriptdeclarativeclass_p.h>
58 
60 
62 : data(0), notifyIndex(-1)
63 {
64 }
65 
168 {
170  d->data = new QDeclarativeContextData(this);
171 
172  d->data->engine = e;
173 }
174 
180 : QObject(*(new QDeclarativeContextPrivate), parent)
181 {
183  d->data = new QDeclarativeContextData(this);
184 
185  d->data->setParent(engine?QDeclarativeContextData::get(engine->rootContext()):0);
186 }
187 
193 : QObject(*(new QDeclarativeContextPrivate), parent)
194 {
196  d->data = new QDeclarativeContextData(this);
197 
198  d->data->setParent(parentContext?QDeclarativeContextData::get(parentContext):0);
199 }
200 
206 {
208  d->data = data;
209 }
210 
219 {
221 
222  if (!d->data->isInternal)
223  d->data->destroy();
224 }
225 
233 {
234  Q_D(const QDeclarativeContext);
235  return d->data && d->data->isValid();
236 }
237 
243 {
244  Q_D(const QDeclarativeContext);
245  return d->data->engine;
246 }
247 
253 {
254  Q_D(const QDeclarativeContext);
255  return d->data->parent?d->data->parent->asQDeclarativeContext():0;
256 }
257 
262 {
263  Q_D(const QDeclarativeContext);
264  return d->data->contextObject;
265 }
266 
271 {
273 
274  QDeclarativeContextData *data = d->data;
275 
276  if (data->isInternal) {
277  qWarning("QDeclarativeContext: Cannot set context object for internal context.");
278  return;
279  }
280 
281  if (!isValid()) {
282  qWarning("QDeclarativeContext: Cannot set context object on invalid context.");
283  return;
284  }
285 
286  data->contextObject = object;
287 }
288 
293 {
295  if (d->notifyIndex == -1)
296  d->notifyIndex = this->metaObject()->methodCount();
297 
298  QDeclarativeContextData *data = d->data;
299 
300  if (data->isInternal) {
301  qWarning("QDeclarativeContext: Cannot set property on internal context.");
302  return;
303  }
304 
305  if (!isValid()) {
306  qWarning("QDeclarativeContext: Cannot set property on invalid context.");
307  return;
308  }
309 
310  if (data->engine) {
311  bool ok;
312  QObject *o = QDeclarativeEnginePrivate::get(data->engine)->toQObject(value, &ok);
313  if (ok) {
314  setContextProperty(name, o);
315  return;
316  }
317  }
318 
319  if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
320 
321  int idx = data->propertyNames->value(name);
322  if (idx == -1) {
323  data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
324  d->propertyValues.append(value);
325 
326  data->refreshExpressions();
327  } else {
328  d->propertyValues[idx] = value;
329  QMetaObject::activate(this, idx + d->notifyIndex, 0);
330  }
331 }
332 
339 {
341  if (d->notifyIndex == -1)
342  d->notifyIndex = this->metaObject()->methodCount();
343 
344  QDeclarativeContextData *data = d->data;
345 
346  if (data->isInternal) {
347  qWarning("QDeclarativeContext: Cannot set property on internal context.");
348  return;
349  }
350 
351  if (!isValid()) {
352  qWarning("QDeclarativeContext: Cannot set property on invalid context.");
353  return;
354  }
355 
356  if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
357  int idx = data->propertyNames->value(name);
358 
359  if (idx == -1) {
360  data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
361  d->propertyValues.append(QVariant::fromValue(value));
362 
363  data->refreshExpressions();
364  } else {
365  d->propertyValues[idx] = QVariant::fromValue(value);
366  QMetaObject::activate(this, idx + d->notifyIndex, 0);
367  }
368 }
369 
375 {
376  Q_D(const QDeclarativeContext);
377  QVariant value;
378  int idx = -1;
379 
380  QDeclarativeContextData *data = d->data;
381 
382  if (data->propertyNames)
383  idx = data->propertyNames->value(name);
384 
385  if (idx == -1) {
386  QByteArray utf8Name = name.toUtf8();
387  if (data->contextObject) {
388  QObject *obj = data->contextObject;
391  QDeclarativePropertyCache::property(data->engine, obj, name, local);
392 
393  if (property) value = obj->metaObject()->property(property->coreIndex).read(obj);
394  }
395  if (!value.isValid() && parentContext())
396  value = parentContext()->contextProperty(name);
397  } else {
398  if (idx >= d->propertyValues.count())
399  value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data());
400  else
401  value = d->propertyValues[idx];
402  }
403 
404  return value;
405 }
406 
414 {
416  return d->data->resolvedUrl(src);
417 }
418 
420 {
421  QDeclarativeContextData *ctxt = this;
422 
423  if (src.isRelative() && !src.isEmpty()) {
424  if (ctxt) {
425  while(ctxt) {
426  if(ctxt->url.isValid())
427  break;
428  else
429  ctxt = ctxt->parent;
430  }
431 
432  if (ctxt)
433  return ctxt->url.resolved(src);
434  else if (engine)
435  return engine->baseUrl().resolved(src);
436  }
437  return QUrl();
438  } else {
439  return src;
440  }
441 }
442 
443 
453 {
455 
456  d->data->url = baseUrl;
457 }
458 
464 {
465  Q_D(const QDeclarativeContext);
466  const QDeclarativeContextData* data = d->data;
467  while (data && data->url.isEmpty())
468  data = data->parent;
469 
470  if (data)
471  return data->url;
472  else
473  return QUrl();
474 }
475 
477 {
478  QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
480  int contextProperty = (int)(quintptr)prop->data;
481 
482  if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
483  return 0;
484  } else {
485  return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
486  }
487 }
488 
490 {
491  QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
493  int contextProperty = (int)(quintptr)prop->data;
494 
495  if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
496  return 0;
497  } else {
498  return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
499  }
500 }
501 
502 
504 : parent(0), engine(0), isInternal(false), publicContext(0), propertyNames(0), contextObject(0),
505  imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
506  contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
507  componentAttached(0)
508 {
509 }
510 
512 : parent(0), engine(0), isInternal(false), publicContext(ctxt), propertyNames(0), contextObject(0),
516 {
517 }
518 
520 {
521  while (childContexts)
523 
524  while (componentAttached) {
526  componentAttached = a->next;
528 
529  a->next = 0;
530  a->prev = 0;
531 
532  emit a->destruction();
533  }
534 
535  if (prevChild) {
536  *prevChild = nextChild;
538  nextChild = 0;
539  prevChild = 0;
540  }
541 
542  engine = 0;
543  parent = 0;
544 }
545 
547 {
548  if (engine) {
549  while (componentAttached) {
551  componentAttached = a->next;
553 
554  a->next = 0;
555  a->prev = 0;
556 
557  emit a->destruction();
558  }
559  }
560 
562  while (expression) {
563  QDeclarativeAbstractExpression *nextExpression = expression->m_nextExpression;
564 
565  expression->m_context = 0;
566  expression->m_prevExpression = 0;
567  expression->m_nextExpression = 0;
568 
569  expression = nextExpression;
570  }
571  expressions = 0;
572 }
573 
575 {
576  if (linkedContext)
578 
579  if (engine) invalidate();
580 
581  clearContext();
582 
583  while (contextObjects) {
586 
587  co->context = 0;
588  co->outerContext = 0;
589  co->nextContextObject = 0;
590  co->prevContextObject = 0;
591  }
592 
594  while (contextGuard) {
595  QDeclarativeGuardedContextData *next = contextGuard->m_next;
596  contextGuard->m_next = 0;
597  contextGuard->m_prev = 0;
598  contextGuard->m_contextData = 0;
599  contextGuard = next;
600  }
601  contextGuards = 0;
602 
603  if (propertyNames)
605 
606  if (imports)
607  imports->release();
608 
609  if (optimizedBindings)
611 
612  delete [] idValues;
613 
614  if (isInternal)
615  delete publicContext;
616 
617  delete this;
618 }
619 
621 {
622  if (p) {
623  parent = p;
624  engine = p->engine;
627  prevChild = &p->childContexts;
628  p->childContexts = this;
629  }
630 }
631 
632 /*
633 Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
634 context-tree dependent caches in the expressions, and should occur every time the context tree
635  *structure* (not values) changes.
636 */
638 {
640  while (child) {
641  child->refreshExpressions();
642  child = child->nextChild;
643  }
644 
646  while (expression) {
647  expression->refresh();
648  expression = expression->m_nextExpression;
649  }
650 }
651 
653 {
655 
656  Q_ASSERT(data->context == 0);
657 
658  data->context = this;
659  data->outerContext = this;
660 
662  if (data->nextContextObject)
666 }
667 
669 {
670  if (!engine)
671  return;
672 
675 
676  const QString &code = script.code;
677  const QString &url = script.file;
678  const QDeclarativeParser::Object::ScriptBlock::Pragmas &pragmas = script.pragmas;
679 
680  Q_ASSERT(!url.isEmpty());
681 
683 
685  if (iter == enginePriv->m_sharedScriptImports.end()) {
686  QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
687 
688  scriptContext->pushScope(enginePriv->contextClass->newUrlContext(url));
689  scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
690 
692  scriptContext->pushScope(scope);
693 
694  scriptEngine->evaluate(code, url, 1);
695 
696  if (scriptEngine->hasUncaughtException()) {
699  enginePriv->warning(error);
700  }
701 
702  scriptEngine->popContext();
703 
704  iter = enginePriv->m_sharedScriptImports.insert(url, scope);
705  }
706 
707  importedScripts.append(*iter);
708 
709  } else {
710 
711  QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
712 
713  scriptContext->pushScope(enginePriv->contextClass->newUrlContext(this, 0, url));
714  scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
715 
717  scriptContext->pushScope(scope);
718 
719  scriptEngine->evaluate(code, url, 1);
720 
721  if (scriptEngine->hasUncaughtException()) {
724  enginePriv->warning(error);
725  }
726 
727  scriptEngine->popContext();
728 
729  importedScripts.append(scope);
730 
731  }
732 }
733 
735 {
736  idValues[idx] = obj;
737  idValues[idx].context = this;
738 }
739 
741 {
745 
746  idValueCount = data->count();
748 }
749 
751 {
752  if (!idValues || !propertyNames)
753  return QString();
754 
755  for (int i=0; i<idValueCount; i++) {
756  if (idValues[i] == obj)
757  return propertyNames->findId(i);
758  }
759 
760  if (linkedContext)
761  return linkedContext->findObjectId(obj);
762  return QString();
763 }
764 
766 {
767  if (!publicContext)
769  return publicContext;
770 }
771 
773 {
775 }
776 
QDeclarativeContextData * outerContext
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
QUrl resolvedUrl(const QUrl &)
static QScriptEngine * getScriptEngine(QDeclarativeEngine *e)
double d
Definition: qnumeric_p.h:62
The QScriptContext class represents a Qt Script function invocation.
QScriptValue newUrlContext(QDeclarativeContextData *, QObject *, const QString &)
QDeclarativeContextData * context
QHash< QString, QScriptValue > m_sharedScriptImports
QDeclarativeComponentAttached * next
QScriptValue evaluate(const QString &program, const QString &fileName=QString(), int lineNumber=1)
Evaluates program, using lineNumber as the base line number, and returns the result of the evaluation...
static QDeclarativeData * get(const QObject *object, bool create=false)
bool isValid() const
Returns true if the URL is valid; otherwise returns false.
Definition: qurl.cpp:4303
QIntegerForSizeof< void * >::Unsigned quintptr
Definition: qglobal.h:986
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QString findId(int value) const
QDeclarativeEngine * engine
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
void setBaseUrl(const QUrl &)
Explicitly sets the url resolvedUrl() will use for relative references to baseUrl.
QUrl baseUrl() const
Return the base URL for this engine.
QDeclarativeContext * publicContext
#define error(msg)
QDeclarativeAbstractExpression ** m_prevExpression
#define at(className, varName)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition: qurl.cpp:4317
QDeclarativeComponentAttached * componentAttached
QUrl baseUrl() const
Returns the base url of the component, or the containing component if none is set.
QDeclarativeGlobalScriptClass * globalClass
QUrl resolvedUrl(const QUrl &)
Resolves the URL src relative to the URL of the containing component.
QDeclarativeContext * parentContext() const
Return the context&#39;s parent QDeclarativeContext, or 0 if this context has no parent or if the parent ...
QDeclarativeComponentAttached ** prev
long ASN1_INTEGER_get ASN1_INTEGER * a
QObject * contextObject() const
Return the context object, or 0 if there is no context object.
void popContext()
Pops the current execution context and restores the previous one.
static int context_count(QDeclarativeListProperty< QObject > *)
QDeclarativeAbstractExpression * expressions
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
QDeclarativeContextData * linkedContext
QDeclarativeContextData * parent
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
static QDeclarativeEnginePrivate * get(QDeclarativeEngine *e)
friend class QDeclarativeContextData
bool isRelative() const
Returns true if the URL is relative; otherwise returns false.
Definition: qurl.cpp:5880
QDeclarativeTypeNameCache * imports
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
const QScriptValue & staticGlobalObject() const
void setContextObject(QObject *)
Set the context object.
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
The QScriptEngine class provides an environment for evaluating Qt Script code.
void setParent(QDeclarativeContextData *)
QDeclarativeContextPrivate * asQDeclarativeContextPrivate()
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QDeclarativeAbstractExpression * m_nextExpression
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
const char * name
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
Data * property(const QScriptDeclarativeClass::Identifier &id) const
QDeclarativeContextData * nextChild
Q_CORE_EXPORT void qWarning(const char *,...)
QDeclarativeContext * rootContext() const
Returns the engine&#39;s root context.
static const char * data(const QByteArray &arr)
QDeclarativeData * contextObjects
The QDeclarativeError class encapsulates a QML error.
QVariant contextProperty(const QString &) const
Returns the value of the name property for this context as a QVariant.
static QVariant fromValue(const T &value)
Returns a QVariant containing a copy of value.
Definition: qvariant.h:336
QDeclarativeContextData * m_context
Q_CORE_EXPORT int QT_FASTCALL script(uint ucs4)
QDeclarativeIntegerCache * propertyNames
void addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script)
QString findObjectId(const QObject *obj) const
void setContextProperty(const QString &, QObject *)
Set the value of the name property on this context.
static QDeclarativeContextPrivate * get(QDeclarativeContext *context)
bool isValid() const
Returns whether the context is valid.
static QScriptValue newStaticScopeObject(QScriptEngine *, int propertyCount, const QString *names, const QScriptValue *values, const QScriptValue::PropertyFlags *flags)
Creates a scope object with a fixed set of undeletable properties.
int userType() const
Returns the storage type of the value stored in the variant.
Definition: qvariant.cpp:1913
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the hash...
Definition: qhash.h:467
The QDeclarativeEngine class provides an environment for instantiating QML components.
QDeclarativeContextData ** prevChild
static void activate(QObject *sender, int signal_index, void **argv)
Definition: qobject.cpp:3690
QDeclarativeContext * asQDeclarativeContext()
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
const void * constData() const
Definition: qvariant.cpp:3065
if(void) toggleToolbarShown
QVariant read(const QObject *obj) const
Reads the property&#39;s value from the given object.
virtual ~QDeclarativeContext()
Destroys the QDeclarativeContext.
void add(const QString &, int)
The QDeclarativeContext class defines a context within a QML engine.
quint16 index
static void exceptionToError(QScriptEngine *, QDeclarativeError &)
QVariant property(const char *name) const
Returns the value of the object&#39;s name property.
Definition: qobject.cpp:3807
QDeclarativeEngine * engine() const
Return the context&#39;s QDeclarativeEngine, or 0 if the context has no QDeclarativeEngine or the QDeclar...
QObject * toQObject(const QVariant &, bool *ok=0) const
static QObject * context_at(QDeclarativeListProperty< QObject > *, int)
void setIdProperty(int, QObject *)
QDeclarativeData ** prevContextObject
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition: qhash.h:865
QDeclarativeData * nextContextObject
QDeclarativeCompiledBindings * optimizedBindings
QUrl resolved(const QUrl &relative) const
Returns the result of the merge of this URL with relative.
Definition: qurl.cpp:5819
bool isValid() const
Returns true if the storage type of this variant is not QVariant::Invalid; otherwise returns false...
Definition: qvariant.h:485
void pushScope(const QScriptValue &object)
Adds the given object to the front of this context&#39;s scope chain.
bool hasUncaughtException() const
Returns true if the last script evaluation resulted in an uncaught exception; otherwise returns false...
void warning(const QDeclarativeError &)
QList< QScriptValue > importedScripts
The QScriptValue class acts as a container for the Qt Script data types.
Definition: qscriptvalue.h:57
void setIdPropertyData(QDeclarativeIntegerCache *)
int methodCount() const
Returns the number of methods known to the meta-object system in this class, including the number of ...
QDeclarativeContext(QDeclarativeEngine *parent, QObject *objParent=0)
Create a new QDeclarativeContext as a child of engine&#39;s root context, and the QObject parent...
QDeclarativeGuardedContextData * contextGuards
static QScriptContext * pushCleanContext(QScriptEngine *)
Enters a new execution context and returns the associated QScriptContext object.
virtual const QMetaObject * metaObject() const
Returns a pointer to the meta-object of this object.
QMetaProperty property(int index) const
Returns the meta-data for the property with the given index.
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
QDeclarativeContextScriptClass * contextClass
QDeclarativeContextData * childContexts
static QDeclarativeContextData * get(QDeclarativeContext *context)