Loading

Paste #pcozh1ztv

  1. /***************************************************************************
  2.  *   Copyright (C) 2018 by Bluesystems                                     *
  3.  *   Author : Emmanuel Lepage Vallee <elv1313@gmail.com>                   *
  4.  *                                                                         *
  5.  *   This program is free software; you can redistribute it and/or modify  *
  6.  *   it under the terms of the GNU General Public License as published by  *
  7.  *   the Free Software Foundation; either version 3 of the License, or     *
  8.  *   (at your option) any later version.                                   *
  9.  *                                                                         *
  10.  *   This program is distributed in the hope that it will be useful,       *
  11.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
  12.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
  13.  *   GNU General Public License for more details.                          *
  14.  *                                                                         *
  15.  *   You should have received a copy of the GNU General Public License     *
  16.  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  17.  **************************************************************************/
  18. #include "contextadapterfactory.h"
  19.  
  20. // Qt
  21. #include <QtCore/QAbstractItemModel>
  22. #include <QtCore/QMutex>
  23. #include <QtCore/private/qmetaobjectbuilder_p.h>
  24. #include <QQmlContext>
  25. #include <QQuickItem>
  26. #include <QQmlEngine>
  27.  
  28. // KQuickItemViews
  29. #include "adapters/abstractitemadapter.h"
  30. #include "viewbase.h"
  31. #include "viewport.h"
  32. #include "private/viewport_p.h"
  33. #include "private/indexmetadata_p.h"
  34. #include "extensions/contextextension.h"
  35. #include "adapters/modeladapter.h"
  36. #include "private/statetracker/viewitem_p.h"
  37. #include "adapters/contextadapter.h"
  38.  
  39. using FactoryFunctor = std::function<ContextAdapter*(QQmlContext*)>;
  40.  
  41. /**
  42.  * Add some metadata to be able to use QAbstractItemModel roles as QObject
  43.  * properties.
  44.  */
  45. struct MetaProperty
  46. {
  47.     // Bitmask to hold (future) metadata regarding how the property is used
  48.     // by QML.
  49.     enum Flags : int {
  50.         UNUSED      = 0x0 << 0, /*!< This property was never used          */
  51.         READ        = 0x1 << 0, /*!< If data() was ever called             */
  52.         HAS_DATA    = 0x1 << 1, /*!< When the QVariant is valid            */
  53.         TRIED_WRITE = 0x1 << 2, /*!< When setData returns false            */
  54.         HAS_WRITTEN = 0x1 << 3, /*!< When setData returns true             */
  55.         HAS_CHANGED = 0x1 << 4, /*!< When the value was queried many times */
  56.         HAS_SUBSET  = 0x1 << 5, /*!< When dataChanged has a role list      */
  57.         HAS_GLOBAL  = 0x1 << 6, /*!< When dataChanged has no role          */
  58.         IS_ROLE     = 0x1 << 7, /*!< When the MetaProperty map to a model role */
  59.     };
  60.     int flags {Flags::UNUSED};
  61.  
  62.     /// Q_PROPERTY internal id
  63.     int propId;
  64.  
  65.     /// The role ID from QAbstractItemModel::roleNames
  66.     int roleId {-1};
  67.  
  68.     /**
  69.      * The name ID from QAbstractItemModel::roleNames
  70.      *
  71.      * (the pointer *is* on purpose reduce cache faults in this hot code path)
  72.      */
  73.     QByteArray* name {nullptr};
  74.  
  75.     uint signalId;
  76. };
  77.  
  78. struct GroupMetaData
  79. {
  80.     ContextExtension* ptr;
  81.     uint offset;
  82. };
  83.  
  84. /**
  85.  * Keep the offset and id of the extension for validation and change notification.
  86.  */
  87. class ContextExtensionPrivate
  88. {
  89. public:
  90.     uint m_Id     {0};
  91.     uint m_Offset {0};
  92.     ContextAdapterFactoryPrivate *d_ptr {nullptr};
  93. };
  94.  
  95. /**
  96.  * This struct is the internal representation normally built by the Qt MOC
  97.  * generator.
  98.  *
  99.  * It holds a "fake" type of QObject designed to reflect the model roles as
  100.  * QObject properties. It also tracks the property being *used* by QML to
  101.  * prevent too many events being pushed into the QML context.
  102.  */
  103. struct DynamicMetaType final
  104. {
  105.     explicit DynamicMetaType(const QHash<int, QByteArray>& roles);
  106.     ~DynamicMetaType() {
  107.         delete[] roles;//FIXME leak [roleCount*sizeof(MetaProperty))];
  108.     }
  109.  
  110.     const size_t              roleCount     {   0   };
  111.     size_t                    propertyCount {   0   };
  112.     MetaProperty*             roles         {nullptr};
  113.     QSet<MetaProperty*>       used          {       };
  114.     QMetaObject              *m_pMetaObject {nullptr};
  115.     bool                      m_GroupInit   { false };
  116.     QHash<int, MetaProperty*> m_hRoleIds    {       };
  117.     uint8_t                  *m_pCacheMap   {nullptr};
  118.  
  119.     /**
  120.      * Assuming the number of role is never *that* high, keep a jump map to
  121.      * prevent doing dispatch vTable when checking the properties source.
  122.      *
  123.      * In theory it can be changed at runtime if the need arise, but for now
  124.      * its static. Better harden the binaries a bit, having call maps on the
  125.      * heap isn't the most secure scheme in the universe.
  126.      */
  127.     GroupMetaData* m_lGroupMapping {nullptr};
  128. };
  129.  
  130. class DynamicContext final : public QObject
  131. {
  132. public:
  133.     explicit DynamicContext(ContextAdapterFactory* mt);
  134.     virtual ~DynamicContext();
  135.  
  136.     // Some "secret" QObject methods.
  137.     virtual int qt_metacall(QMetaObject::Call call, int id, void **argv) override;
  138.     virtual void* qt_metacast(const char *name) override;
  139.     virtual const QMetaObject *metaObject() const override;
  140.  
  141.     // Use a C array to prevent the array bound checks
  142.     QVariant              **m_lVariants {nullptr};
  143.     DynamicMetaType       * m_pMetaType {nullptr};
  144.     bool                    m_Cache     { true  };
  145.     QQmlContext           * m_pCtx      {nullptr};
  146.     QPersistentModelIndex   m_Index     {       };
  147.     QQmlContext           * m_pParentCtx{nullptr};
  148.     QMetaObject::Connection m_Conn;
  149.     QMutex                  m_Mutex;
  150.  
  151.     ContextAdapterFactoryPrivate* d_ptr {nullptr};
  152.     ContextAdapter* m_pBuilder;
  153. };
  154.  
  155. class ContextAdapterFactoryPrivate
  156. {
  157. public:
  158.     // Attributes
  159.     QList<ContextExtension*>  m_lGroups   {       };
  160.     mutable DynamicMetaType  *m_pMetaType {nullptr};
  161.     QAbstractItemModel       *m_pModel    {nullptr};
  162.  
  163.     FactoryFunctor m_fFactory;
  164.  
  165.     // Helper
  166.     void initGroup(const QHash<int, QByteArray>& rls);
  167.     void finish();
  168.  
  169.     ContextAdapterFactory* q_ptr;
  170. };
  171.  
  172. /**
  173.  * Create a group of virtual Q_PROPERTY to match the model role names.
  174.  */
  175. class RoleGroup final : public ContextExtension
  176. {
  177. public:
  178.     explicit RoleGroup(ContextAdapterFactoryPrivate* d) : d_ptr(d) {}
  179.  
  180.     // The implementation isn't necessary in this case given it uses a second
  181.     // layer of vTable instead of a static list. It goes against the
  182.     // documentation, but that's on purpose.
  183.     virtual QVariant getProperty(AbstractItemAdapter* item, uint id, const QModelIndex& index) const override;
  184.     virtual uint size() const override;
  185.     virtual QByteArray getPropertyName(uint id) const override;
  186.  
  187.     ContextAdapterFactoryPrivate* d_ptr;
  188. };
  189.  
  190. ContextAdapterFactory::ContextAdapterFactory(FactoryFunctor f) : d_ptr(new ContextAdapterFactoryPrivate())
  191. {
  192.     d_ptr->q_ptr = this;
  193.     d_ptr->m_fFactory = f;
  194.  
  195.     addContextExtension(new RoleGroup(d_ptr));
  196. }
  197.  
  198. ContextAdapterFactory::~ContextAdapterFactory()
  199. {
  200.     delete d_ptr;
  201. }
  202.  
  203. uint ContextExtension::size() const
  204. {
  205.     return propertyNames().size();
  206. }
  207.  
  208. bool ContextExtension::supportCaching(uint id) const
  209. {
  210.     Q_UNUSED(id)
  211.     return true;
  212. }
  213.  
  214. QVector<QByteArray>& ContextExtension::propertyNames() const
  215. {
  216.     static QVector<QByteArray> r;
  217.     return r;
  218. }
  219.  
  220. QByteArray ContextExtension::getPropertyName(uint id) const
  221. {
  222.     return propertyNames()[id];
  223. }
  224.  
  225. void ContextExtension::setProperty(AbstractItemAdapter* item, uint id, const QVariant& value) const
  226. {
  227.     Q_UNUSED(item)
  228.     Q_UNUSED(id)
  229.     Q_UNUSED(value)
  230. }
  231.  
  232. void ContextExtension::changeProperty(AbstractItemAdapter* item, uint id)
  233. {
  234.     Q_UNUSED(item)
  235.     Q_UNUSED(id)
  236.     Q_ASSERT(false);
  237. /*
  238.     const auto metaRole = &d_ptr->d_ptr->m_pMetaType->roles[id];
  239.     Q_ASSERT(metaRole);
  240.  
  241.     auto mo = d_ptr->d_ptr->m_pMetaType->m_pMetaObject;
  242.  
  243.     index()*/
  244. }
  245.  
  246. void ContextAdapter::flushCache()
  247. {
  248.     for (uint i = 0; i < d_ptr->m_pMetaType->propertyCount; i++) {
  249.         if (d_ptr->m_lVariants[i])
  250.             delete d_ptr->m_lVariants[i];
  251.  
  252.         d_ptr->m_lVariants[i] = nullptr;
  253.     }
  254. }
  255.  
  256. void AbstractItemAdapter::dismissCacheEntry(ContextExtension* e, int id)
  257. {
  258.     auto dx = s_ptr->m_pMetadata->contextAdapter()->d_ptr;
  259.     if (!dx)
  260.         return;
  261.  
  262.     Q_ASSERT(e);
  263.     Q_ASSERT(e->d_ptr->d_ptr->q_ptr == viewport()->modelAdapter()->contextAdapterFactory());
  264.     Q_ASSERT(e->d_ptr->d_ptr->m_lGroups[e->d_ptr->m_Id] == e);
  265.     Q_ASSERT(id >= 0 && id < e->size());
  266.  
  267.     dx->m_lVariants[e->d_ptr->m_Offset + id] = nullptr;
  268. }
  269.  
  270. QVariant RoleGroup::getProperty(AbstractItemAdapter* item, uint id, const QModelIndex& index) const
  271. {
  272.     Q_UNUSED(item)
  273.     const auto metaRole = &d_ptr->m_pMetaType->roles[id];
  274.  
  275.     // Keep track of the accessed roles
  276.     if (!(metaRole->flags & MetaProperty::Flags::READ)) {
  277.         d_ptr->m_pMetaType->used << metaRole;
  278.         //qDebug() << "\n NEW ROLE!" << (*metaRole->name) << d_ptr->m_pMetaType->used.size();
  279.     }
  280.  
  281.     metaRole->flags |= MetaProperty::Flags::READ;
  282.  
  283.     return index.data(metaRole->roleId);
  284. }
  285.  
  286. uint RoleGroup::size() const
  287. {
  288.     return d_ptr->m_pMetaType->roleCount;
  289. }
  290.  
  291. QByteArray RoleGroup::getPropertyName(uint id) const
  292. {
  293.     return *d_ptr->m_pMetaType->roles[id].name;
  294. }
  295.  
  296. const QMetaObject *DynamicContext::metaObject() const
  297. {
  298.     Q_ASSERT(m_pMetaType);
  299.     return m_pMetaType->m_pMetaObject;
  300. }
  301.  
  302. int DynamicContext::qt_metacall(QMetaObject::Call call, int id, void **argv)
  303. {
  304.     if (!m_Mutex.try_lock())
  305.         return -1;
  306.  
  307.  
  308.     const int realId = id - m_pMetaType->m_pMetaObject->propertyOffset();
  309.  
  310.     qDebug() << "META" << id << realId << call << QMetaObject::ReadProperty;
  311.     if (realId < 0) {
  312.         m_Mutex.unlock();
  313.         return QObject::qt_metacall(call, id, argv);
  314.     }
  315.  
  316.     if (call == QMetaObject::ReadProperty) {
  317.         if (Q_UNLIKELY(((size_t)realId) >= m_pMetaType->propertyCount)) {
  318.             Q_ASSERT(false);
  319.             m_Mutex.unlock();
  320.             return -1;
  321.         }
  322.  
  323.         const auto group = &m_pMetaType->m_lGroupMapping[realId];
  324.         Q_ASSERT(group->ptr);
  325.  
  326.         const QModelIndex idx = m_pBuilder->item() ? m_pBuilder->item()->index() : m_Index;
  327.  
  328.         const bool supportsCache = m_Cache &&
  329.             (m_pMetaType->m_pCacheMap[realId/8] & (1 << (realId % 8)));
  330.  
  331.         // Use a special function for the role case. It's only known at runtime.
  332.         QVariant *value = m_lVariants[realId] && supportsCache
  333.             ? m_lVariants[realId] : new QVariant(
  334.                 group->ptr->getProperty(m_pBuilder->item(), realId - group->offset, idx));
  335.  
  336.         if (supportsCache && !m_lVariants[realId])
  337.             m_lVariants[realId] = value;
  338.  
  339.         QMetaType::construct(QMetaType::QVariant, argv[0], value->data());
  340.  
  341. //         if (!supportsCache)
  342. //             delete value;
  343.     }
  344.     else if (call == QMetaObject::WriteProperty) {
  345.         qDebug() << "SET" << argv[0];
  346.  
  347.         //FIXME enable setData
  348.         //const QModelIndex idx = m_pBuilder->item() ? m_pBuilder->item()->index() : m_Index;
  349.         //Q_ASSERT(false); //TODO call setData
  350.         //const int roleId = m_hIdMapper.value(realId);
  351.         //m_Index.model()->setData(
  352.         //    m_Index, roleId, QVariant(property.typeId, argv[0])
  353.         //);
  354.         //m_lUsedProperties << roleId;
  355.  
  356.         *reinterpret_cast<int*>(argv[2]) = 1;  // setProperty return value
  357.         QMetaObject::activate(this, m_pMetaType->m_pMetaObject, realId, nullptr);
  358.     }
  359.     else if (call == QMetaObject::InvokeMetaMethod) {
  360.         int sigId = id - m_pMetaType->m_pMetaObject->methodOffset();
  361.         qDebug() << "LA LA INVOKE" << sigId << id;
  362.         QMetaObject::activate(this,  m_pMetaType->m_pMetaObject, id, nullptr);
  363.         return -1;
  364.     }
  365.  
  366.     m_Mutex.unlock();
  367.  
  368.     return -1;
  369. }
  370.  
  371. void* DynamicContext::qt_metacast(const char *name)
  372. {
  373.     if (!strcmp(name, m_pMetaType->m_pMetaObject->className()))
  374.         return this;
  375.  
  376.     return QObject::qt_metacast(name);
  377. }
  378.  
  379. DynamicMetaType::DynamicMetaType(const QHash<int, QByteArray>& rls) :
  380. roleCount(rls.size())
  381. {}
  382.  
  383. /// Populate a vTable with the propertyId -> group object
  384. void ContextAdapterFactoryPrivate::initGroup(const QHash<int, QByteArray>& rls)
  385. {
  386.     Q_ASSERT(!m_pMetaType->m_GroupInit);
  387.  
  388.     for (auto group : qAsConst(m_lGroups))
  389.         m_pMetaType->propertyCount += group->size();
  390.  
  391.     m_pMetaType->m_lGroupMapping = (GroupMetaData*) malloc(
  392.         sizeof(GroupMetaData) * m_pMetaType->propertyCount
  393.     );
  394.  
  395.     uint offset(0), realId(0), groupId(0);
  396.  
  397.     for (auto group : qAsConst(m_lGroups)) {
  398.         Q_ASSERT(!group->d_ptr->d_ptr);
  399.         group->d_ptr->d_ptr    = this;
  400.         group->d_ptr->m_Offset = offset;
  401.         group->d_ptr->m_Id     = groupId++;
  402.  
  403.         const uint gs = group->size();
  404.  
  405.         for (uint i = 0; i < gs; i++)
  406.             m_pMetaType->m_lGroupMapping[offset+i] = {group, offset};
  407.  
  408.         offset += gs;
  409.     }
  410.     Q_ASSERT(offset == m_pMetaType->propertyCount);
  411.  
  412.     // Add a bitfield to store the properties that need to skip the cache
  413.     const int fieldSize = m_pMetaType->propertyCount / 8 + (m_pMetaType->propertyCount%8?1:0);
  414.     m_pMetaType->m_pCacheMap = (uint8_t*) malloc(fieldSize);
  415.     for (int i = 0; i < fieldSize; i++)
  416.         m_pMetaType->m_pCacheMap[i] = 0;
  417.  
  418.     m_pMetaType->m_GroupInit = true;
  419.  
  420.     // Create the metaobject
  421.     QMetaObjectBuilder builder;
  422.     builder.setClassName("DynamicContext");
  423.     builder.setSuperClass(&QObject::staticMetaObject);
  424.  
  425.     // Use a C array like the moc would do because this is called **A LOT**
  426.     m_pMetaType->roles = new MetaProperty[m_pMetaType->propertyCount];
  427.  
  428.     // Setup the role metadata
  429.     for (auto i = rls.constBegin(); i != rls.constEnd(); i++) {
  430.         uint id = realId++;
  431.         MetaProperty* r = &m_pMetaType->roles[id];
  432.  
  433.         r->roleId = i.key();
  434.         r->name   = new QByteArray(i.value());
  435.         r->flags |= MetaProperty::Flags::IS_ROLE;
  436.  
  437.         m_pMetaType->m_hRoleIds[i.key()] = r;
  438.     }
  439.  
  440.     realId = 0;
  441.  
  442.     // Add all object virtual properties
  443.     for (const auto g : qAsConst(m_lGroups)) {
  444.         for (uint j = 0; j < g->size(); j++) {
  445.             uint id = realId++;
  446.             Q_ASSERT(id < m_pMetaType->propertyCount);
  447.  
  448.             MetaProperty* r = &m_pMetaType->roles[id];
  449.             r->propId   = id;
  450.             const auto name = g->getPropertyName(j);
  451.  
  452.             auto property = builder.addProperty(name, "QVariant");
  453.             property.setWritable(true);
  454.  
  455.             auto signal = builder.addSignal(name + "Changed()");
  456.             r->signalId = signal.index();
  457.             property.setNotifySignal(signal);
  458.  
  459.             // Set the cache bit
  460.             m_pMetaType->m_pCacheMap[id/8] |= (g->supportCaching(j)?1:0) << (id % 8);
  461.         }
  462.     }
  463.  
  464.     m_pMetaType->m_pMetaObject = builder.toMetaObject();
  465. }
  466.  
  467. DynamicContext::DynamicContext(ContextAdapterFactory* cm) :
  468.     m_pMetaType(cm->d_ptr->m_pMetaType)
  469. {
  470.     Q_ASSERT(m_pMetaType);
  471.     Q_ASSERT(m_pMetaType->roleCount <= m_pMetaType->propertyCount);
  472.  
  473.     m_lVariants = (QVariant**) malloc(sizeof(QVariant*)*m_pMetaType->propertyCount);
  474.  
  475.     //TODO SIMD this
  476.     for (uint i = 0; i < m_pMetaType->propertyCount; i++)
  477.         m_lVariants[i] = nullptr;
  478. }
  479.  
  480. DynamicContext::~DynamicContext()
  481. {}
  482.  
  483. //FIXME delete the metatype now that it's invalid.
  484. //     if (m_pMetaType) {
  485. //         qDeleteAll(m_hContextMapper);
  486. //         m_hContextMapper.clear();
  487. //
  488. //         delete m_pMetaType;
  489. //         m_pMetaType = nullptr;
  490. //     }
  491.  
  492. bool ContextAdapter::updateRoles(const QVector<int> &modified) const
  493. {
  494.     qDebug() << "IN UPDATE ROLE"<< d_ptr->d_ptr->m_pMetaType;
  495.     if (!d_ptr->d_ptr->m_pMetaType)
  496.         return false;
  497.  
  498.     bool ret = false;
  499.  
  500.     if (!modified.isEmpty()) {
  501.         for (auto r : qAsConst(modified)) {
  502.             if (auto mr = d_ptr->d_ptr->m_pMetaType->m_hRoleIds.value(r)) {
  503.                 // This works because the role offset is always 0
  504.                 if (d_ptr->m_lVariants[mr->propId]) {
  505.                     delete d_ptr->m_lVariants[mr->propId];
  506.                     d_ptr->m_lVariants[mr->propId] = nullptr;
  507.                     QMetaMethod m = d_ptr->metaObject()->method(mr->signalId);
  508.                     m.invoke(d_ptr);
  509.                     ret |= ret;
  510.                 }
  511.             }
  512.         }
  513.     }
  514.     else {
  515.         // Only update the roles known to have an impact
  516.         for (auto mr : qAsConst(d_ptr->d_ptr->m_pMetaType->used)) {
  517.             if (d_ptr->m_lVariants[mr->propId]) {
  518.                 if (auto v = d_ptr->m_lVariants[mr->propId])
  519.                     delete v;
  520.  
  521.                 d_ptr->m_lVariants[mr->propId] = nullptr;
  522.  
  523.                 //FIXME this should work, but it doesn't
  524.                 auto mo = d_ptr->d_ptr->m_pMetaType->m_pMetaObject;
  525.                 const int methodId = mo->methodOffset() + mr->signalId;
  526.                 QMetaMethod m = mo->method(methodId);
  527.                 //m.invoke(d_ptr);
  528.                 Q_ASSERT(m.name() == (*mr->name)+"Changed");
  529.  
  530.                 //FIXME this should also work, but also doesn't
  531.                 //QMetaObject::activate(d_ptr, mo, mr->signalId, nullptr);
  532.  
  533.                 //FIXME Use this for now, but it prevent setData from being implemented
  534.                 d_ptr->setProperty(*mr->name, 0x1337);
  535.  
  536.                 QMetaObject::activate(d_ptr, mo, mr->signalId, nullptr);
  537.  
  538.                 ret = true;
  539.             }
  540.         }
  541.     }
  542.  
  543.     return ret;
  544. }
  545.  
  546. QAbstractItemModel *ContextAdapterFactory::model() const
  547. {
  548.     return d_ptr->m_pModel;
  549. }
  550.  
  551. void ContextAdapterFactory::setModel(QAbstractItemModel *m)
  552. {
  553.     d_ptr->m_pModel = m;
  554. }
  555.  
  556. void ContextAdapterFactoryPrivate::finish()
  557. {
  558.     Q_ASSERT(m_pModel);
  559.  
  560.     if (m_pMetaType)
  561.         return;
  562.  
  563.     const auto roles = m_pModel->roleNames();
  564.  
  565.     m_pMetaType = new DynamicMetaType(roles);
  566.     initGroup(roles);
  567. }
  568.  
  569. void ContextAdapterFactory::addContextExtension(ContextExtension* pg)
  570. {
  571.     Q_ASSERT(!d_ptr->m_pMetaType);
  572.  
  573.     if (d_ptr->m_pMetaType) {
  574.         qWarning() << "It is not possible to add property group after creating a builder";
  575.         return;
  576.     }
  577.  
  578.     d_ptr->m_lGroups << pg;
  579. }
  580.  
  581. QSet<QByteArray> ContextAdapterFactory::usedRoles() const
  582. {
  583.     if (!d_ptr->m_pMetaType)
  584.         return {};
  585.  
  586.     QSet<QByteArray> ret;
  587.  
  588.     for (const auto mr : qAsConst(d_ptr->m_pMetaType->used)) {
  589.         if (mr->roleId != -1)
  590.             ret << *mr->name;
  591.     }
  592.  
  593.     return ret;
  594. }
  595.  
  596. ContextAdapter*
  597. ContextAdapterFactory::createAdapter(FactoryFunctor f, QQmlContext *parentContext) const
  598. {
  599.     ContextAdapter* ret = f(parentContext);
  600.  
  601.     Q_ASSERT(!ret->d_ptr);
  602.  
  603.     d_ptr->finish();
  604.     ret->d_ptr = new DynamicContext(const_cast<ContextAdapterFactory*>(this));
  605.     ret->d_ptr->d_ptr = d_ptr;
  606.     ret->d_ptr->setParent(parentContext);
  607.     ret->d_ptr->m_pBuilder   = ret;
  608.     ret->d_ptr->m_pParentCtx = parentContext;
  609.  
  610.     //HACK QtQuick ignores
  611.     ret->d_ptr->m_Conn = QObject::connect(ret->d_ptr, &QObject::destroyed, ret->d_ptr, [ret, this, parentContext]() {
  612.         qWarning() << "Rebuilding the cache because QtQuick bugs trashed it";
  613.         ret->d_ptr = new DynamicContext(const_cast<ContextAdapterFactory*>(this));
  614.         ret->d_ptr->d_ptr = d_ptr;
  615.         ret->d_ptr->setParent(parentContext);
  616.         ret->d_ptr->m_pBuilder   = ret;
  617.         ret->d_ptr->m_pParentCtx = parentContext;
  618.     });
  619.  
  620.     return ret;
  621. }
  622.  
  623. ContextAdapter* ContextAdapterFactory::createAdapter(QQmlContext *parentContext) const
  624. {
  625.     return createAdapter(d_ptr->m_fFactory, parentContext);
  626. }
  627.  
  628. ContextAdapter::ContextAdapter(QQmlContext *parentContext)
  629. {
  630.     Q_UNUSED(parentContext)
  631. }
  632.  
  633. ContextAdapter::~ContextAdapter()
  634. {
  635.     if (d_ptr->m_pCtx)
  636.         d_ptr->m_pCtx->setContextObject(nullptr);
  637.  
  638.     QObject::disconnect(d_ptr->m_Conn);
  639.  
  640.     d_ptr->m_pBuilder = nullptr;
  641.  
  642.     delete d_ptr;
  643. }
  644.  
  645. bool ContextAdapter::isCacheEnabled() const
  646. {
  647.     return d_ptr->m_Cache;
  648. }
  649.  
  650. void ContextAdapter::setCacheEnabled(bool v)
  651. {
  652.     d_ptr->m_Cache = v;
  653. }
  654.  
  655. QModelIndex ContextAdapter::index() const
  656. {
  657.     return d_ptr->m_Index;
  658. }
  659.  
  660. void ContextAdapter::setModelIndex(const QModelIndex& index)
  661. {
  662.     d_ptr->m_Index = index;
  663. }
  664.  
  665. QQmlContext* ContextAdapter::context() const
  666. {
  667.     Q_ASSERT(d_ptr);
  668.  
  669.     if (!d_ptr->m_pCtx) {
  670.         d_ptr->m_pCtx = new QQmlContext(d_ptr->m_pParentCtx, d_ptr->parent());
  671.         d_ptr->m_pCtx->setContextObject(d_ptr);
  672.         d_ptr->m_pCtx->engine()->setObjectOwnership(
  673.             d_ptr, QQmlEngine::CppOwnership
  674.         );
  675.         d_ptr->m_pCtx->engine()->setObjectOwnership(
  676.             d_ptr->m_pCtx, QQmlEngine::CppOwnership
  677.         );
  678.     }
  679.  
  680.     return d_ptr->m_pCtx;
  681. }
  682.  
  683. QObject *ContextAdapter::contextObject() const
  684. {
  685.     return d_ptr;
  686. }
  687.  
  688. bool ContextAdapter::isActive() const
  689. {
  690.     return d_ptr->m_pCtx;
  691. }
  692.  
  693. AbstractItemAdapter* ContextAdapter::item() const
  694. {
  695.     return nullptr;
  696. }
  697.  
  698. ContextExtension::ContextExtension() : d_ptr(new ContextExtensionPrivate())
  699. {}

Comments