QVariant ObjectDynamicPropertyModel::data(const QModelIndex &index, int role) const
{
  if (!m_obj) {
    return QVariant();
  }

  const QList<QByteArray> propNames = m_obj.data()->dynamicPropertyNames();
  if (index.row() < 0 || index.row() >= propNames.size()) {
    return QVariant();
  }

  const QByteArray propName = propNames.at(index.row());
  const QVariant propValue = m_obj.data()->property(propName);

  if (role == Qt::DisplayRole || role == Qt::EditRole) {
    if (index.column() == 0) {
      return QString::fromUtf8(propName);
    } else if (index.column() == 1) {
      return role == Qt::EditRole ? propValue : VariantHandler::displayString(propValue);
    } else if (index.column() == 2) {
      return propValue.typeName();
    } else if (index.column() == 3) {
      return tr("<dynamic>");
    }
  } else if (role == PropertyModel::ActionRole) {
    return PropertyModel::Delete
         | ((MetaObjectRepository::instance()->metaObject(propValue.typeName()) && *reinterpret_cast<void* const*>(propValue.data())) || propValue.value<QObject*>()
            ? PropertyModel::NavigateTo
            : PropertyModel::NoAction);
  } else if (role == PropertyModel::ValueRole) {
    return propValue;
  } else if (role == PropertyModel::AppropriateToolRole) {
    ToolModel *toolModel = Probe::instance()->toolModel();
    ToolFactory *factory;
    if (propValue.canConvert<QObject*>())
      factory = toolModel->data(toolModel->toolForObject(propValue.value<QObject*>()), ToolModelRole::ToolFactory).value<ToolFactory*>();
    else
      factory = toolModel->data(toolModel->toolForObject(*reinterpret_cast<void* const*>(propValue.data()), propValue.typeName()), ToolModelRole::ToolFactory).value<ToolFactory*>();
    if (factory) {
      return factory->name();
    }
    return QVariant();
  }

  return QVariant();
}
QVariant ObjectStaticPropertyModel::data(const QModelIndex &index, int role) const
{
  if (!index.isValid() || !m_obj || index.row() < 0 ||
      index.row() >= m_obj.data()->metaObject()->propertyCount()) {
    return QVariant();
  }

  const QMetaProperty prop = m_obj.data()->metaObject()->property(index.row());
  const QVariant value = prop.read(m_obj.data());
  if (role == Qt::DisplayRole) {
    if (index.column() == 0) {
      return prop.name();
    } else if (index.column() == 1) {
      // QMetaProperty::read sets QVariant::typeName to int for enums,
      // so we need to handle that separately here
      const QString enumStr = Util::enumToString(value, prop.typeName(), m_obj.data());
      if (!enumStr.isEmpty()) {
        return enumStr;
      }
      return VariantHandler::displayString(value);
    } else if (index.column() == 2) {
      return prop.typeName();
    } else if (index.column() == 3) {
      const QMetaObject *mo = m_obj.data()->metaObject();
      while (mo->propertyOffset() > index.row()) {
        mo = mo->superClass();
      }
      return mo->className();
    }
  } else if (role == Qt::DecorationRole) {
    if (index.column() == 1) {
      return VariantHandler::decoration(value);
    }
  } else if (role == Qt::EditRole) {
    if (index.column() == 1 && prop.isWritable()) {
      return value;
    }
  } else if (role == Qt::ToolTipRole) {
    return detailString(prop);
  } else if (role == PropertyModel::ActionRole) {
    return (prop.isResettable() ? PropertyModel::Reset : PropertyModel::NoAction)
         | ((MetaObjectRepository::instance()->metaObject(value.typeName()) && *reinterpret_cast<void* const*>(value.data())) || value.value<QObject*>()
            ? PropertyModel::NavigateTo
            : PropertyModel::NoAction);
  } else if (role == PropertyModel::ValueRole) {
    return value;
  } else if (role == PropertyModel::AppropriateToolRole) {
    ToolModel *toolModel = Probe::instance()->toolModel();
    ToolFactory *factory;
    if (value.canConvert<QObject*>())
      factory = toolModel->data(toolModel->toolForObject(value.value<QObject*>()), ToolModelRole::ToolFactory).value<ToolFactory*>();
    else
      factory = toolModel->data(toolModel->toolForObject(*reinterpret_cast<void* const*>(value.data()), value.typeName()), ToolModelRole::ToolFactory).value<ToolFactory*>();
    if (factory) {
      return factory->name();
    }
    return QVariant();
  }

  return QVariant();
}