void RemoteModelServer::newRequest(const GammaRay::Message &msg)
{
  if (!m_model && msg.type() != Protocol::ModelSyncBarrier)
    return;

  switch (msg.type()) {
    case Protocol::ModelRowColumnCountRequest:
    {
      Protocol::ModelIndex index;
      msg.payload() >> index;
      const QModelIndex qmIndex = Protocol::toQModelIndex(m_model, index);

      Message msg(m_myAddress, Protocol::ModelRowColumnCountReply);
      msg.payload() << index << m_model->rowCount(qmIndex) << m_model->columnCount(qmIndex);
      Server::send(msg);
      break;
    }

    case Protocol::ModelContentRequest:
    {
      Protocol::ModelIndex index;
      msg.payload() >> index;
      const QModelIndex qmIndex = Protocol::toQModelIndex(m_model, index);
      if (!qmIndex.isValid())
        break;

      Message msg(m_myAddress, Protocol::ModelContentReply);
      msg.payload() << index << filterItemData(m_model->itemData(qmIndex)) << qint32(m_model->flags(qmIndex));
      Server::send(msg);
      break;
    }

    case Protocol::ModelHeaderRequest:
    {
      qint8 orientation;
      qint32 section;
      msg.payload() >> orientation >> section;
      Q_ASSERT(orientation == Qt::Horizontal || orientation == Qt::Vertical);
      Q_ASSERT(section >= 0);

      QHash<qint32, QVariant> data;
      // TODO: add all roles
      data.insert(Qt::DisplayRole, m_model->headerData(section, static_cast<Qt::Orientation>(orientation), Qt::DisplayRole));
      data.insert(Qt::ToolTipRole, m_model->headerData(section, static_cast<Qt::Orientation>(orientation), Qt::ToolTipRole));

      Message msg(m_myAddress, Protocol::ModelHeaderReply);
      msg.payload() << orientation << section << data;
      Server::send(msg);
      break;
    }

    case Protocol::ModelSetDataRequest:
    {
      Protocol::ModelIndex index;
      int role;
      QVariant value;
      msg.payload() >> index >> role >> value;

      m_model->setData(Protocol::toQModelIndex(m_model, index), value, role);
      break;
    }

    case Protocol::ModelSyncBarrier:
    {
      qint32 barrierId;
      msg.payload() >> barrierId;
      Message reply(m_myAddress, Protocol::ModelSyncBarrier);
      reply.payload() << barrierId;
      Server::send(reply);
      break;
    }
  }
}
void PropertySyncer::handleMessage(const GammaRay::Message& msg)
{
    Q_ASSERT(msg.address() == m_address);
    switch (msg.type()) {
    case Protocol::PropertySyncRequest:
    {
        Protocol::ObjectAddress addr;
        msg.payload() >> addr;
        Q_ASSERT(addr != Protocol::InvalidObjectAddress);

        const auto it = std::find_if(m_objects.constBegin(), m_objects.constEnd(), [addr](const ObjectInfo &info) {
            return info.addr == addr;
        });
        if (it == m_objects.constEnd())
            break;

        QVector<QPair<QString, QVariant> > values;
        const auto propCount = (*it).obj->metaObject()->propertyCount();
        values.reserve(propCount);
        for (int i = qobjectPropertyOffset(); i < propCount; ++i) {
            const auto prop = (*it).obj->metaObject()->property(i);
            values.push_back(qMakePair(QString(prop.name()), prop.read((*it).obj)));
        }
        Q_ASSERT(!values.isEmpty());

        Message msg(m_address, Protocol::PropertyValuesChanged);
        msg.payload() << addr << (quint32)values.size();
        foreach (const auto &value, values)
            msg.payload() << value.first << value.second;
        emit message(msg);
        break;
    }
    case Protocol::PropertyValuesChanged:
    {
        Protocol::ObjectAddress addr;
        quint32 changeSize;
        msg.payload() >> addr >> changeSize;
        Q_ASSERT(addr != Protocol::InvalidObjectAddress);
        Q_ASSERT(changeSize > 0);

        auto it = std::find_if(m_objects.begin(), m_objects.end(), [addr](const ObjectInfo &info) {
            return info.addr == addr;
        });
        if (it == m_objects.end())
            break;

        for (quint32 i = 0; i < changeSize; ++i) {
            QString propName;
            QVariant propValue;
            msg.payload() >> propName >> propValue;
            (*it).recursionLock = true;
            (*it).obj->setProperty(propName.toUtf8(), propValue);

            // it can be invalid if as a result of the above call new objects have been registered for example
            it = std::find_if(m_objects.begin(), m_objects.end(), [addr](const ObjectInfo &info) {
                return info.addr == addr;
            });
            Q_ASSERT(it != m_objects.end());
            (*it).recursionLock = false;
        }
        break;
    }
    default:
        Q_ASSERT(!"We should not get here!");
    }
}
void RemoteModelServer::newRequest(const GammaRay::Message &msg)
{
    if (!m_model && msg.type() != Protocol::ModelSyncBarrier)
        return;

    ProbeGuard g;
    switch (msg.type()) {
    case Protocol::ModelRowColumnCountRequest:
    {
        Protocol::ModelIndex index;
        msg.payload() >> index;
        const QModelIndex qmIndex = Protocol::toQModelIndex(m_model, index);

        Message msg(m_myAddress, Protocol::ModelRowColumnCountReply);
        msg.payload() << index << m_model->rowCount(qmIndex) << m_model->columnCount(qmIndex);
        sendMessage(msg);
        break;
    }

    case Protocol::ModelContentRequest:
    {
        quint32 size;
        msg.payload() >> size;
        Q_ASSERT(size > 0);

        QVector<QModelIndex> indexes;
        indexes.reserve(size);
        for (quint32 i = 0; i < size; ++i) {
            Protocol::ModelIndex index;
            msg.payload() >> index;
            const QModelIndex qmIndex = Protocol::toQModelIndex(m_model, index);
            if (!qmIndex.isValid())
                continue;
            indexes.push_back(qmIndex);
        }
        if (indexes.isEmpty())
            break;

        Message msg(m_myAddress, Protocol::ModelContentReply);
        msg.payload() << quint32(indexes.size());
        foreach (const auto &qmIndex, indexes) {
            msg.payload() << Protocol::fromQModelIndex(qmIndex) << filterItemData(m_model->itemData(qmIndex)) << qint32(m_model->flags(qmIndex));
        }

        sendMessage(msg);
        break;
    }

    case Protocol::ModelHeaderRequest:
    {
        qint8 orientation;
        qint32 section;
        msg.payload() >> orientation >> section;
        Q_ASSERT(orientation == Qt::Horizontal || orientation == Qt::Vertical);
        Q_ASSERT(section >= 0);

        QHash<qint32, QVariant> data;
        // TODO: add all roles
        data.insert(Qt::DisplayRole, m_model->headerData(section, static_cast<Qt::Orientation>(orientation), Qt::DisplayRole));
        data.insert(Qt::ToolTipRole, m_model->headerData(section, static_cast<Qt::Orientation>(orientation), Qt::ToolTipRole));

        Message msg(m_myAddress, Protocol::ModelHeaderReply);
        msg.payload() << orientation << section << data;
        sendMessage(msg);
        break;
    }

    case Protocol::ModelSetDataRequest:
    {
        Protocol::ModelIndex index;
        int role;
        QVariant value;
        msg.payload() >> index >> role >> value;

        m_model->setData(Protocol::toQModelIndex(m_model, index), value, role);
        break;
    }

    case Protocol::ModelSyncBarrier:
    {
        qint32 barrierId;
        msg.payload() >> barrierId;
        Message reply(m_myAddress, Protocol::ModelSyncBarrier);
        reply.payload() << barrierId;
        sendMessage(reply);
        break;
    }
    }