Loading

Paste #pjvfaojvh

  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.     qDebug() << "GET PROP" << id << *metaRole->name;
  276.  
  277.     // Keep track of the accessed roles
  278.     if (!(metaRole->flags & MetaProperty::Flags::READ)) {
  279.         d_ptr->m_pMetaType->used << metaRole;
  280.         //qDebug() << "\n NEW ROLE!" << (*metaRole->name) << d_ptr->m_pMetaType->used.size();
  281.     }
  282.  
  283.     metaRole->flags |= MetaProperty::Flags::READ;
  284.  
  285.     return index.data(metaRole->roleId);
  286. }
  287.  
  288. uint RoleGroup::size() const
  289. {
  290.     return d_ptr->m_pMetaType->roleCount;
  291. }
  292.  
  293. QByteArray RoleGroup::getPropertyName(uint id) const
  294. {
  295.     return *d_ptr->m_pMetaType->roles[id].name;
  296. }
  297.  
  298. const QMetaObject *DynamicContext::metaObject() const
  299. {
  300.     Q_ASSERT(m_pMetaType);
  301.     return m_pMetaType->m_pMetaObject;
  302. }
  303.  
  304. int DynamicContext::qt_metacall(QMetaObject::Call call, int id, void **argv)
  305. {
  306.     if (!m_Mutex.try_lock())
  307.         return -1;
  308.  
  309.  
  310.     const int realId = id - m_pMetaType->m_pMetaObject->propertyOffset();
  311.  
  312.     qDebug() << "HI" << id << realId << call << QMetaObject::ReadProperty;
  313.     if (realId < 0) {
  314.         m_Mutex.unlock();
  315.         return QObject::qt_metacall(call, id, argv);
  316.     }
  317.  
  318.     if (call == QMetaObject::ReadProperty) {
  319.         qDebug() << "HA";
  320.         if (Q_UNLIKELY(((size_t)realId) >= m_pMetaType->propertyCount)) {
  321.             Q_ASSERT(false);
  322.             m_Mutex.unlock();
  323.             return -1;
  324.         }
  325.  
  326.         const auto group = &m_pMetaType->m_lGroupMapping[realId];
  327.         Q_ASSERT(group->ptr);
  328.  
  329.         const QModelIndex idx = m_pBuilder->item() ? m_pBuilder->item()->index() : m_Index;
  330.  
  331.         const bool supportsCache = m_Cache &&
  332.             (m_pMetaType->m_pCacheMap[realId/8] & (1 << (realId % 8)));
  333.  
  334.         qDebug() << "OH" << m_lVariants[realId];
  335.  
  336.         // Use a special function for the role case. It's only known at runtime.
  337.         QVariant *value = m_lVariants[realId] && supportsCache
  338.             ? m_lVariants[realId] : new QVariant(
  339.                 group->ptr->getProperty(m_pBuilder->item(), realId - group->offset, idx));
  340.  
  341.         if (supportsCache && !m_lVariants[realId])
  342.             m_lVariants[realId] = value;
  343.  
  344.         QMetaType::construct(QMetaType::QVariant, argv[0], value->data());
  345.  
  346. //         if (!supportsCache)
  347. //             delete value;
  348.     }
  349.     else if (call == QMetaObject::WriteProperty) {
  350.         const QModelIndex idx = m_pBuilder->item() ? m_pBuilder->item()->index() : m_Index;
  351.         qDebug() << "SET" << argv[0];
  352. //         Q_ASSERT(false); //TODO call setData
  353. //         const int roleId = m_hIdMapper.value(realId);
  354. //         m_Index.model()->setData(
  355. //             m_Index, roleId, QVariant(property.typeId, argv[0])
  356. //         );
  357. //         m_lUsedProperties << roleId;
  358.         *reinterpret_cast<int*>(argv[2]) = 1;  // setProperty return value
  359.         QMetaObject::activate(this, m_pMetaType->m_pMetaObject, realId, nullptr);
  360.     }
  361.     else if (call == QMetaObject::InvokeMetaMethod) {
  362.         int sigId = id - m_pMetaType->m_pMetaObject->methodOffset();
  363.         qDebug() << "LA LA INVOKE" << sigId << id;
  364.         QMetaObject::activate(this,  m_pMetaType->m_pMetaObject, id, nullptr);
  365.         return -1;
  366.     }
  367.  
  368.     m_Mutex.unlock();
  369.  
  370.     return -1;
  371. }
  372.  
  373. void* DynamicContext::qt_metacast(const char *name)
  374. {
  375.     if (!strcmp(name, m_pMetaType->m_pMetaObject->className()))
  376.         return this;
  377.  
  378.     return QObject::qt_metacast(name);
  379. }
  380.  
  381. DynamicMetaType::DynamicMetaType(const QHash<int, QByteArray>& rls) :
  382. roleCount(rls.size())
  383. {}
  384.  
  385. /// Populate a vTable with the propertyId -> group object
  386. void ContextAdapterFactoryPrivate::initGroup(const QHash<int, QByteArray>& rls)
  387. {
  388.     Q_ASSERT(!m_pMetaType->m_GroupInit);
  389.  
  390.     for (auto group : qAsConst(m_lGroups))
  391.         m_pMetaType->propertyCount += group->size();
  392.  
  393.     m_pMetaType->m_lGroupMapping = (GroupMetaData*) malloc(
  394.         sizeof(GroupMetaData) * m_pMetaType->propertyCount
  395.     );
  396.  
  397.     uint offset(0), realId(0), groupId(0);
  398.  
  399.     for (auto group : qAsConst(m_lGroups)) {
  400.         Q_ASSERT(!group->d_ptr->d_ptr);
  401.         group->d_ptr->d_ptr    = this;
  402.         group->d_ptr->m_Offset = offset;
  403.         group->d_ptr->m_Id     = groupId++;
  404.  
  405.         const uint gs = group->size();
  406.  
  407.         for (uint i = 0; i < gs; i++)
  408.             m_pMetaType->m_lGroupMapping[offset+i] = {group, offset};
  409.  
  410.         offset += gs;
  411.     }
  412.     Q_ASSERT(offset == m_pMetaType->propertyCount);
  413.  
  414.     // Add a bitfield to store the properties that need to skip the cache
  415.     const int fieldSize = m_pMetaType->propertyCount / 8 + (m_pMetaType->propertyCount%8?1:0);
  416.     m_pMetaType->m_pCacheMap = (uint8_t*) malloc(fieldSize);
  417.     for (int i = 0; i < fieldSize; i++)
  418.         m_pMetaType->m_pCacheMap[i] = 0;
  419.  
  420.     m_pMetaType->m_GroupInit = true;
  421.  
  422.     // Create the metaobject
  423.     QMetaObjectBuilder builder;
  424.     builder.setClassName("DynamicContext");
  425.     builder.setSuperClass(&QObject::staticMetaObject);
  426.  
  427.     // Use a C array like the moc would do because this is called **A LOT**
  428.     m_pMetaType->roles = new MetaProperty[m_pMetaType->propertyCount];
  429.  
  430.     // Setup the role metadata
  431.     for (auto i = rls.constBegin(); i != rls.constEnd(); i++) {
  432.         uint id = realId++;
  433.         MetaProperty* r = &m_pMetaType->roles[id];
  434.  
  435.         r->roleId = i.key();
  436.         r->name   = new QByteArray(i.value());
  437.         r->flags |= MetaProperty::Flags::IS_ROLE;
  438.  
  439.         m_pMetaType->m_hRoleIds[i.key()] = r;
  440.     }
  441.  
  442.     realId = 0;
  443.  
  444.     // Add all object virtual properties
  445.     for (const auto g : qAsConst(m_lGroups)) {
  446.         for (uint j = 0; j < g->size(); j++) {
  447.             uint id = realId++;
  448.             Q_ASSERT(id < m_pMetaType->propertyCount);
  449.  
  450.             MetaProperty* r = &m_pMetaType->roles[id];
  451.             r->propId   = id;
  452.             const auto name = g->getPropertyName(j);
  453.  
  454.             auto property = builder.addProperty(name, "QVariant");
  455.             property.setWritable(true);
  456.  
  457.             auto signal = builder.addSignal(name + "Changed()");
  458.             r->signalId = signal.index();
  459.             property.setNotifySignal(signal);
  460.  
  461.             // Set the cache bit
  462.             m_pMetaType->m_pCacheMap[id/8] |= (g->supportCaching(j)?1:0) << (id % 8);
  463.         }
  464.     }
  465.  
  466.     m_pMetaType->m_pMetaObject = builder.toMetaObject();
  467. }
  468.  
  469. DynamicContext::DynamicContext(ContextAdapterFactory* cm) :
  470.     m_pMetaType(cm->d_ptr->m_pMetaType)
  471. {
  472.     Q_ASSERT(m_pMetaType);
  473.     Q_ASSERT(m_pMetaType->roleCount <= m_pMetaType->propertyCount);
  474.  
  475.     m_lVariants = (QVariant**) malloc(sizeof(QVariant*)*m_pMetaType->propertyCount);
  476.  
  477.     //TODO SIMD this
  478.     for (uint i = 0; i < m_pMetaType->propertyCount; i++)
  479.         m_lVariants[i] = nullptr;
  480. }
  481.  
  482. DynamicContext::~DynamicContext()
  483. {}
  484.  
  485. //FIXME delete the metatype now that it's invalid.
  486. //     if (m_pMetaType) {
  487. //         qDeleteAll(m_hContextMapper);
  488. //         m_hContextMapper.clear();
  489. //
  490. //         delete m_pMetaType;
  491. //         m_pMetaType = nullptr;
  492. //     }
  493.  
  494. bool ContextAdapter::updateRoles(const QVector<int> &modified) const
  495. {
  496.     qDebug() << "IN UPDATE ROLE"<< d_ptr->d_ptr->m_pMetaType;
  497.     if (!d_ptr->d_ptr->m_pMetaType)
  498.         return false;
  499.  
  500.     bool ret = false;
  501.  
  502.     if (!modified.isEmpty()) {
  503.         for (auto r : qAsConst(modified)) {
  504.             if (auto mr = d_ptr->d_ptr->m_pMetaType->m_hRoleIds.value(r)) {
  505.                 // This works because the role offset is always 0
  506.                 if (d_ptr->m_lVariants[mr->propId]) {
  507.                     delete d_ptr->m_lVariants[mr->propId];
  508.                     d_ptr->m_lVariants[mr->propId] = nullptr;
  509.                     QMetaMethod m = d_ptr->metaObject()->method(mr->signalId);
  510.                     m.invoke(d_ptr);
  511.                     ret |= ret;
  512.                 }
  513.             }
  514.         }
  515.     }
  516.     else {
  517.         // Only update the roles known to have an impact
  518.         for (auto mr : qAsConst(d_ptr->d_ptr->m_pMetaType->used)) {
  519.             //if (d_ptr->m_lVariants[mr->propId]) {
  520.                 if (auto v = d_ptr->m_lVariants[mr->propId])
  521.                     delete v;
  522.  
  523.                 d_ptr->m_lVariants[mr->propId] = nullptr;
  524.  
  525.                 auto mo = d_ptr->d_ptr->m_pMetaType->m_pMetaObject;
  526.  
  527.                 const int methodId = mo->methodOffset() + mr->signalId;
  528.  
  529.                 QMetaMethod m = mo->method(methodId);
  530.  
  531.                 //FIXME this should work, but it doesn't
  532.                 //m.invoke(d_ptr);
  533.  
  534.                 //FIXME this should also work, but also doesn't
  535.                 //QMetaObject::activate(d_ptr, mo, mr->signalId, nullptr);
  536.  
  537.                 //FIXME Use this for now, but it prevent setData from being implemented
  538.                 d_ptr->setProperty(*mr->name, 0x1337);
  539.  
  540.                 ret = true;
  541.             //}
  542.         }
  543.     }
  544.  
  545.     return ret;
  546. }
  547.  
  548. QAbstractItemModel *ContextAdapterFactory::model() const
  549. {
  550.     return d_ptr->m_pModel;
  551. }
  552.  
  553. void ContextAdapterFactory::setModel(QAbstractItemModel *m)
  554. {
  555.     d_ptr->m_pModel = m;
  556. }
  557.  
  558. void ContextAdapterFactoryPrivate::finish()
  559. {
  560.     Q_ASSERT(m_pModel);
  561.  
  562.     if (m_pMetaType)
  563.         return;
  564.  
  565.     const auto roles = m_pModel->roleNames();
  566.  
  567.     m_pMetaType = new DynamicMetaType(roles);
  568.     initGroup(roles);
  569. }
  570.  
  571. void ContextAdapterFactory::addContextExtension(ContextExtension* pg)
  572. {
  573.     Q_ASSERT(!d_ptr->m_pMetaType);
  574.  
  575.     if (d_ptr->m_pMetaType) {
  576.         qWarning() << "It is not possible to add property group after creating a builder";
  577.         return;
  578.     }
  579.  
  580.     d_ptr->m_lGroups << pg;
  581. }
  582.  
  583. QSet<QByteArray> ContextAdapterFactory::usedRoles() const
  584. {
  585.     if (!d_ptr->m_pMetaType)
  586.         return {};
  587.  
  588.     QSet<QByteArray> ret;
  589.  
  590.     for (const auto mr : qAsConst(d_ptr->m_pMetaType->used)) {
  591.         if (mr->roleId != -1)
  592.             ret << *mr->name;
  593.     }
  594.  
  595.     return ret;
  596. }
  597.  
  598. ContextAdapter*
  599. ContextAdapterFactory::createAdapter(FactoryFunctor f, QQmlContext *parentContext) const
  600. {
  601.     ContextAdapter* ret = f(parentContext);
  602.  
  603.     Q_ASSERT(!ret->d_ptr);
  604.  
  605.     d_ptr->finish();
  606.     ret->d_ptr = new DynamicContext(const_cast<ContextAdapterFactory*>(this));
  607.     ret->d_ptr->d_ptr = d_ptr;
  608.     ret->d_ptr->setParent(parentContext);
  609.     ret->d_ptr->m_pBuilder   = ret;
  610.     ret->d_ptr->m_pParentCtx = parentContext;
  611.  
  612.     //HACK QtQuick ignores
  613.     ret->d_ptr->m_Conn = QObject::connect(ret->d_ptr, &QObject::destroyed, ret->d_ptr, [ret, this, parentContext]() {
  614.         qWarning() << "Rebuilding the cache because QtQuick bugs trashed it";
  615.         ret->d_ptr = new DynamicContext(const_cast<ContextAdapterFactory*>(this));
  616.         ret->d_ptr->d_ptr = d_ptr;
  617.         ret->d_ptr->setParent(parentContext);
  618.         ret->d_ptr->m_pBuilder   = ret;
  619.         ret->d_ptr->m_pParentCtx = parentContext;
  620.     });
  621.  
  622.     return ret;
  623. }
  624.  
  625. ContextAdapter* ContextAdapterFactory::createAdapter(QQmlContext *parentContext) const
  626. {
  627.     return createAdapter(d_ptr->m_fFactory, parentContext);
  628. }
  629.  
  630. ContextAdapter::ContextAdapter(QQmlContext *parentContext)
  631. {
  632.     Q_UNUSED(parentContext)
  633. }
  634.  
  635. ContextAdapter::~ContextAdapter()
  636. {
  637.     if (d_ptr->m_pCtx)
  638.         d_ptr->m_pCtx->setContextObject(nullptr);
  639.  
  640.     QObject::disconnect(d_ptr->m_Conn);
  641.  
  642.     d_ptr->m_pBuilder = nullptr;
  643.  
  644.     delete d_ptr;
  645. }
  646.  
  647. bool ContextAdapter::isCacheEnabled() const
  648. {
  649.     return d_ptr->m_Cache;
  650. }
  651.  
  652. void ContextAdapter::setCacheEnabled(bool v)
  653. {
  654.     d_ptr->m_Cache = v;
  655. }
  656.  
  657. QModelIndex ContextAdapter::index() const
  658. {
  659.     return d_ptr->m_Index;
  660. }
  661.  
  662. void ContextAdapter::setModelIndex(const QModelIndex& index)
  663. {
  664.     d_ptr->m_Index = index;
  665. }
  666.  
  667. QQmlContext* ContextAdapter::context() const
  668. {
  669.     Q_ASSERT(d_ptr);
  670.  
  671.     if (!d_ptr->m_pCtx) {
  672.         d_ptr->m_pCtx = new QQmlContext(d_ptr->m_pParentCtx, d_ptr->parent());
  673.         d_ptr->m_pCtx->setContextObject(d_ptr);
  674.         d_ptr->m_pCtx->engine()->setObjectOwnership(
  675.             d_ptr, QQmlEngine::CppOwnership
  676.         );
  677.         d_ptr->m_pCtx->engine()->setObjectOwnership(
  678.             d_ptr->m_pCtx, QQmlEngine::CppOwnership
  679.         );
  680.     }
  681.  
  682.     return d_ptr->m_pCtx;
  683. }
  684.  
  685. QObject *ContextAdapter::contextObject() const
  686. {
  687.     return d_ptr;
  688. }
  689.  
  690. bool ContextAdapter::isActive() const
  691. {
  692.     return d_ptr->m_pCtx;
  693. }
  694.  
  695. AbstractItemAdapter* ContextAdapter::item() const
  696. {
  697.     return nullptr;
  698. }
  699.  
  700. ContextExtension::ContextExtension() : d_ptr(new ContextExtensionPrivate())
  701. {}

Comments