/*************************************************************************** * 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 { class ViewProviderDocumentObject; /** 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 messages which are already translated. Those that are untranslatable can only be send * as messages intended for a developer directly using Console.. * * For the former, this may be marked using QT_TRANSLATE_NOOP("Notifications","My message") * * For translated Notification, 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.")); * * or * * Gui::TranslatedUserWarning(obj, * QObject::tr("Wrong selection"), * QObject::tr("Cannot add a constraint between two external geometries.")); * * or * * Gui::TranslatedUserError(obj, * QObject::tr("Wrong selection"), * QObject::tr("Cannot add a constraint between two external geometries.")); * * * depending on the severity. * * 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); template inline void NotifyUserWarning(TNotifier && notifier, TCaption && caption, TMessage && message); template inline void TranslatedUserWarning(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); template inline void NotifyUserError(TNotifier && notifier, TCaption && caption, TMessage && message); template inline void TranslatedUserError(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) { static_assert(content != Base::ContentType::Untranslatable, "A Gui notification cannot be provided with an untranslatable message."); static_assert(recipient != Base::IntendedRecipient::Developer, "A Gui notification cannot be intended only for the developer, use Console instead."); static_assert(!(recipient == Base::IntendedRecipient::All && content == Base::ContentType::Translated), "Information intended for Developers must not be translated. Provide an untranslated message instead."); Base::Reference hGrp = App::GetApplication().GetUserParameter(). GetGroup("BaseApp")->GetGroup("Preferences")-> GetGroup("NotificationArea"); bool nonIntrusive = hGrp->GetBool("NonIntrusiveNotificationsEnabled", true); if(!nonIntrusive) { // If Developers are also an intended recipient, notify before creating the blocking pop-up if constexpr(recipient == Base::IntendedRecipient::All) { // Send also to log for developer only auto msg = std::string(message).append("\n"); // use untranslated message if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->getFullLabel(), msg.c_str()); } else if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->getObject()->getFullLabel(), msg.c_str()); } else if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->getDocument()->Label.getStrValue(), msg.c_str()); } else if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->Label.getStrValue(), msg.c_str()); } else { Base::Console().Send(notifier, msg.c_str()); } } if constexpr(content == Base::ContentType::Untranslated) { 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 { QMessageBox::information(Gui::getMainWindow(), QCoreApplication::translate("Notifications", caption), QCoreApplication::translate("Notifications", message)); } } else { if constexpr( type == Base::LogStyle::Warning) { QMessageBox::warning(Gui::getMainWindow(), caption, message); } else if constexpr( type == Base::LogStyle::Error) { QMessageBox::critical(Gui::getMainWindow(), caption, message); } else { QMessageBox::information(Gui::getMainWindow(), caption, message); } } } else { if constexpr( content == Base::ContentType::Translated) { // trailing newline is not necessary as translated messages are not shown in logs auto msg = QStringLiteral("%1. %2").arg(caption).arg(message); // QString if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->getFullLabel(), msg.toUtf8()); } else if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->getObject()->getFullLabel(), msg.toUtf8()); } else if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->getDocument()->Label.getStrValue(), msg.toUtf8()); } else if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->Label.getStrValue(), 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 if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->getObject()->getFullLabel(), msg.c_str()); } else if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->getDocument()->Label.getStrValue(), msg.c_str()); } else if constexpr( std::is_base_of_v::type>> ) { Base::Console().Send(notifier->Label.getStrValue(), 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::NotifyUserWarning(TNotifier && notifier, TCaption && caption, TMessage && message) { Notify(std::forward(notifier), std::forward(caption), std::forward(message)); } template inline void Gui::TranslatedUserWarning(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::NotifyUserError(TNotifier && notifier, TCaption && caption, TMessage && message) { Notify(std::forward(notifier), std::forward(caption), std::forward(message)); } template inline void Gui::TranslatedUserError(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