#ifndef DIALOGOPENER_H #define DIALOGOPENER_H #include #include #include #include #include #include #include #include #ifdef Q_OS_WINDOWS class ExternalDialogOpener : public QWidget { public: ExternalDialogOpener(); ~ExternalDialogOpener(); }; #endif class DialogBlocker : public QDialog { public: DialogBlocker(QWidget* parent); ~DialogBlocker(); }; class DialogOpener { private: class DialogInfoBase { public: DialogInfoBase() = default; virtual ~DialogInfoBase() = default; QString getDialogClass() const {return mDialogClass;} void setDialogClass(const QString &newDialogClass) {mDialogClass = newDialogClass;} virtual void raise(bool raiseIfMinimized = false) = 0; virtual void close() = 0; virtual bool isParent(QObject* parent) = 0; protected: QString mDialogClass; }; template class DialogInfo : public DialogInfoBase { public: QPointer getDialog() const { return mDialog;} void setDialog(QPointer newDialog) { mDialog = newDialog; } void raise(bool raiseIfMinimized = false) override { if(raiseIfMinimized && mDialog->isMinimized()) { mDialog->showNormal(); } if(!mDialog->isMinimized()) { mDialog->raise(); mDialog->activateWindow(); } } void close() override { Platform::getInstance()->closeFileFolderSelectors(mDialog); mDialog->close(); } void clear() { mDialogClass.clear(); DialogOpener::removeDialog(mDialog); } bool isParent(QObject* parent) override { return mDialog->parent() == parent; } bool operator==(const DialogInfo &info) { return (info.mDialog == mDialog); } private: QPointer mDialog; }; struct GeometryInfo { bool maximized; QRect geometry; bool isEmpty() const {return geometry.isEmpty();} }; public: template static std::shared_ptr> findDialog() { auto classType = QString::fromUtf8(DialogType::staticMetaObject.className()); auto finder = [classType](const std::shared_ptr& dialogInfo) { return (dialogInfo->getDialogClass() == classType); }; auto itOccurence = std::find_if(mOpenedDialogs.begin(), mOpenedDialogs.end(), finder); if (itOccurence != mOpenedDialogs.end()) { return std::dynamic_pointer_cast>(*itOccurence); } return nullptr; } template static void removeDialogByClass() { auto dialogInfo = findDialog(); if(dialogInfo) { auto dialogInfoByType = std::dynamic_pointer_cast>(dialogInfo); if(dialogInfoByType) { removeDialog(dialogInfoByType->getDialog()); } } } template static void closeDialogsByParentClass() { auto parentDialog = findDialog(); if(parentDialog) { Platform::getInstance()->closeFileFolderSelectors(parentDialog->getDialog()); foreach(auto dialogInfo, mOpenedDialogs) { if(dialogInfo->isParent(parentDialog->getDialog())) { dialogInfo->close(); } } qApp->processEvents(QEventLoop::ExcludeUserInputEvents); } } template static void setParent(QPointer dialog, bool whenParentIsActivated) { auto parentDialog = findDialog(); if(parentDialog && ((whenParentIsActivated && parentDialog->getDialog()->isActiveWindow()) || (!whenParentIsActivated && !parentDialog->getDialog()->isMinimized()))) { closeDialogsByParentClass(); auto windowFlags = dialog->windowFlags(); parentDialog->raise(true); dialog->setParent(parentDialog->getDialog()); dialog->setWindowFlags(windowFlags); } } template static void showDialog(QPointer dialog, bool whenParentIsActivated, std::function func) { if(dialog) { setParent(dialog,whenParentIsActivated); showDialog(dialog, func); } } template static void showDialog(QPointer dialog, std::function func) { if(dialog) { dialog->connect(dialog.data(), &DialogType::finished, [func, dialog](){ if(func) { func(); } removeDialog(dialog); }); showDialogImpl(dialog); } } template static void showDialog(QPointer dialog, bool whenParentIsActivated, CallbackClass* caller, void(CallbackClass::*func)(QPointer)) { if(dialog) { setParent(dialog, whenParentIsActivated); dialog->connect(dialog.data(), &DialogType::finished, [dialog, caller, func](){ removeDialog(dialog); if(caller && func) { (caller->*func)(dialog); } }); showDialogImpl(dialog); } } template static void showDialog(QPointer dialog, CallbackClass* caller, void(CallbackClass::*func)(QPointer)) { if(dialog) { dialog->connect(dialog.data(), &DialogType::finished, [dialog, caller, func](){ if(caller && func) { (caller->*func)(dialog); } removeDialog(dialog); }); showDialogImpl(dialog); } } template static void showNonModalDialog(QPointer dialog) { if(dialog) { removeWhenClose(dialog); dialog->setModal(false); showDialogImpl(dialog, false); } } template static void showGeometryRetainerDialog(QPointer dialog) { if(dialog) { removeWhenClose(dialog); showDialogImpl(dialog, false); auto classType = QString::fromUtf8(DialogType::staticMetaObject.className()); mSavedGeometries.insert(classType, GeometryInfo()); } } template static void showDialog(QPointer dialog) { if(dialog) { removeWhenClose(dialog); showDialogImpl(dialog); } } template static void removeDialog(QPointer dialog) { if(dialog) { auto classType = QString::fromUtf8(DialogType::staticMetaObject.className()); if(mSavedGeometries.contains(classType)) { GeometryInfo info; info.maximized = dialog->isMaximized(); info.geometry = dialog->geometry(); mSavedGeometries.insert(classType, info); } if(dialog->parent()) { qApp->setActiveWindow(dialog->parentWidget()); } dialog->deleteLater(); } } static void raiseAllDialogs() { foreach(auto dialogInfo, mOpenedDialogs) { dialogInfo->raise(); } qApp->processEvents(); } static void closeAllDialogs() { foreach(auto dialogInfo, mOpenedDialogs) { dialogInfo->close(); } } private: static QList> mOpenedDialogs; static QMap mSavedGeometries; template static void removeWhenClose(QPointer dialog) { dialog->connect(dialog.data(), &DialogType::finished, [dialog]() { removeDialog(dialog); }); } template static void showDialogImpl(QPointer dialog, bool changeWindowModality = true) { if(dialog) { auto classType = QString::fromUtf8(DialogType::staticMetaObject.className()); auto info = findSiblingDialogInfo(classType); if(info) { if(info->getDialog() != dialog) { QRect siblingGeometry = info->getDialog()->geometry(); bool siblingIsMaximized = info->getDialog()->isMaximized(); dialog->setWindowFlags(info->getDialog()->windowFlags()); removeDialog(info->getDialog()); info->setDialog(dialog); info->setDialogClass(classType); initDialog(dialog); if(siblingIsMaximized) { dialog->setWindowState(Qt::WindowMaximized); } else if(siblingGeometry.isValid()) { dialog->setGeometry(siblingGeometry); } } } else { info = std::make_shared>(); info->setDialog(dialog); info->setDialogClass(classType); mOpenedDialogs.append(info); dialog->setWindowFlags(dialog->windowFlags() & ~Qt::WindowContextHelpButtonHint); initDialog(dialog); } #ifdef Q_OS_WINDOWS ExternalDialogOpener externalOpener; #endif if(changeWindowModality) { if(dialog->parent()) { dialog->setWindowModality(Qt::WindowModal); } } auto geoInfo = mSavedGeometries.value(classType, GeometryInfo()); if(!geoInfo.isEmpty()) { //First time this is used if(geoInfo.maximized) { auto dialogGeo = dialog->geometry(); dialogGeo.moveCenter(geoInfo.geometry.center()); dialog->move(dialogGeo.topLeft()); dialog->showMaximized(); } else { dialog->setGeometry(geoInfo.geometry); dialog->show(); } } else { dialog->show(); } info->raise(true); } } template static void initDialog(QPointer dialog) { dialog->connect(dialog.data(), &QObject::destroyed, [dialog](){ auto info = findDialogInfo(dialog); if(info) { mOpenedDialogs.removeOne(info); } }); //This depends on QDialog -> Check if we can templatizate it in order to reuse it with QML auto dpiResize = new HighDpiResize(dialog); Q_UNUSED(dpiResize); } template static std::shared_ptr> findDialogInfo(QPointer dialog) { auto finder = [dialog](const std::shared_ptr dialogInfo) { auto dialogInfoByType = std::dynamic_pointer_cast>(dialogInfo); return (dialogInfoByType && dialogInfoByType->getDialog() == dialog); }; auto itOccurence = std::find_if(mOpenedDialogs.begin(), mOpenedDialogs.end(), finder); if (itOccurence != mOpenedDialogs.end()) { return std::dynamic_pointer_cast>(*itOccurence); } return nullptr; } template static std::shared_ptr> findSiblingDialogInfo(const QString& classType) { auto finder = [classType](const std::shared_ptr dialogInfo) { auto dialogInfoByType = std::dynamic_pointer_cast>(dialogInfo); if(dialogInfoByType && !dialogInfoByType->getDialogClass().isEmpty()) { return (dialogInfoByType->getDialogClass() == classType); } return false; }; auto itOccurence = std::find_if(mOpenedDialogs.begin(), mOpenedDialogs.end(), finder); if (itOccurence != mOpenedDialogs.end()) { return std::dynamic_pointer_cast>(*itOccurence); } return nullptr; } }; #endif // DIALOGOPENER_H