/** * @RDE_HEADER@ * Gui Plugin for NotificationManangement * * Created by Mike Lennart Wille, ESZS, 2025-06-17 */ #include "nom_edit_gui_plugin.h" #include "nom_dialog.h" #include #include #include #include #include #include #include #include #include #include #include namespace NotificationManagement { std::shared_ptr GuiPlugin::createGuiInterface(LtsSession::LtsSession *session) { return std::make_shared(session); } const QString InterfaceImpl::s_nomEditGuiPlugin = QStringLiteral("nomEditGuiPlugin"); InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session) : GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Nom.Edit")) , m_noti(nullptr) , m_requestHelper(new LtsUtils::RequestHelper(this)) { qApp->installEventFilter(this); } InterfaceImpl::~InterfaceImpl() {} int InterfaceImpl::isDeleted(const NomNotification &data) const { int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId(); for (const auto &addr : data.recipientIds()) { if (addr.addressType() == AddressType_def::Operator) { if (addr.addressId() != operatorId) continue; if (addr.isDeleted()) return true; } } return false; } void InterfaceImpl::showNotificationList(int notificationId) { DEBUG_LOG(m_logger) << "showNotificationList notificationId=" << notificationId; initNotificationSystem(); } bool InterfaceImpl::eventFilter(QObject *watched, QEvent *event) { // DEBUG_LOG(m_logger) << "event->type()" << event->type(); if (watched == qApp && !event->isAccepted() && event->type() == LtsWidgets::LtsLinkEvent::eventTypeId()) { DEBUG_LOG(m_logger) << "0 event->type()" << event->type(); } auto ev = static_cast(event); if (event->type() == LtsWidgets::LtsLinkEvent::eventTypeId()) { DEBUG_LOG(m_logger) << "event->type() == LtsWidgets::LinkEvent::eventId()"; DEBUG_LOG(m_logger) << "ev->url()=" << ev->url().toString(); const auto ev = static_cast(event); const auto identifier = ev->url().path().mid(1); int id = 0; QRegularExpression re(QStringLiteral("(\\d+)$")); QRegularExpressionMatch match = re.match(identifier); if (match.hasMatch()) { id = match.captured(1).toInt(); } DEBUG_LOG(m_logger) << "identifier=" << identifier << ", id=" << id; if(ev->url().host().toLower() == QStringLiteral("notificationack") && id > 0) { DEBUG_LOG(m_logger) << "ack"; ack(m_nomNotifications.value(m_nomNotifications.value(id).id())); //hier eigentlich nicht } DEBUG_LOG(m_logger) << "ev->url().host()=" << ev->url().host(); if (ev->url().host().toLower() == s_nomEditGuiPlugin.toLower()) { DEBUG_LOG(m_logger) << "ev->url().host()=" << ev->url().host(); m_session->addWidget(onShowNotificationManagementDialog(nullptr), menuGroup(), QStringLiteral("NotificationEdit"), LtsWidgets::LayoutArea::eDialogTab); return true; } } return QObject::eventFilter(watched, event); } void InterfaceImpl::onNotificationChanged(const NotificationManagement::NomNotification ¬i, DataModification modType) { DEBUG_LOG(m_logger) << "onNotificationChanged title=" << noti.title() << ", content =" << noti.content() << ", args.size=" << noti.contentArgs().size() << ", modType=" << modType; if (noti.exerciseId() != m_session->exerciseId()) return; if (!isMyMessage(noti.recipientIds())) return; const QString notiIdent = QCoreApplication::translate("Notification", noti.title().c_str()) + QString::number(noti.id()); if (isDeleted(noti)) { m_unreadMessages.remove(noti.id()); updateUnreadCount(); if (m_session->baseLayout()->messageIdentifierExists(notiIdent)) { m_session->baseLayout()->removeQueuedMessage(notiIdent); } return; } NomNotification localNoti = noti; QString content = QCoreApplication::translate("Notification", localNoti.content().c_str()); for (const std::string& arg : noti.contentArgs()) { // .arg() ersetzt immer den kleinsten freien Platzhalter (z. B. zuerst %1, dann %2) content = content.arg(QString::fromStdString(arg)); DEBUG_LOG(m_logger) << ".arg() ersetzt immer den kleinsten freien Platzhalter" << ", arg=" << arg << ", content=" << content; } localNoti.content(content.toStdString()); m_nomNotifications.insert(noti.id(), localNoti); // When it's low, dont add it to the unread_message if (noti.processed() <= 0 && (modType == DataModification::eAdded || modType == DataModification::eModified)) { if (m_unreadMessages.contains(noti.id()) && noti.priority() < Priority::Normal) { m_unreadMessages.remove(noti.id()); } if (!m_unreadMessages.contains(noti.id())) { m_unreadMessages.insert(noti.id()); QString content = QString::fromStdString(localNoti.content()); for (const std::string& arg : noti.contentArgs()) { content = content.arg(QString::fromStdString(arg)); } QMap linkMap; parseContent(content, linkMap); // now replace the strings QMapIterator it(linkMap); while (it.hasNext()) { it.next(); content = content.replace(QStringLiteral("[%1](%2)").arg(it.value(), it.key()), QStringLiteral("%2").arg(it.key(), it.value())); } const QString openMessageLink(QStringLiteral("OpenMessages")); const LtsWidgets::LtsNotificationBox::MessageType messageType = static_cast(noti.messageType().underlying()); // If Priority is High add Notification for every user if (noti.priority() == Priority::High) { m_session->baseLayout()->showMessage( QCoreApplication::translate("Notification", noti.title().c_str()), content, messageType, [this, linkMap, noti](const QString &link) { Q_UNUSED(link) // Nothing to do here for now as links are already taken care of inside the Message see: LtsBaseLayoutWidget::showMessage // do not try to ack already acked notification if (!noti.processed()) { DEBUG_LOG(m_logger) << "ack"; ack(noti); //hier nach neustart? } }, true, notiIdent); m_session->baseLayout()->installEventFilter(this); } else if (noti.priority() == Priority::Highest) { // if the proirity is highest parse the links and send them directly without user input for (const auto &link : linkMap.keys()) { auto *event = new LtsWidgets::LtsLinkEvent(QUrl(link), m_session->baseLayout()); event->setAccepted(false); DEBUG_LOG(m_logger) << "Post event" << event << " " << event->url().toString(); QApplication::postEvent(qApp, event); // receive link events by overriding eventFilter of your *parented* QObject class } // do not try to ack already acked notification if (!noti.processed()) { DEBUG_LOG(m_logger) << "ack"; ack(noti); //oder hier? } } } } if ((noti.processed() && (modType == DataModification::eModified)) || modType == DataModification::eRemoved) { m_unreadMessages.remove(noti.id()); // deletes nothing if there is no message with that id :) // remove notification from user if (m_session->baseLayout()->messageIdentifierExists(notiIdent)) { m_session->baseLayout()->removeQueuedMessage(notiIdent); } } updateUnreadCount(); // recalc notification icon counter } void InterfaceImpl::onReadReceiptReply(const Core::FunctionReplyObject &replyObject) { DEBUG_LOG(m_logger) << "Got ReadReceiptReply " << replyObject.translated() << " add info: " << replyObject.additionalInfo(); } void InterfaceImpl::initNotificationSystem() { if (m_noti != nullptr) return; m_noti = m_session->createNotification(QStringLiteral("nom.Notifications")); m_noti->setIcon(QIcon(QStringLiteral("icon:messages_notif.svg"))); m_noti->setToolTip(tr("No unread notifications")); m_noti->setAction( [this]() { m_session->addWidget(onShowNotificationManagementDialog(nullptr), menuGroup(), QStringLiteral("NotificationEdit"), LtsWidgets::LayoutArea::eDialogTab); }); connect(m_dtc.get(), &NotificationManagement::Interface::Dtc::nomNotificationChanged, this, &InterfaceImpl::onNotificationChanged, Qt::UniqueConnection); m_dtc->enableNomNotification(); } void InterfaceImpl::updateUnreadCount() { if (m_noti == nullptr) return; m_noti->setCount(m_unreadMessages.count()); m_noti->setToolTip(tr("%Ln unread message(s)", "", m_unreadMessages.count())); } bool InterfaceImpl::parseContent(const QString &contentString, QMap &retMap) { if (contentString.isEmpty()) return false; // Mark Down Regex lookig for String between ]( and ) eg: TestLingk "[LinkName](http::blahblah)" QRegularExpression regLink(QStringLiteral("(?<=\\]\\()(.*?)(?=\\))")); QRegularExpressionMatch matchLink = regLink.match(contentString); QRegularExpression regDesc(QStringLiteral("(?<=\\[)(.*?)(?=\\]\\()")); QRegularExpressionMatch matchDesc = regDesc.match(contentString); QRegularExpressionMatchIterator itLink = regLink.globalMatch(contentString); QRegularExpressionMatchIterator itDesc = regDesc.globalMatch(contentString); while (itLink.hasNext() && itDesc.hasNext()) { QString linkRef = itLink.next().captured(); QString linkDesc = itDesc.next().captured(); if (!linkRef.isEmpty() && !linkDesc.isEmpty()) { retMap.insert(linkRef, linkDesc); } } return retMap.size(); } QVector InterfaceImpl::getActions() { QVector ret; { LtsWidgets::PluginData plData; plData.menuGroup = menuGroup(); plData.menuText = tr("Notifications"); plData.menuIcon = QIcon(QLatin1String("icon:messages_notif.svg")); plData.identifier = QLatin1String("NotificationEdit"); plData.operatorRight = OperatorRights::NotificationEdit; plData.exercisePart = LtsWidgets::ExercisePart::eSpecial; plData.createWidgetFunc = [this](QWidget *parent) { return onShowNotificationManagementDialog(parent); }; ret.append(plData); } // Init System without button initNotificationSystem(); return ret; } bool InterfaceImpl::fetchInterfaces() { if (!m_session->getDtc(m_dtc)) return false; if (!m_session->getFtc(m_ftc)) return false; return true; } void InterfaceImpl::clearInterfaces() { m_dtc = nullptr; m_ftc = nullptr; m_dtcOpm = nullptr; } LtsWidgets::LtsDialog *InterfaceImpl::onShowNotificationManagementDialog(QWidget *parent) { auto *dialog = new NotificationManagementDialog(m_session, menuGroup(), parent); return dialog; } void InterfaceImpl::ack(const NotificationManagement::NomNotification ¬ification) { ReadReceipt request; int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId(); int workstationId = LtsSessionData::LtsSessionData::getInstance()->getWorkstationId(); for (const auto &addr : notification.recipientIds()) { if ((addr.addressType() == AddressType_def::Operator && addr.addressId() == operatorId) || (addr.addressType() == AddressType_def::Workstation && addr.addressId() == workstationId)) { request.addressId(addr.id()); break; } } request.operatorId(operatorId); request.workstationId(workstationId); request.notificationIds({notification.id()}); request.processed(!notification.processed()); DEBUG_LOG(m_logger) << "m_ftc->readReceipt "; m_ftc->readReceiptRequest(request, this); } bool InterfaceImpl::isMyMessage(const std::vector
&recipents) { if (recipents.empty()) return false; using Iter = std::vector
::const_iterator; Iter it = recipents.begin(); while (it != recipents.end()) { if (it->addressType() == AddressType::Operator && it->addressId() == LtsSessionData::LtsSessionData::getInstance()->getOperatorId()) { return true; } else if (it->addressType() == AddressType::Workstation && it->addressId() == LtsSessionData::LtsSessionData::getInstance()->getWorkstationId()) { return true; } ++it; } return false; } } // namespace NotificationManagement