File indexing completed on 2024-05-12 05:00:04
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2023 Stefano Crocco <stefano.crocco@alice.it> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KONQINTERFACES_COMMON 0008 #define KONQINTERFACES_COMMON 0009 0010 #include <QObject> 0011 0012 namespace KonqInterfaces { 0013 /** 0014 * @brief Casts either the given object or one of its children as a pointer to T if possible 0015 * 0016 * @param obj the object to cast 0017 * @return @p obj or one of its children cast to a `T*` or `nullptr` if neither @p obj nor 0018 * its children can be cast to a `T*` 0019 * @internal 0020 * This function has two implementations, depending on whether or not `T` derives from `QObject`. 0021 * This allows to make use `QObject::findChild` when possible. 0022 * 0023 * To distinguish the two cases, as() uses `std::conditional`, delegating the actual implementation 0024 * either to CallAsForExtension::call() or CallAsForInterface::call() 0025 * @endinternal 0026 */ 0027 template <typename T> T* as(QObject *obj); 0028 0029 /** 0030 * @brief Struct used to implement as() when the template is a `QObject` 0031 */ 0032 struct CallAsForExtension { 0033 /** 0034 * @brief Casts either the given object or one of its children as a pointer to T if possible 0035 * 0036 * This function assumes that `T` is a `QObject`-derived class and uses `QObject::findChild` 0037 * to determine the return value, except if @p obj can itself be cast to `T*` 0038 * @return @p obj or one of its children cast to a `T*` or `nullptr` if neither @p obj nor 0039 * its children can be cast to a `T*` 0040 */ 0041 template <typename T> T* call(QObject* obj); 0042 }; 0043 /** 0044 * @brief Struct used to implement as() when the template is not a `QObject` 0045 */ 0046 struct CallAsForInterface { 0047 /** 0048 * @brief Casts either the given object or one of its children as a pointer to T if possible 0049 * 0050 * Unlike CallAsForExtension::call(), this function doesn't make any assumption about the type 0051 * of `T`, so it always works. However, it uses `dynamic_cast` and custom code rather than 0052 * the more specialized `QObject::findChild`. 0053 * @return @p obj or one of its children cast to a `T*` or `nullptr` if neither @p obj nor 0054 * its children can be cast to a `T*` 0055 */ 0056 template <typename T> T* call(QObject* obj); 0057 }; 0058 } 0059 0060 template<typename T> T* KonqInterfaces::as(QObject *obj) 0061 { 0062 typename std::conditional<(std::is_base_of<QObject, T>()), CallAsForExtension, CallAsForInterface>::type func; 0063 return func.template call<T>(obj); 0064 } 0065 0066 template<typename T> T* KonqInterfaces::CallAsForExtension::call(QObject *obj) 0067 { 0068 T* res = qobject_cast<T*>(obj); 0069 return res ? res : obj->findChild<T*>(); 0070 } 0071 0072 template<typename T> T* KonqInterfaces::CallAsForInterface::call(QObject *obj) 0073 { 0074 T* res = dynamic_cast<T*>(obj); 0075 if (res) { 0076 return res; 0077 } 0078 QObjectList children = obj->findChildren<QObject*>(); 0079 for (QObject *c : children) { 0080 res = dynamic_cast<T*>(c); 0081 if (res) { 0082 return res; 0083 } 0084 } 0085 return nullptr; 0086 } 0087 0088 #endif //KONQINTERFACES_COMMON