File indexing completed on 2024-04-28 04:44:14

0001 /*
0002     SnoreNotify is a Notification Framework based on Qt
0003     Copyright (C) 2013-2015  Hannah von Reth <vonreth@kde.org>
0004 
0005     SnoreNotify is free software: you can redistribute it and/or modify
0006     it under the terms of the GNU Lesser General Public License as published by
0007     the Free Software Foundation, either version 3 of the License, or
0008     (at your option) any later version.
0009 
0010     SnoreNotify is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013     GNU Lesser General Public License for more details.
0014 
0015     You should have received a copy of the GNU Lesser General Public License
0016     along with SnoreNotify.  If not, see <http://www.gnu.org/licenses/>.
0017 */
0018 
0019 #include "snore.h"
0020 #include "snore_p.h"
0021 #include "snoreconstants.h"
0022 #include "lambdahint.h"
0023 #include "notification/notification.h"
0024 #include "notification/notification_p.h"
0025 #include "plugins/plugincontainer.h"
0026 #include "plugins/plugins.h"
0027 #include "plugins/snorebackend.h"
0028 #include "plugins/snorefrontend.h"
0029 
0030 #include "version.h"
0031 
0032 #include <QGuiApplication>
0033 #include <QSettings>
0034 #include <QThread>
0035 
0036 using namespace Snore;
0037 
0038 SnoreCore::SnoreCore(QObject *parent):
0039     QObject(parent)
0040 {
0041     if (QThread::currentThread() != parent->thread()) {
0042         moveToThread(parent->thread());
0043     }
0044     d_ptr = new SnoreCorePrivate();
0045     Q_D(SnoreCore);
0046     d->q_ptr = this;
0047 }
0048 
0049 SnoreCore &SnoreCore::instance()
0050 {
0051     static SnoreCore *instance = nullptr;
0052     if (!instance) {
0053         qRegisterMetaType<Application>();
0054         qRegisterMetaType<LambdaHint>();
0055         qRegisterMetaType<Notification>();
0056         qRegisterMetaType<SnorePlugin::PluginTypes>();
0057         qRegisterMetaTypeStreamOperators<SnorePlugin::PluginTypes>();
0058         instance = new SnoreCore(qApp);
0059         SnoreCorePrivate::instance()->init();
0060     }
0061     return *instance;
0062 }
0063 
0064 SnoreCore::~SnoreCore()
0065 {
0066     Q_D(SnoreCore);
0067     d->deleteLater();
0068 }
0069 
0070 void SnoreCore::loadPlugins(SnorePlugin::PluginTypes types)
0071 {
0072     if (QThread::currentThread() != thread()) {
0073         qCDebug(SNORE) << "Delayed Plugin loading." << QThread::currentThread() << thread();
0074         QMetaObject::invokeMethod(this, "loadPlugins", Qt::BlockingQueuedConnection, Q_ARG(Snore::SnorePlugin::PluginTypes, types));
0075         return;
0076     }
0077     Q_D(SnoreCore);
0078     setSettingsValue(Constants::SettingsKeys::PluginTypes, QVariant::fromValue(types));
0079     qCDebug(SNORE) << "Loading plugin types:" << types;
0080     foreach(const SnorePlugin::PluginTypes type, SnorePlugin::types()) {
0081         if (type != SnorePlugin::All && types & type) {
0082             foreach(PluginContainer * info, PluginContainer::pluginCache(type).values()) {
0083                 SnorePlugin *plugin = info->load();
0084                 if (!plugin) {
0085                     continue;
0086                 }
0087 
0088                 switch (info->type()) {
0089                 case SnorePlugin::Backend:
0090                     break;
0091                 case SnorePlugin::SecondaryBackend:
0092                 case SnorePlugin::Frontend:
0093                 case SnorePlugin::Plugin:
0094                 case SnorePlugin::Settings:
0095                     plugin->setEnabled(plugin->settingsValue(Constants::SettingsKeys::Enabled).toBool());
0096                     break;
0097                 default:
0098                     qCWarning(SNORE) << "Plugin Cache corrupted\n" << info->file() << info->type();
0099                     continue;
0100                 }
0101 
0102                 qCDebug(SNORE) << info->name() << "is a" << info->type();
0103                 d->m_pluginNames[info->type()].append(info->name());
0104                 auto key = qMakePair(type, info->name());
0105                 Q_ASSERT_X(!d->m_plugins.contains(key), Q_FUNC_INFO, "Multiple plugins of the same type with the same name.");
0106                 d->m_plugins.insert(key, plugin);
0107             }
0108             if (d->m_pluginNames.contains(type)) {
0109                 qSort(d->m_pluginNames[type]);
0110             }
0111         }
0112     }
0113     d->slotInitPrimaryNotificationBackend();
0114     qCDebug(SNORE) << "Loaded Plugins:" << d->m_pluginNames;
0115 }
0116 
0117 void SnoreCore::broadcastNotification(Notification notification)
0118 {
0119     Q_D(SnoreCore);
0120     if (d->m_activeNotifications.size() >= d->maxNumberOfActiveNotifications()) {
0121         qCDebug(SNORE) << "queue size:" << d->m_notificationQue.size() << "active size:" << d->m_activeNotifications.size();
0122         d->m_notificationQue.append(notification);
0123         return;
0124     }
0125     Q_ASSERT_X(!notification.data()->isBroadcasted(), Q_FUNC_INFO, "Notification was already broadcasted.");
0126     qCDebug(SNORE) << "Broadcasting" << notification << "timeout:" << notification.timeout();
0127     if (d->m_notificationBackend != nullptr) {
0128         if (notification.isUpdate() && !d->m_notificationBackend->canUpdateNotification()) {
0129             requestCloseNotification(notification.old(), Notification::Replaced);
0130         }
0131     }
0132     notification.data()->setBroadcasted();
0133     notification.addActiveIn(this);
0134     if (!d->m_notificationBackend) {
0135         d->startNotificationTimeoutTimer(notification);
0136     }
0137     emit d->notify(notification);
0138 }
0139 
0140 void SnoreCore::registerApplication(const Application &application)
0141 {
0142     Q_D(SnoreCore);
0143     Q_ASSERT_X(!d->m_applications.contains(application.key()), Q_FUNC_INFO,
0144                "Applications mus be registered only once.");
0145     qCDebug(SNORE) << "Registering Application:" << application;
0146     d->m_applications.insert(application.key(), application);
0147     emit d->applicationRegistered(application);
0148 }
0149 
0150 void SnoreCore::deregisterApplication(const Application &application)
0151 {
0152     Q_D(SnoreCore);
0153     emit d->applicationDeregistered(application);
0154     d->m_applications.take(application.key());
0155 }
0156 
0157 const QHash<QString, Application> &SnoreCore::aplications() const
0158 {
0159     Q_D(const SnoreCore);
0160     return d->m_applications;
0161 }
0162 
0163 const QStringList SnoreCore::pluginNames(SnorePlugin::PluginTypes type) const
0164 {
0165     Q_D(const SnoreCore);
0166     QStringList out;
0167     for (auto t : SnorePlugin::types()) {
0168         if (t & type) {
0169             out.append(d->m_pluginNames.value(t));
0170         }
0171     }
0172     return out;
0173 }
0174 
0175 const QString SnoreCore::primaryNotificationBackend() const
0176 {
0177     Q_D(const SnoreCore);
0178     if (d->m_notificationBackend.isNull()) {
0179         return QString::null;
0180     }
0181     return d->m_notificationBackend->name();
0182 }
0183 
0184 bool SnoreCore::setPrimaryNotificationBackend(const QString &backend)
0185 {
0186     Q_D(SnoreCore);
0187     return d->setBackendIfAvailible(backend);
0188 }
0189 
0190 void SnoreCore::requestCloseNotification(Notification n, Notification::CloseReasons r)
0191 {
0192     Q_D(SnoreCore);
0193     bool wasQued  = d->m_notificationQue.removeOne(n);
0194     if (wasQued) {
0195         qCDebug(SNORE) << n << " was qued.";
0196     }
0197     if (!wasQued && d->m_notificationBackend) {
0198         d->m_notificationBackend->requestCloseNotification(n, r);
0199     } else {
0200         if (n.isValid()) {
0201             n.data()->setCloseReason(r);
0202             emit notificationClosed(n);
0203         }
0204     }
0205 }
0206 
0207 void SnoreCore::setDefaultApplication(const Application app)
0208 {
0209     Q_D(SnoreCore);
0210     d->m_defaultApp = app;
0211 }
0212 
0213 QVariant SnoreCore::settingsValue(const SettingsKey &key) const
0214 {
0215     Q_D(const SnoreCore);
0216     QString nk = d->normalizeSettingsKey(key.key, key.type);
0217     if (key.type == LocalSetting && !d->m_settings->contains(nk)) {
0218         nk = d->normalizeSettingsKey(key.key + QStringLiteral("-SnoreDefault"), key.type);
0219     }
0220     return d->m_settings->value(nk);
0221 }
0222 
0223 void SnoreCore::setSettingsValue(const SettingsKey &key, const QVariant &value)
0224 {
0225     Q_D(SnoreCore);
0226     d->m_settings->setValue(d->normalizeSettingsKey(key.key, key.type), value);
0227 }
0228 
0229 void SnoreCore::setDefaultSettingsValue(const SettingsKey &key, const QVariant &value)
0230 {
0231     Q_D(SnoreCore);
0232     QString nk = d->normalizeSettingsKey(key.key, key.type);
0233     if (!d->m_settings->contains(nk)) {
0234         qCDebug(SNORE) <<  "Set default value" << nk << value;
0235         d->m_settings->setValue(nk, value);
0236     }
0237 }
0238 
0239 Notification SnoreCore::getActiveNotificationByID(uint id) const
0240 {
0241     Q_D(const SnoreCore);
0242     return d->m_activeNotifications.value(id);
0243 }
0244 
0245 void SnoreCore::displayExampleNotification()
0246 {
0247     Application app = SnoreCorePrivate::instance()->defaultApplication();
0248     QString text = QLatin1String("<i>") + tr("This is %1").arg(app.name()) + QLatin1String("</i><br>"
0249                    "<b>") + tr("Everything is awesome!") + QLatin1String("</b><br>");
0250     if (!app.constHints().value("use-markup").toBool()) {
0251         text = Utils::normalizeMarkup(text, Utils::NoMarkup);
0252     }
0253     Notification noti(app, app.defaultAlert(), tr("Hello There!"), text, app.icon());
0254     noti.addAction(Action(1, tr("Awesome Action!")));
0255     broadcastNotification(noti);
0256 }