File indexing completed on 2024-05-05 04:38:47
0001 /* 0002 SPDX-FileCopyrightText: 2017 Christoph Roick <chrisito@gmx.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef KDEVPLATFORM_SCOPEDDIALOG_H 0008 #define KDEVPLATFORM_SCOPEDDIALOG_H 0009 0010 #include <QPointer> 0011 0012 #include <utility> 0013 0014 namespace KDevelop { 0015 0016 /// A tag that requests construction of a null ScopedDialog, avoids ambiguity with the variadic template constructor. 0017 struct NullScopedDialog 0018 { 0019 // The explicit default constructor ensures that ambiguous code `ScopedDialog<QDialog> d{{}};` does not compile. 0020 explicit constexpr NullScopedDialog() noexcept = default; 0021 }; 0022 0023 /** 0024 * Wrapper class for QDialogs which should not be instantiated on stack. 0025 * 0026 * Parents of QDialogs may be unintentionally deleted during the execution of the 0027 * dialog and automatically delete their children. When returning to the calling 0028 * function they get intentionally deleted again, which will lead to a crash. This 0029 * can be circumvented by using a QPointer which keeps track of the QDialogs validity. 0030 * See this 0031 * <a href="https://blogs.kde.org/2009/03/26/how-crash-almost-every-qtkde-application-and-how-fix-it-0">blog entry</a> 0032 * for explanation. The ScopedDialog utility allows using the dialog like a 0033 * common pointer. 0034 * 0035 * Instead of 0036 * \code 0037 QFileDialog dlg(this); 0038 if (dlg.exec()) 0039 return; 0040 \endcode 0041 simply use 0042 * \code 0043 ScopedDialog<QFileDialog> dlg(this); 0044 if (dlg->exec()) 0045 return; 0046 \endcode 0047 without need to manually clean up afterwards. 0048 */ 0049 // This class template is final, because inheriting it shouldn't be useful, and 0050 // the forwarding-reference constructor would be invoked in places where slicing 0051 // normally occurs. 0052 template<typename DialogType> 0053 class ScopedDialog final 0054 { 0055 Q_DISABLE_COPY_MOVE(ScopedDialog) 0056 public: 0057 // Explicitly delete unconventional overloads of copy and move constructors 0058 // to prevent a compiler from using the forwarding-reference constructor in 0059 // places where a copy or a move constructor are normally invoked. 0060 ScopedDialog(ScopedDialog&) = delete; 0061 ScopedDialog(const ScopedDialog&&) = delete; 0062 0063 /// Construct the dialog with any set of allowed arguments 0064 /// for the construction of DialogType 0065 template<typename ... Arguments> 0066 explicit ScopedDialog(Arguments&& ... args) 0067 : ptr{new DialogType(std::forward<Arguments>(args)...)} 0068 { 0069 } 0070 /// Automatically deletes the dialog if it is still present 0071 ~ScopedDialog() 0072 { 0073 delete ptr; 0074 } 0075 0076 /// Construct a null scoped dialog, i.e. don't create a DialogType but initialize the dialog pointer with nullptr 0077 explicit ScopedDialog(NullScopedDialog) 0078 { 0079 } 0080 /// Destroy the previous dialog if present, then create a dialog with arguments accepted by DialogType() 0081 template<typename... Arguments> 0082 void assign(Arguments&&... args) 0083 { 0084 delete ptr; 0085 ptr = new DialogType(std::forward<Arguments>(args)...); 0086 } 0087 0088 /// Access the raw pointer to the dialog 0089 DialogType* data() const 0090 { 0091 return ptr; 0092 } 0093 /// Access members of the dialog 0094 DialogType* operator->() const 0095 { 0096 return ptr; 0097 } 0098 /// Access the dialog 0099 DialogType& operator*() const 0100 { 0101 return *ptr; 0102 } 0103 /// Return the corresponding pointer 0104 operator DialogType*() const { 0105 return ptr; 0106 } 0107 0108 private: 0109 QPointer<DialogType> ptr; 0110 }; 0111 0112 } 0113 0114 #endif // KDEVPLATFORM_SCOPEDDIALOG_H