Gui: Remove old signal for critical messages in favour of Notification Area

===========================================================================

The former system of autoclosing messageboxes is removed in favour of the Notification Area.
This commit is contained in:
Abdullah Tahiri
2022-12-29 16:02:50 +01:00
committed by abdullahtahiriyo
parent 340ccb8ed6
commit eb7bf5d977
2 changed files with 2 additions and 181 deletions

View File

@@ -71,13 +71,6 @@ public:
IgnoreErrorOnRecompute = 12, // Don't report errors if the recompute failed
};
enum class NotificationType {
Information,
Warning,
Error,
Critical,
};
/** @name Properties */
//@{
/// holds the long name of the document (utf-8 coded)
@@ -177,8 +170,6 @@ public:
boost::signals2::signal<void (const App::Document&, const std::vector<App::DocumentObject*>&)> signalSkipRecompute;
boost::signals2::signal<void (const App::DocumentObject&)> signalFinishRestoreObject;
boost::signals2::signal<void (const App::Document&,const App::Property&)> signalChangePropertyEditor;
// signal user message
boost::signals2::signal<void (const App::DocumentObject&, const QString &, NotificationType)> signalUserMessage;
//@}
boost::signals2::signal<void (std::string)> signalLinkXsetValue;

View File

@@ -30,6 +30,7 @@
# include <QMessageBox>
# include <QTextStream>
# include <QTimer>
# include <QStatusBar>
# include <Inventor/actions/SoSearchAction.h>
# include <Inventor/nodes/SoSeparator.h>
#endif
@@ -55,6 +56,7 @@
#include "FileDialog.h"
#include "MainWindow.h"
#include "MDIView.h"
#include "NotificationArea.h"
#include "Selection.h"
#include "Thumbnail.h"
#include "Tree.h"
@@ -72,175 +74,6 @@ namespace bp = boost::placeholders;
namespace Gui {
/** This class is an implementation only class to handle user notifications offered by App::Document.
*
* It provides a mechanism requiring confirmation for critical notifications only during User initiated restore/document loading ( it
* does not require confirmation for macro/Python initiated restore, not to interfere with automations).
*
* Additionally, it provides a mechanism to show autoclosing non-modal user notifications in a non-intrusive way.
**/
class MessageManager {
public:
MessageManager() = default;
~MessageManager();
void setDocument(Gui::Document * pDocument);
void slotUserMessage(const App::DocumentObject&, const QString &, App::Document::NotificationType);
private:
void reorderAutoClosingMessages();
QMessageBox* createNonModalMessage(const QString & msg, App::Document::NotificationType notificationtype);
void pushAutoClosingMessage(const QString & msg, App::Document::NotificationType notificationtype);
void pushAutoClosingMessageTooManyMessages();
private:
using Connection = boost::signals2::connection;
Gui::Document * pDoc;
Connection connectUserMessage;
bool requireConfirmationCriticalMessageDuringRestoring = true;
std::vector<QMessageBox*> openAutoClosingMessages;
std::mutex mutexAutoClosingMessages;
const int autoClosingTimeout = 5000; // ms
const int autoClosingMessageStackingOffset = 10;
const unsigned int maxNumberOfOpenAutoClosingMessages = 3;
bool maxNumberOfOpenAutoClosingMessagesLimitReached = false;
};
MessageManager::~MessageManager(){
connectUserMessage.disconnect();
}
void MessageManager::setDocument(Gui::Document * pDocument)
{
pDoc = pDocument;
connectUserMessage = pDoc->getDocument()->signalUserMessage.connect
(boost::bind(&Gui::MessageManager::slotUserMessage, this, bp::_1, bp::_2, bp::_3));
}
void MessageManager::slotUserMessage(const App::DocumentObject& obj, const QString & msg, App::Document::NotificationType notificationtype)
{
(void) obj;
auto userInitiatedRestore = Application::Instance->testStatus(Gui::Application::UserInitiatedOpenDocument);
if(notificationtype == App::Document::NotificationType::Critical && userInitiatedRestore && requireConfirmationCriticalMessageDuringRestoring) {
auto confirmMsg = msg + QStringLiteral("\n\n") + QObject::tr("Do you want to skip confirmation of further critical message notifications while loading the file?");
auto button = QMessageBox::critical(pDoc->getActiveView(), QObject::tr("Critical Message"), confirmMsg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No );
if(button == QMessageBox::Yes)
requireConfirmationCriticalMessageDuringRestoring = false;
}
else { // Non-critical errors and warnings - auto-closing non-blocking message box
auto messageNumber = openAutoClosingMessages.size();
// Not opening more than the number of maximum autoclosing messages
// If maximum reached, the mechanism only resets after all present messages are auto-closed
if( messageNumber < maxNumberOfOpenAutoClosingMessages) {
if(messageNumber == 0 && maxNumberOfOpenAutoClosingMessagesLimitReached) {
maxNumberOfOpenAutoClosingMessagesLimitReached = false;
}
if(!maxNumberOfOpenAutoClosingMessagesLimitReached) {
pushAutoClosingMessage(msg, notificationtype);
}
}
else {
if(!maxNumberOfOpenAutoClosingMessagesLimitReached)
pushAutoClosingMessageTooManyMessages();
maxNumberOfOpenAutoClosingMessagesLimitReached = true;
}
}
}
void MessageManager::pushAutoClosingMessage(const QString & msg, App::Document::NotificationType notificationtype)
{
std::lock_guard<std::mutex> g(mutexAutoClosingMessages); // guard to avoid creating new messages while closing old messages (via timer)
auto msgBox = createNonModalMessage(msg, notificationtype);
msgBox->show();
int numberOpenAutoClosingMessages = openAutoClosingMessages.size();
openAutoClosingMessages.push_back(msgBox);
reorderAutoClosingMessages();
QTimer::singleShot(autoClosingTimeout*numberOpenAutoClosingMessages, [msgBox, this](){
std::lock_guard<std::mutex> g(mutexAutoClosingMessages); // guard to avoid closing old messages while creating new ones
if(msgBox) {
msgBox->done(0);
openAutoClosingMessages.erase(
std::remove(openAutoClosingMessages.begin(), openAutoClosingMessages.end(), msgBox),
openAutoClosingMessages.end());
reorderAutoClosingMessages();
}
});
}
void MessageManager::pushAutoClosingMessageTooManyMessages()
{
pushAutoClosingMessage(QObject::tr("Too many message notifications. Notification temporarily stopped. Look at the report view for more information."), App::Document::NotificationType::Warning);
}
QMessageBox* MessageManager::createNonModalMessage(const QString & msg, App::Document::NotificationType notificationtype)
{
auto parent = pDoc->getActiveView();
QMessageBox* msgBox = new QMessageBox(parent);
msgBox->setAttribute(Qt::WA_DeleteOnClose); // msgbox deleted automatically upon closed
msgBox->setStandardButtons(QMessageBox::NoButton);
msgBox->setWindowFlag(Qt::FramelessWindowHint,true);
msgBox->setText(msg);
if(notificationtype == App::Document::NotificationType::Error) {
msgBox->setWindowTitle(QObject::tr("Error"));
msgBox->setIcon(QMessageBox::Critical);
}
else if(notificationtype == App::Document::NotificationType::Warning) {
msgBox->setWindowTitle(QObject::tr("Warning"));
msgBox->setIcon(QMessageBox::Warning);
}
else if(notificationtype == App::Document::NotificationType::Information) {
msgBox->setWindowTitle(QObject::tr("Information"));
msgBox->setIcon(QMessageBox::Information);
}
else if(notificationtype == App::Document::NotificationType::Critical) {
msgBox->setWindowTitle(QObject::tr("Critical"));
msgBox->setIcon(QMessageBox::Critical);
}
msgBox->setModal( false ); // if you want it non-modal
return msgBox;
}
void MessageManager::reorderAutoClosingMessages()
{
auto parent = pDoc->getActiveView();
int numberOpenAutoClosingMessages = openAutoClosingMessages.size();
auto x = parent->width() / 2;
auto y = parent->height() / 7;
int posindex = numberOpenAutoClosingMessages - 1;
for (auto rit = openAutoClosingMessages.rbegin(); rit != openAutoClosingMessages.rend(); ++rit, posindex--) {
int xw = x - (*rit)->width() / 2 + autoClosingMessageStackingOffset*posindex;;
int yw = y + autoClosingMessageStackingOffset*posindex;
(*rit)->move(xw, yw);
(*rit)->raise();
}
}
// Pimpl class
struct DocumentP
{
@@ -301,8 +134,6 @@ struct DocumentP
using ConnectionBlock = boost::signals2::shared_connection_block;
ConnectionBlock connectActObjectBlocker;
ConnectionBlock connectChangeDocumentBlocker;
MessageManager messageManager;
};
} // namespace Gui
@@ -384,7 +215,6 @@ Document::Document(App::Document* pcDocument,Application * app)
d->connectTransactionRemove = pcDocument->signalTransactionRemove.connect
(boost::bind(&Gui::Document::slotTransactionRemove, this, bp::_1, bp::_2));
d->messageManager.setDocument(this);
// pointer to the python class
// NOTE: As this Python object doesn't get returned to the interpreter we
// mustn't increment it (Werner Jan-12-2006)