aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Holland <dominik.holland@pelagicore.com>2019-01-10 14:11:13 +0100
committerDominik Holland <dominik.holland@pelagicore.com>2019-01-11 12:18:54 +0000
commit7c191b1eda7f859ebc91d3a841f01ea86b8f0db9 (patch)
tree935608519781484374940ee19328d675bee18ea1
parent278839a14994364f7977f66c1b2bc80f4d9aea49 (diff)
Show a meaningful error message debug and release libraries mixed
On mac it can easily happen that debug and release libraries are mixed when building an application. E.g. using one of the qface examples. In general qtivicore tries to load the correct plugin version if available, but if the wrong one was loaded or the appropriate one was not available it can happen that plugin interfaces can't be casted to the correct types and thus the class doesn't work. When this happens a more descriptive error message is now shown and the backend is not used. Change-Id: I4ae63ac87509ec3feb1ae65750d8e0ee71ad6520 Reviewed-by: Robert Griebl <robert.griebl@pelagicore.com>
-rw-r--r--src/ivicore/qiviabstractfeature.cpp8
-rw-r--r--src/ivicore/qiviabstractfeature_p.h8
-rw-r--r--src/ivicore/qiviabstractfeaturelistmodel_p.h6
-rw-r--r--src/ivicore/qiviabstractzonedfeature.cpp2
-rw-r--r--src/ivicore/qivipagingmodel.cpp2
-rw-r--r--src/ivicore/qivisearchandbrowsemodel.cpp2
-rw-r--r--src/ivicore/qiviserviceinterface.cpp12
-rw-r--r--src/ivicore/qiviserviceinterface.h19
-rw-r--r--src/ivimedia/qiviamfmtuner.cpp2
-rw-r--r--src/ivimedia/qivimediadevicediscoverymodel.cpp2
-rw-r--r--src/ivimedia/qivimediaindexercontrol.cpp2
-rw-r--r--src/ivimedia/qivimediaplayer.cpp2
-rw-r--r--src/tools/ivigenerator/templates_frontend/interface.cpp.tpl4
-rw-r--r--src/tools/ivigenerator/templates_test/tst_test.cpp.tpl5
14 files changed, 63 insertions, 13 deletions
diff --git a/src/ivicore/qiviabstractfeature.cpp b/src/ivicore/qiviabstractfeature.cpp
index 6c90516..ee2be9c 100644
--- a/src/ivicore/qiviabstractfeature.cpp
+++ b/src/ivicore/qiviabstractfeature.cpp
@@ -312,8 +312,12 @@ bool QIviAbstractFeature::setServiceObject(QIviServiceObject *so)
if (so) {
connectToServiceObject(d->m_serviceObject);
- if (!d->m_isConnected)
- qWarning("The QIviServiceObject got accepted but QIviAbstractFeature::connectToServiceObject wasn't called");
+ if (!d->m_isConnected) {
+ qCritical() << this <<
+ "accepted the given QIviServiceObject, but didn't connect to it completely"
+ ", as QIviAbstractFeature::connectToServiceObject wasn't called.";
+ return false;
+ }
connect(so, &QObject::destroyed, this, &QIviAbstractFeature::serviceObjectDestroyed);
}
diff --git a/src/ivicore/qiviabstractfeature_p.h b/src/ivicore/qiviabstractfeature_p.h
index 59e912b..633681f 100644
--- a/src/ivicore/qiviabstractfeature_p.h
+++ b/src/ivicore/qiviabstractfeature_p.h
@@ -59,6 +59,7 @@
#include "qiviabstractfeature.h"
#include "qivifeatureinterface.h"
+#include "qiviserviceobject.h"
QT_BEGIN_NAMESPACE
@@ -85,6 +86,13 @@ public:
virtual bool notify(const QByteArray &propertyName, const QVariant &value);
QIviFeatureInterface *backend() const;
+ template <class T> T backend() const
+ {
+ Q_Q(const QIviAbstractFeature);
+ if (m_serviceObject)
+ return m_serviceObject->interfaceInstance<T>(q->interfaceName());
+ return nullptr;
+ }
void setDiscoveryResult(QIviAbstractFeature::DiscoveryResult discoveryResult);
void onInitializationDone();
diff --git a/src/ivicore/qiviabstractfeaturelistmodel_p.h b/src/ivicore/qiviabstractfeaturelistmodel_p.h
index 5adb88c..ea09a91 100644
--- a/src/ivicore/qiviabstractfeaturelistmodel_p.h
+++ b/src/ivicore/qiviabstractfeaturelistmodel_p.h
@@ -62,7 +62,7 @@
QT_BEGIN_NAMESPACE
-class QIviHelperFeature : public QIviAbstractFeature
+class Q_QTIVICORE_EXPORT QIviHelperFeature : public QIviAbstractFeature
{
Q_OBJECT
@@ -95,6 +95,10 @@ public:
virtual void initialize();
QIviFeatureInterface *backend() const;
+ template <class T> T backend() const
+ {
+ return m_feature->iviPrivate()->backend<T>();
+ }
Q_DISABLE_COPY(QIviAbstractFeatureListModelPrivate)
diff --git a/src/ivicore/qiviabstractzonedfeature.cpp b/src/ivicore/qiviabstractzonedfeature.cpp
index f583ed3..5d7c0c4 100644
--- a/src/ivicore/qiviabstractzonedfeature.cpp
+++ b/src/ivicore/qiviabstractzonedfeature.cpp
@@ -144,7 +144,7 @@ QIviZonedFeatureInterface *QIviAbstractZonedFeature::backend(const QString &inte
if (auto *parentFeature = qobject_cast<QIviAbstractZonedFeature*>(parent()))
return parentFeature->backend();
else if (QIviServiceObject *so = serviceObject())
- return qobject_cast<QIviZonedFeatureInterface*>(so->interfaceInstance(iface));
+ return so->interfaceInstance<QIviZonedFeatureInterface*>(iface);
return nullptr;
}
diff --git a/src/ivicore/qivipagingmodel.cpp b/src/ivicore/qivipagingmodel.cpp
index 30ae7f9..b5dd312 100644
--- a/src/ivicore/qivipagingmodel.cpp
+++ b/src/ivicore/qivipagingmodel.cpp
@@ -252,7 +252,7 @@ const QIviStandardItem *QIviPagingModelPrivate::itemAt(int i) const
QIviPagingModelInterface *QIviPagingModelPrivate::backend() const
{
- return qobject_cast<QIviPagingModelInterface*>(QIviAbstractFeatureListModelPrivate::backend());
+ return QIviAbstractFeatureListModelPrivate::backend<QIviPagingModelInterface*>();
}
/*!
diff --git a/src/ivicore/qivisearchandbrowsemodel.cpp b/src/ivicore/qivisearchandbrowsemodel.cpp
index 5ce2ca9..c9e70b4 100644
--- a/src/ivicore/qivisearchandbrowsemodel.cpp
+++ b/src/ivicore/qivisearchandbrowsemodel.cpp
@@ -174,7 +174,7 @@ void QIviSearchAndBrowseModelPrivate::setAvailableContenTypes(const QStringList
QIviSearchAndBrowseModelInterface *QIviSearchAndBrowseModelPrivate::searchBackend() const
{
- return qobject_cast<QIviSearchAndBrowseModelInterface*>(QIviPagingModelPrivate::backend());
+ return QIviAbstractFeatureListModelPrivate::backend<QIviSearchAndBrowseModelInterface*>();
}
void QIviSearchAndBrowseModelPrivate::updateContentType(const QString &contentType)
diff --git a/src/ivicore/qiviserviceinterface.cpp b/src/ivicore/qiviserviceinterface.cpp
index 6ae9ea5..5cd24a4 100644
--- a/src/ivicore/qiviserviceinterface.cpp
+++ b/src/ivicore/qiviserviceinterface.cpp
@@ -44,6 +44,18 @@
QT_BEGIN_NAMESPACE
+/*!
+ \fn template <class T> T qivi_interface_cast(QObject *backend)
+ \relates QIviServiceInterface
+
+ Casts the given \a backend to the interface type T.
+
+ When implementing a QtIvi Feature this function should be used, as it shows a meaningful error
+ message when the cast fails.
+
+ \sa qobject_cast
+*/
+
QIviServiceInterface::~QIviServiceInterface()
{
}
diff --git a/src/ivicore/qiviserviceinterface.h b/src/ivicore/qiviserviceinterface.h
index fe811ff..98e43f6 100644
--- a/src/ivicore/qiviserviceinterface.h
+++ b/src/ivicore/qiviserviceinterface.h
@@ -50,6 +50,20 @@
QT_BEGIN_NAMESPACE
+template <class T> T qivi_interface_cast(QObject *backend)
+{
+ T inst = qobject_cast<T>(backend);
+ static bool showOnce = true;
+ if (!inst && showOnce) {
+ typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
+ qCritical("Casting the backend to the interface %s failed.\n"
+ "Either the backend pointer is not of the correct type or casting failed because "
+ "debug and release libraries were mixed.", ObjType::staticMetaObject.className());
+ showOnce = false;
+ }
+ return inst;
+}
+
class Q_QTIVICORE_EXPORT QIviServiceInterface
{
public:
@@ -57,6 +71,11 @@ public:
virtual QStringList interfaces() const = 0;
virtual QIviFeatureInterface *interfaceInstance(const QString &interface) const = 0;
+
+ template <class T> T interfaceInstance(const QString &interface) const {
+ T inst = qivi_interface_cast<T>(interfaceInstance(interface));
+ return inst;
+ }
};
#define QIviServiceInterface_iid "org.qt-project.qtivi.QIviServiceInterface/1.0"
diff --git a/src/ivimedia/qiviamfmtuner.cpp b/src/ivimedia/qiviamfmtuner.cpp
index a0da253..9590dfd 100644
--- a/src/ivimedia/qiviamfmtuner.cpp
+++ b/src/ivimedia/qiviamfmtuner.cpp
@@ -148,7 +148,7 @@ void QIviAmFmTunerPrivate::onScanStatusChanged(bool scanRunning)
QIviAmFmTunerBackendInterface *QIviAmFmTunerPrivate::tunerBackend() const
{
- return qobject_cast<QIviAmFmTunerBackendInterface*>(backend());
+ return backend<QIviAmFmTunerBackendInterface*>();
}
/*!
diff --git a/src/ivimedia/qivimediadevicediscoverymodel.cpp b/src/ivimedia/qivimediadevicediscoverymodel.cpp
index 6efd360..410e583 100644
--- a/src/ivimedia/qivimediadevicediscoverymodel.cpp
+++ b/src/ivimedia/qivimediadevicediscoverymodel.cpp
@@ -125,7 +125,7 @@ void QIviMediaDeviceDiscoveryModelPrivate::onDeviceRemoved(QIviServiceObject *de
QIviMediaDeviceDiscoveryModelBackendInterface *QIviMediaDeviceDiscoveryModelPrivate::discoveryBackend() const
{
- return qobject_cast<QIviMediaDeviceDiscoveryModelBackendInterface*>(backend());
+ return backend<QIviMediaDeviceDiscoveryModelBackendInterface*>();
}
/*!
diff --git a/src/ivimedia/qivimediaindexercontrol.cpp b/src/ivimedia/qivimediaindexercontrol.cpp
index cdbefff..004de33 100644
--- a/src/ivimedia/qivimediaindexercontrol.cpp
+++ b/src/ivimedia/qivimediaindexercontrol.cpp
@@ -84,7 +84,7 @@ void QIviMediaIndexerControlPrivate::onStateChanged(QIviMediaIndexerControl::Sta
QIviMediaIndexerControlBackendInterface *QIviMediaIndexerControlPrivate::indexerBackend() const
{
- return qobject_cast<QIviMediaIndexerControlBackendInterface*>(backend());
+ return backend<QIviMediaIndexerControlBackendInterface*>();
}
/*!
diff --git a/src/ivimedia/qivimediaplayer.cpp b/src/ivimedia/qivimediaplayer.cpp
index 4460569..8d78246 100644
--- a/src/ivimedia/qivimediaplayer.cpp
+++ b/src/ivimedia/qivimediaplayer.cpp
@@ -162,7 +162,7 @@ void QIviMediaPlayerPrivate::onMutedChanged(bool muted)
QIviMediaPlayerBackendInterface *QIviMediaPlayerPrivate::playerBackend() const
{
- return qobject_cast<QIviMediaPlayerBackendInterface*>(backend());
+ return backend<QIviMediaPlayerBackendInterface*>();
}
/*!
diff --git a/src/tools/ivigenerator/templates_frontend/interface.cpp.tpl b/src/tools/ivigenerator/templates_frontend/interface.cpp.tpl
index 5f4c904..7cddae5 100644
--- a/src/tools/ivigenerator/templates_frontend/interface.cpp.tpl
+++ b/src/tools/ivigenerator/templates_frontend/interface.cpp.tpl
@@ -446,14 +446,14 @@ void {{class}}::clearServiceObject()
/*! \internal */
{{class}}BackendInterface *{{class}}::{{interface|lower}}Backend() const
{
- return qobject_cast<{{class}}BackendInterface*>(backend());
+ return qivi_interface_cast<{{class}}BackendInterface*>(backend());
}
{% else %}
/*! \internal */
{{class}}BackendInterface *{{class}}::{{interface|lower}}Backend() const
{
if (QIviServiceObject *so = serviceObject())
- return qobject_cast<{{class}}BackendInterface*>(so->interfaceInstance(interfaceName()));
+ return so->interfaceInstance<{{class}}BackendInterface*>(interfaceName());
return nullptr;
}
{% endif %}
diff --git a/src/tools/ivigenerator/templates_test/tst_test.cpp.tpl b/src/tools/ivigenerator/templates_test/tst_test.cpp.tpl
index 6660ead..194e3ee 100644
--- a/src/tools/ivigenerator/templates_test/tst_test.cpp.tpl
+++ b/src/tools/ivigenerator/templates_test/tst_test.cpp.tpl
@@ -306,7 +306,10 @@ void {{interface}}Test::testInvalidBackend()
{{interface}}InvalidServiceObject *service = new {{interface}}InvalidServiceObject();
manager->registerService(service, service->interfaces());
{{interface}} cc;
- QTest::ignoreMessage(QtWarningMsg, "The QIviServiceObject got accepted but QIviAbstractFeature::connectToServiceObject wasn't called");
+ QTest::ignoreMessage(QtCriticalMsg, QRegularExpression(".*accepted the given QIviServiceObject, "
+ "but didn't connect to it completely, as "
+ "QIviAbstractFeature::connectToServiceObject "
+ "wasn't called."));
cc.startAutoDiscovery();
// Running without a backend means that changes do not propagate