diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index e9b487058f..a11939163d 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1171,6 +1171,7 @@ SET(FreeCADGui_SRCS Macro.h MergeDocuments.h MetaTypes.h + Notifications.h PreCompiled.cpp PreCompiled.h QtAll.h diff --git a/src/Gui/Notifications.h b/src/Gui/Notifications.h new file mode 100644 index 0000000000..d805f38bf0 --- /dev/null +++ b/src/Gui/Notifications.h @@ -0,0 +1,219 @@ +/*************************************************************************** + * Copyright (c) 2023 Abdullah Tahiri * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef GUI_NOTIFICATIONS_H +#define GUI_NOTIFICATIONS_H + +#include +#include + +#include +#include +#include +#include + +namespace Gui { + +/** Methods to seamlessly provide intrusive or non-intrusive notifications of error, warning, + * messages, translated notifications, or untranslated notifications originating in a given + * document object. + * + * They are intended for easy substitution of currently blocking modal dialogs in which the user + * may only click 'ok'. + * + * It produces a blocking modal notification or a non-intrusive non-modal notification depending on + * the preference parameter NotificationArea/NonIntrusiveNotificationsEnabled. + * + * The notifier field can be a string or an App::DocumentObject * object, then the notifier is taken from the + * getFullLabel() method of the DocumentObject. + * + * Translations: + * + * An attempt is made by NotificationArea to translate the message using the "Notifications" context, + * except for TranslatedNotification. + * + * For the former, this may be marked using QT_TRANSLATE_NOOP("Notifications","My message") + * + * For TranslatedNotification, many modules using blocking notifications have their translations stored + * in other contexts, and the translations available at the callee function. This kind of notification + * provides a very low entry point to move existing blocking notifications into non-intrusive respecting + * the user choice (given by NotificationArea/NonIntrusiveNotificationsEnabled). + * + * Example 1: + * + * QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + * QObject::tr("Cannot add a constraint between two external geometries.")); + * + * Can be rewritten as: + * + * Gui::TranslatedNotification(obj, + * QObject::tr("Wrong selection"), + * QObject::tr("Cannot add a constraint between two external geometries.")); + * + * Here obj is a DocumentObject and serves to set the Notifier field for the notification. + * If the user preference is to see non-intrusive notifications, no pop-up will be shown and the + * notification will be shown in the notifications area. If the user preference is to see intrusive + * notifications, the pop-up will be shown (and it won't appear on the notification area as as a non- + * intrusive notification). + */ + +///generic function to send any message provided by Base::LogStyle +template +inline void Notify(TNotifier && notifier, TCaption && caption, TMessage && message); + +/** Convenience function to notify warnings + * The NotificationArea will attempt to find a translation in the "Notifications" context. + * This may be marked using QT_TRANSLATE_NOOP("Notifications","My message") + */ +template +inline void NotifyWarning(TNotifier && notifier, TCaption && caption, TMessage && message); + +/** Convenience function to notify errors + * The NotificationArea will attempt to find a translation in the "Notifications" context. + * This may be marked using QT_TRANSLATE_NOOP("Notifications","My message") + */ +template +inline void NotifyError(TNotifier && notifier, TCaption && caption, TMessage && message); + +/** Convenience function to notify messages + * The NotificationArea will attempt to find a translation in the "Notifications" context. + * This may be marked using QT_TRANSLATE_NOOP("Notifications","My message") + */ +template +inline void NotifyMessage(TNotifier && notifier, TCaption && caption, TMessage && message); + +/** Convenience function to send already translated user notifications. + * No attempt will be made by the NotificationArea to translate them. + */ +template +inline void TranslatedNotification(TNotifier && notifier, TCaption && caption, TMessage && message); + +/** Convenience function to send untranslated user notifications. + * The NotificationArea will attempt to find a translation in the "Notifications" context. + * This may be marked using QT_TRANSLATE_NOOP("Notifications","My message") + */ +template +inline void Notification(TNotifier && notifier, TCaption && caption, TMessage && message); +} //namespace Gui + + +template +inline void Gui::Notify(TNotifier && notifier, TCaption && caption, TMessage && message) +{ + Base::Reference hGrp = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")-> + GetGroup("NotificationArea"); + + bool nonIntrusive = hGrp->GetBool("NonIntrusiveNotificationsEnabled", true); + + if(!nonIntrusive) { + if constexpr( type == Base::LogStyle::Warning) { + QMessageBox::warning(Gui::getMainWindow(), + QCoreApplication::translate("Notifications", caption), + QCoreApplication::translate("Notifications", message)); + } + else + if constexpr( type == Base::LogStyle::Error) { + QMessageBox::critical(Gui::getMainWindow(), + QCoreApplication::translate("Notifications", caption), + QCoreApplication::translate("Notifications", message)); + } + else + if constexpr( type == Base::LogStyle::TranslatedNotification) { + QMessageBox::information(Gui::getMainWindow(), + caption, + message); + } + else { + QMessageBox::information(Gui::getMainWindow(), + QCoreApplication::translate("Notifications", caption), + QCoreApplication::translate("Notifications", message)); + } + } + else { + + if constexpr( type == Base::LogStyle::TranslatedNotification) { + // trailing newline is necessary as this may be shown too in a console requiring them (depending on the configuration). + auto msg = message.append(QStringLiteral("\n")); // QString + + if constexpr( std::is_base_of_v::type>> ) { + Base::Console().Send(notifier->getFullLabel(), msg.toUtf8()); + } + else { + Base::Console().Send(notifier, msg.toUtf8()); + } + } + else { + // trailing newline is necessary as this may be shown too in a console requiring them (depending on the configuration). + auto msg = std::string(message).append("\n"); + + if constexpr( std::is_base_of_v::type>> ) { + Base::Console().Send(notifier->getFullLabel(), msg.c_str()); + } + else { + Base::Console().Send(notifier, msg.c_str()); + } + } + } +} + +template +inline void Gui::NotifyWarning(TNotifier && notifier, TCaption && caption, TMessage && message) +{ + Notify(std::forward(notifier), + std::forward(caption), + std::forward(message)); +} + +template +inline void Gui::NotifyError(TNotifier && notifier, TCaption && caption, TMessage && message) +{ + Notify( std::forward(notifier), + std::forward(caption), + std::forward(message)); +} + +template +inline void Gui::NotifyMessage(TNotifier && notifier, TCaption && caption, TMessage && message) +{ + Notify(std::forward(notifier), + std::forward(caption), + std::forward(message)); +} + +template +inline void Gui::TranslatedNotification(TNotifier && notifier, TCaption && caption, TMessage && message) +{ + Notify(std::forward(notifier), + std::forward(caption), + std::forward(message)); +} + +template +inline void Gui::Notification(TNotifier && notifier, TCaption && caption, TMessage && message) +{ + Notify(std::forward(notifier), + std::forward(caption), + std::forward(message)); +} + +#endif // GUI_NOTIFICATIONS_H