Commit cd953611 authored by Juzef's avatar Juzef

Grouping similar notifications - first try

parent 7dc236f6
......@@ -72,7 +72,7 @@ void WindowNotifierWindow::createGui()
QLabel *textLabel = new QLabel;
QString text = CurrentNotification->text();
if (!CurrentNotification->details().isEmpty())
text += "<br/> <small>" + CurrentNotification->details() + "</small>";
text += "<br/> <small>" + CurrentNotification->details().join("<br/>") + "</small>";
textLabel->setText(text);
labelsLayout->addWidget(textLabel);
......
......@@ -5,6 +5,7 @@ set (notify_SRCS
listener/chat-event-listener.cpp
listener/event-listener.cpp
listener/group-event-listener.cpp
notification/aggregate-notification.cpp
notification/new-message-notification.cpp
notification/multilogon-notification.cpp
notification/notification.cpp
......@@ -24,6 +25,7 @@ set (notify_MOC_SRCS
listener/chat-event-listener.h
listener/event-listener.h
listener/group-event-listener.h
notification/aggregate-notification.h
notification/new-message-notification.h
notification/multilogon-notification.h
notification/notification.h
......
......@@ -34,7 +34,7 @@
#include "configuration/configuration-file.h"
#include "debug.h"
#include "gui/windows/message-dialog.h"
#include "notify/notification/notification.h"
#include "notify/notification/aggregate-notification.h"
#include "notify/notifier.h"
#include "status/status-container-manager.h"
......@@ -133,13 +133,15 @@ const QList<NotifyEvent *> & NotificationManager::notifyEvents() const
return NotifyEvents;
}
void NotificationManager::notify(Notification *notification)
void NotificationManager::notify(Notification *rawNotification)
{
kdebugf();
QString notifyType = notification->key();
Notification *notification = findGroup(rawNotification);
QString notifyType = rawNotification->key();
bool foundNotifier = false;
bool foundNotifierWithCallbackSupported = !notification->requireCallback();
bool foundNotifierWithCallbackSupported = !rawNotification->requireCallback();
notification->acquire();
......@@ -172,11 +174,34 @@ void NotificationManager::notify(Notification *notification)
notification->release();
if (!foundNotifierWithCallbackSupported)
MessageDialog::show(KaduIcon("dialog-warning"), tr("Kadu"), tr("Unable to find notifier for %1 event").arg(notification->type()));
MessageDialog::show(KaduIcon("dialog-warning"), tr("Kadu"), tr("Unable to find notifier for %1 event").arg(rawNotification->type()));
kdebugf2();
}
Notification * NotificationManager::findGroup(Notification *rawNotification)
{
AggregateNotification *aggregate = ActiveNotifications.value(rawNotification->identifier());
if (aggregate)
{
aggregate->addNotification(rawNotification);
}
else
{
aggregate = new AggregateNotification(rawNotification);
connect(aggregate, SIGNAL(closed(Notification*)), this, SLOT(removeGrouped(Notification*)));
}
ActiveNotifications.insert(rawNotification->identifier(), aggregate);
return aggregate;
}
void NotificationManager::removeGrouped ( Notification* notification )
{
ActiveNotifications.remove(notification->identifier());
}
QString NotificationManager::notifyConfigurationKey(const QString &eventType)
{
......
......@@ -24,6 +24,7 @@
#ifndef NOTIFICATION_MANAGER_H
#define NOTIFICATION_MANAGER_H
#include <QtCore/QHash>
#include <QtCore/QTimer>
#include <QtGui/QGroupBox>
......@@ -35,6 +36,7 @@
#include "status/status.h"
class Action;
class AggregateNotification;
class Group;
class Message;
class MultilogonSession;
......@@ -57,9 +59,16 @@ class KADUAPI NotificationManager : public QObject
QList<Notifier *> Notifiers;
QList<NotifyEvent *> NotifyEvents;
QHash<QString, AggregateNotification*> ActiveNotifications;
NotificationManager();
virtual ~NotificationManager();
Notification * findGroup(Notification *notification);
private slots:
void removeGrouped(Notification *notification);
public:
static NotificationManager * instance();
......
......@@ -46,6 +46,7 @@ public:
virtual ~AccountNotification();
Account account() const { return CurrentAccount; }
virtual QString groupKey() const { return CurrentAccount.id(); }
};
......
......@@ -43,3 +43,8 @@ void ChatNotification::openChat()
if (chatWidget)
chatWidget->activate();
}
void ChatNotification::callbackAccept()
{
openChat();
}
\ No newline at end of file
......@@ -41,9 +41,13 @@ public:
Chat chat() { return CurrentChat; }
virtual QString groupKey() const { return CurrentChat.uuid(); }
public slots:
void openChat();
virtual void callbackAccept();
};
#endif // CHAT_NOTIFICATION_H
......@@ -64,7 +64,7 @@ void MessageNotification::unregisterEvents()
MessageNotification::MessageNotification(MessageType messageType, const Message &message) :
ChatNotification(message.messageChat(), messageType == NewChat ? "NewChat" : "NewMessage",
KaduIcon("protocols/common/message"))
KaduIcon("protocols/common/message")), CurrentMessage(message)
{
QString syntax;
......
......@@ -23,9 +23,9 @@
#ifndef NEW_MESSAGE_NOTIFICATION_H
#define NEW_MESSAGE_NOTIFICATION_H
#include "message/message.h"
#include "chat-notification.h"
class Message;
class NotifyEvent;
class MessageNotification : public ChatNotification
......@@ -35,12 +35,16 @@ class MessageNotification : public ChatNotification
static NotifyEvent *NewChatNotifyEvent;
static NotifyEvent *NewMessageNotifyEvent;
Message CurrentMessage;
public:
enum MessageType {
NewChat,
NewMessage
};
virtual QString groupKey() const { return CurrentMessage.messageSender().id(); }
static void registerEvents();
static void unregisterEvents();
......
......@@ -145,11 +145,16 @@ void Notification::setText(const QString &text)
Text = text;
}
void Notification::setDetails(const QString &details)
void Notification::setDetails(const QStringList &details)
{
Details = details;
}
void Notification::setDetails(const QString &details)
{
Details = QStringList(details);
}
void Notification::setIcon(const KaduIcon &icon)
{
Icon = icon;
......
......@@ -116,7 +116,7 @@ private:
QString Title;
QString Text;
QString Details;
QStringList Details;
KaduIcon Icon;
QList<Callback> Callbacks;
......@@ -143,19 +143,19 @@ public:
/**
Wywo�ywane przez notyfikator, kt�ry zajmuje si� danym zdarzeniem.
**/
void acquire();
virtual void acquire();
/**
Wywo�ywane przez notyfikator, kt�ry przestaje zajmowa� si� danym zdarzeniem.
Gdy �aden notyfikator nie zajmuje si� danym zdarzeniem, zdarzenie jest zwalniane.
Wyst�puje to na przyk�ad w przypadku modu��w d�wi�kowych czy modu�u hints, gdy
dymek zniknie po up�ywie okre�lonego czasu a nie przez zdarzenie wywo�ane przez u�ytkownika.
**/
void release();
virtual void release();
/**
Zamyka zdarzenie. Wywo�uje sygna� closed() i usuwa obiekt.
**/
void close();
virtual void close();
/**
Usuwa akcje u�ytkownika
......@@ -184,10 +184,13 @@ public:
@return typ zdarzenia
**/
const QString & type() const { return Type; }
virtual const QString & type() const { return Type; }
QString key() const;
virtual QString key() const;
virtual QString groupKey() const { return Title; }
virtual QString identifier() { return Type + "_" + groupKey(); }
/**
Ustawia tytu� zdarzenia.
**/
......@@ -197,45 +200,46 @@ public:
@return tytu� zdarzenia
**/
const QString & title() const { return Title; }
virtual const QString title() const { return Title; }
/**
Ustawia tre�� zdarzenia.
**/
void setText(const QString &text);
virtual void setText(const QString &text);
/**
Tre�� zdarzenia.
@return tre�� zdarzenia
**/
const QString & text() const { return Text; }
virtual const QString text() const { return Text; }
/**
Ustawia szczeg��y zdarzenia (jak na przyk�ad tekst wiadomo�ci).
**/
void setDetails(const QString &details);
virtual void setDetails(const QStringList &details);
virtual void setDetails(const QString &details);
/**
Szczeg��y zdarzenia
**/
const QString & details() const { return Details; }
virtual const QStringList details() const { return Details; }
/**
Ustawia ikon� zdarzenia.
**/
void setIcon(const KaduIcon &icon);
virtual void setIcon(const KaduIcon &icon);
/**
Ikona zdarzenia.
@return ikona zdarzenia
**/
const KaduIcon & icon() const { return Icon; }
virtual const KaduIcon & icon() const { return Icon; }
/**
Lista akcji.
@return lista akcji
**/
const QList<Callback> & getCallbacks() { return Callbacks; }
virtual const QList<Callback> & getCallbacks() { return Callbacks; }
public slots:
/**
......@@ -250,14 +254,14 @@ public slots:
/**
Slot anuluj�cy domy�ln� akcj� - wywo�ywany r�cznie przy wyborze dowolnej innej akcji.
**/
void clearDefaultCallback();
virtual void clearDefaultCallback();
signals:
/**
Sygna� wysylany przy zamykaniu zdarzenia, po wyborze przez u�ytkownika dowolnej akcji.
**/
void updated(Notification *);
void closed(Notification *);
};
#endif // NOTIFICATION_H
......@@ -110,6 +110,7 @@ StatusChangedNotification::StatusChangedNotification(const QString &toStatus, co
ChatNotification(ChatTypeContact::findChat(contact, ActionCreateAndAdd),
QString("StatusChanged") + toStatus, contact.contactAccount().protocolHandler()->statusIcon(contact.currentStatus().type()))
{
CurrentContact = contact;
Status status = contact.currentStatus();
setText(tr("<b>%1</b> changed status to <i>%2</i>").arg(
......
......@@ -42,13 +42,15 @@ class StatusChangedNotification : public ChatNotification
static NotifyEvent *StatusChangedToDoNotDisturbNotifyEvent;
static NotifyEvent *StatusChangedToOfflineNotifyEvent;
Contact CurrentContact;
public:
static void registerEvents();
static void unregisterEvents();
virtual QString groupKey() const { return CurrentContact.id(); }
StatusChangedNotification(const QString &toStatus, const Contact &contact);
virtual ~StatusChangedNotification() {}
};
#endif // STATUS_CHANGED_NOTIFICATION_H
......@@ -26,6 +26,7 @@
#include "gui/widgets/chat-widget.h"
#include "message/message-manager.h"
#include "message/message-render-info.h"
#include "notify/notification/aggregate-notification.h"
#include "notify/notification/chat-notification.h"
#include "chat-notifier.h"
......@@ -49,15 +50,21 @@ void ChatNotifier::sendNotificationToChatWidget(Notification *notification, Chat
{
QString content = notification->text();
if (!notification->details().isEmpty())
content += "<br/> <small>" + notification->details() + "</small>";
content += "<br/> <small>" + notification->details().join("<br/>") + "</small>";
chatWidget->appendSystemMessage(content);
}
void ChatNotifier::notify(Notification *notification)
{
AggregateNotification *aggregateNotification = qobject_cast<AggregateNotification *>(notification);
if (!aggregateNotification)
return;
Notification *latestNotification = aggregateNotification->notifications().last();
BuddySet buddies;
ChatNotification *chatNotification = qobject_cast<ChatNotification *>(notification);
ChatNotification *chatNotification = qobject_cast<ChatNotification *>(latestNotification);
if (chatNotification)
buddies = chatNotification->chat().contacts().toBuddySet();
......@@ -68,7 +75,7 @@ void ChatNotifier::notify(Notification *notification)
{
// warning: do not exchange intersect caller and argument, it will modify buddies variable if you do
if (buddies.isEmpty() || !i.key().contacts().toBuddySet().intersect(buddies).isEmpty())
sendNotificationToChatWidget(notification, i.value());
sendNotificationToChatWidget(latestNotification, i.value());
i++;
}
......
......@@ -117,7 +117,7 @@ void EncryptionNgNotification::notifyEncryptionError(const QString &error)
}
EncryptionNgNotification::EncryptionNgNotification(const QString &name) :
Notification(name, KaduIcon("security-high"))
Notification(name, KaduIcon("security-high")), Name(name)
{
}
......
......@@ -42,6 +42,8 @@ class ENCRYPTIONAPI EncryptionNgNotification : public Notification
static NotifyEvent *PublicKeySendErrorNotification;
static NotifyEvent *EncryptionErrorNotification;
QString Name;
public:
static void registerNotifications();
static void unregisterNotifications();
......@@ -50,6 +52,8 @@ public:
static void notifyPublicKeySendError(Contact contact, const QString &error);
static void notifyEncryptionError(const QString &error);
virtual QString groupKey() const { return Name; }
explicit EncryptionNgNotification(const QString &name);
virtual ~EncryptionNgNotification();
......
......@@ -27,6 +27,7 @@
#include "notify/notification/chat-notification.h"
class Chat;
class NotifyEvent;
class FirewallNotification : public ChatNotification
......@@ -44,6 +45,8 @@ public:
explicit FirewallNotification(const Chat &chat);
virtual ~FirewallNotification();
virtual QString groupKey() const { return "firewall"; }
};
#endif // FIREWALL_NOTIFICATION_H
......@@ -195,7 +195,7 @@ void FreedesktopNotify::notify(Notification *notification)
{
if (!msgRcv || ShowContentMessage)
{
body = notification->details();
body = notification->details().join(QLatin1String("\n"));
body.replace(StripBr, QLatin1String("\n"));
if (ServerSupportsMarkup)
body.remove(StripUnsupportedHtml);
......
......@@ -35,6 +35,7 @@
#include "configuration/configuration-file.h"
#include "contacts/contact-set.h"
#include "icons/icons-manager.h"
#include "notify/notification/aggregate-notification.h"
#include "notify/notification/chat-notification.h"
#include "notify/notification/notification.h"
#include "parser/parser.h"
......@@ -57,12 +58,15 @@ Hint::Hint(QWidget *parent, Notification *notification)
notification->acquire();
AggregateNotification *aggregateNotification = qobject_cast<AggregateNotification *>(notification);
if (aggregateNotification)
{
notification = aggregateNotification->notifications().first();
}
ChatNotification *chatNotification = qobject_cast<ChatNotification *>(notification);
CurrentChat = chatNotification ? chatNotification->chat() : Chat::null;
if (!notification->details().isEmpty())
details.append(notification->details());
startSecs = secs = config_file.readNumEntry("Hints", "Event_" + notification->key() + "_timeout", 10);
createLabels(notification->icon().icon().pixmap(config_file.readNumEntry("Hints", "AllEvents_iconSize", 32)));
......@@ -185,6 +189,9 @@ void Hint::updateText()
if (config_file.readBoolEntry("Hints", "ShowContentMessage"))
{
QStringList details;
if (!notification->details().isEmpty())
details = notification->details();
int count = details.count();
if (count)
......@@ -261,12 +268,8 @@ bool Hint::isDeprecated()
return (!requireCallbacks) && startSecs != 0 && secs == 0;
}
void Hint::addDetail(const QString &detail)
void Hint::notificationUpdated()
{
details.append(detail);
if (details.count() > 5)
details.pop_front();
resetTimeout();
updateText();
}
......
......@@ -83,13 +83,12 @@ public:
void mouseOver();
void mouseOut();
void notificationUpdated();
void getData(QString &text, QPixmap &pixmap, unsigned int &timeout, QFont &font, QColor &fgcolor, QColor &bgcolor);
bool requireManualClosing();
bool isDeprecated();
void addDetail(const QString &detail);
Chat chat() { return CurrentChat; }
Notification * getNotification() { return notification; }
......
......@@ -261,14 +261,8 @@ void HintManager::deleteHint(Hint *hint)
{
kdebugf();
DisplayedNotifications.removeAll(hint->getNotification()->identifier());
hints.removeAll(hint);
for (QMap<QPair<Chat, QString>, Hint *>::iterator it = linkedHints.begin(); it != linkedHints.end(); )
{
if (it.value() == hint)
it = linkedHints.erase(it);
else
it++;
}
layout->removeWidget(hint);
hint->deleteLater();
......@@ -323,7 +317,6 @@ void HintManager::processButtonPress(const QString &buttonName, Hint *hint)
switch (config_file.readNumEntry("Hints", buttonName))
{
case 1:
openChat(hint);
hint->acceptNotification();
break;
......@@ -391,20 +384,6 @@ void HintManager::chatUpdated(const Chat &chat)
if (chat.unreadMessagesCount() > 0)
return;
QPair<Chat, QString> newChat = qMakePair(chat, QString("NewChat"));
QPair<Chat, QString> newMessage = qMakePair(chat, QString("NewMessage"));
if (linkedHints.contains(newChat))
{
Hint *linkedHint = linkedHints.take(newChat);
linkedHint->close();
}
if (linkedHints.contains(newMessage))
{
Hint *linkedHint = linkedHints.take(newMessage);
linkedHint->close();
}
foreach (Hint *h, hints)
{
if (h->chat() == chat && !h->requireManualClosing())
......@@ -438,23 +417,41 @@ Hint *HintManager::addHint(Notification *notification)
{
kdebugf();
connect(notification, SIGNAL(closed(Notification *)), this, SLOT(notificationClosed(Notification *)));
Hint *hint;
Hint *hint = new Hint(frame, notification);
hints.append(hint);
if (DisplayedNotifications.contains(notification->identifier()))
{
foreach (Hint *h, hints)
if (h->getNotification()->identifier() == notification->identifier())
{
hint = h;
//hope this refreshes this hint
hint->notificationUpdated();
break;
}
}
else
{
connect(notification, SIGNAL(closed(Notification *)), this, SLOT(notificationClosed(Notification *)));
setLayoutDirection();
layout->addWidget(hint);
hint = new Hint(frame, notification);
hints.append(hint);
connect(hint, SIGNAL(leftButtonClicked(Hint *)), this, SLOT(leftButtonSlot(Hint *)));
connect(hint, SIGNAL(rightButtonClicked(Hint *)), this, SLOT(rightButtonSlot(Hint *)));
connect(hint, SIGNAL(midButtonClicked(Hint *)), this, SLOT(midButtonSlot(Hint *)));
connect(hint, SIGNAL(closing(Hint *)), this, SLOT(deleteHintAndUpdate(Hint *)));
connect(hint, SIGNAL(updated(Hint *)), this, SLOT(hintUpdated()));
setHint();
setLayoutDirection();
layout->addWidget(hint);
if (!hint_timer->isActive())
hint_timer->start(1000);
connect(hint, SIGNAL(leftButtonClicked(Hint *)), this, SLOT(leftButtonSlot(Hint *)));
connect(hint, SIGNAL(rightButtonClicked(Hint *)), this, SLOT(rightButtonSlot(Hint *)));
connect(hint, SIGNAL(midButtonClicked(Hint *)), this, SLOT(midButtonSlot(Hint *)));
connect(hint, SIGNAL(closing(Hint *)), this, SLOT(deleteHintAndUpdate(Hint *)));
connect(hint, SIGNAL(updated(Hint *)), this, SLOT(hintUpdated()));
setHint();
if (!hint_timer->isActive())
hint_timer->start(1000);
DisplayedNotifications.append(notification->identifier());
}
kdebugf2();
......@@ -584,38 +581,14 @@ void HintManager::notify(Notification *notification)
{
kdebugf();
ChatNotification *chatNotification = qobject_cast<ChatNotification *>(notification);
//TODO hack
if (!chatNotification || notification->type().contains("StatusChanged"))
{
addHint(notification);
kdebugf2();
return;
}
if (linkedHints.contains(qMakePair(chatNotification->chat(), notification->type())))
{
Hint *linkedHint = linkedHints.value(qMakePair(chatNotification->chat(), notification->type()));
linkedHint->addDetail(notification->details());
}
else
{
Hint *linkedHint = addHint(notification);
linkedHints.insert(qMakePair(chatNotification->chat(), notification->type()), linkedHint);
}
addHint(notification);
kdebugf2();
}
void HintManager::notificationClosed(Notification *notification)
{
ChatNotification *chatNotification = qobject_cast<ChatNotification *>(notification);
if (!chatNotification)
return;
if (linkedHints.contains(qMakePair(chatNotification->chat(), notification->type())))
linkedHints.remove(qMakePair(chatNotification->chat(), notification->type()));
Q_UNUSED(notification)
}
void HintManager::realCopyConfiguration(const QString &fromCategory, const QString &fromHint, const QString &toHint)
......
......@@ -51,8 +51,8 @@ class HintManager : public Notifier, public AbstractToolTip, public Configuratio
QString Style;
double Opacity;
QStringList DisplayedNotifications;
QList<Hint *> hints;
QMap<QPair<Chat, QString>, Hint *> linkedHints;
HintsConfigurationUiHandler *UiHandler;
......
......@@ -100,7 +100,7 @@ QString Qt4Notify::parseText(const QString &text, Notification *notification, co
ret = ret.replace("%&m", notification->text());
ret = ret.replace("%&t", notification->title());
ret = ret.replace("%&d", notification->details());
ret = ret.replace("%&d", notification->details().join(QLatin1String("\n")));
}
else
ret = def;
......@@ -123,7 +123,7 @@ void Qt4Notify::notify(Notification *notification)
QString syntax = config_file.readEntry("Qt4DockingNotify", QString("Event_") + notification->key() + "_syntax");
Qt4TrayIcon::instance()->showMessage(parseText(title, notification, notification->text()),
parseText(syntax, notification, notification->details()),
parseText(syntax, notification, notification->details().join(QLatin1String("\n"))),
(QSystemTrayIcon::MessageIcon)icon, timeout * 1000);
notification->release();
......
......@@ -241,7 +241,7 @@ void Speech::notify(Notification *notification)
text = notification->text();
else
{
QString details = notification->details();
QString details = notification->details().join(QLatin1String("\n"));
if (details.length() > config_file.readNumEntry("Speech", "MaxLength"))
syntax = config_file.readEntry("Speech", "MsgTooLong" + sex);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment