diff --git a/src/common/database/Database.cpp b/src/common/database/Database.cpp index 8b93342..5eacb98 100644 --- a/src/common/database/Database.cpp +++ b/src/common/database/Database.cpp @@ -1,292 +1,294 @@ /* * Copyright (C) 2014 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Database.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include "Debug.h" + namespace Common { namespace { #ifdef QT_DEBUG QString lastExecutedQuery; #endif std::mutex databases_mutex; struct DatabaseInfo { Qt::HANDLE thread; Database::OpenMode openMode; }; bool operator<(const DatabaseInfo &left, const DatabaseInfo &right) { return left.thread < right.thread ? true : left.thread > right.thread ? false : left.openMode < right.openMode; } std::map> databases; } class QSqlDatabaseWrapper { private: QSqlDatabase m_database; bool m_open; QString m_connectionName; public: QSqlDatabaseWrapper(const DatabaseInfo &info) : m_open(false) { m_connectionName = "kactivities_db_resources_" // Adding the thread number to the database name + QString::number((quintptr)info.thread) // And whether it is read-only or read-write + (info.openMode == Database::ReadOnly ? "_readonly" : "_readwrite"); m_database = QSqlDatabase::contains(m_connectionName) ? QSqlDatabase::database(m_connectionName) : QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), m_connectionName); if (info.openMode == Database::ReadOnly) { m_database.setConnectOptions(QStringLiteral("QSQLITE_OPEN_READONLY")); } // We are allowing the database file to be overridden mostly for testing purposes m_database.setDatabaseName(ResourcesDatabaseSchema::path()); m_open = m_database.open(); if (!m_open) { - qWarning() << "KActivities: Database is not open: " - << m_database.connectionName() - << m_database.databaseName() - << m_database.lastError(); + qCWarning(KAMD_LOG_RESOURCES) << "KActivities: Database is not open: " + << m_database.connectionName() + << m_database.databaseName() + << m_database.lastError(); if (info.openMode == Database::ReadWrite) { qFatal("KActivities: Opening the database in RW mode should always succeed"); } } } ~QSqlDatabaseWrapper() { - qDebug() << "Closing SQL connection: " << m_connectionName; + qCDebug(KAMD_LOG_RESOURCES) << "Closing SQL connection: " << m_connectionName; } QSqlDatabase &get() { return m_database; } bool isOpen() const { return m_open; } QString connectionName() const { return m_connectionName; } }; class Database::Private { public: Private() { } QSqlQuery query(const QString &query) { return database ? QSqlQuery(query, database->get()) : QSqlQuery(); } QSqlQuery query() { return database ? QSqlQuery(database->get()) : QSqlQuery(); } QScopedPointer database; }; Database::Locker::Locker(Database &database) : m_database(database.d->database->get()) { m_database.transaction(); } Database::Locker::~Locker() { m_database.commit(); } Database::Ptr Database::instance(Source source, OpenMode openMode) { Q_UNUSED(source) // for the time being std::lock_guard lock(databases_mutex); // We are saving instances per thread and per read/write mode DatabaseInfo info; info.thread = QThread::currentThreadId(); info.openMode = openMode; // Do we have an instance matching the request? auto search = databases.find(info); if (search != databases.end()) { auto ptr = search->second.lock(); if (ptr) { return ptr; } } // Creating a new database instance auto ptr = std::make_shared(); ptr->d->database.reset(new QSqlDatabaseWrapper(info)); if (!ptr->d->database->isOpen()) { return nullptr; } databases[info] = ptr; if (info.openMode == ReadOnly) { // From now on, only SELECT queries will work ptr->setPragma(QStringLiteral("query_only = 1")); // These should not make any difference ptr->setPragma(QStringLiteral("synchronous = 0")); } else { // Using the write-ahead log and sync = NORMAL for faster writes ptr->setPragma(QStringLiteral("synchronous = 1")); } // Maybe we should use the write-ahead log auto walResult = ptr->pragma(QStringLiteral("journal_mode = WAL")); if (walResult != "wal") { - qWarning() << "KActivities: Database can not be opened in WAL mode. Check the " - "SQLite version (required >3.7.0). And whether your filesystem " - "supports shared memory"; + qCWarning(KAMD_LOG_RESOURCES) << "KActivities: Database can not be opened in WAL mode. Check the " + "SQLite version (required >3.7.0). And whether your filesystem " + "supports shared memory"; return nullptr; } // We don't have a big database, lets flush the WAL when // it reaches 400k, not 4M as is default ptr->setPragma(QStringLiteral("wal_autocheckpoint = 100")); - qDebug() << "KActivities: Database connection: " << ptr->d->database->connectionName() + qCDebug(KAMD_LOG_RESOURCES) << "KActivities: Database connection: " << ptr->d->database->connectionName() << "\n query_only: " << ptr->pragma(QStringLiteral("query_only")) << "\n journal_mode: " << ptr->pragma(QStringLiteral("journal_mode")) << "\n wal_autocheckpoint: " << ptr->pragma(QStringLiteral("wal_autocheckpoint")) << "\n synchronous: " << ptr->pragma(QStringLiteral("synchronous")) ; return ptr; } Database::Database() { } Database::~Database() { } QSqlQuery Database::createQuery() const { return d->query(); } QString Database::lastQuery() const { #ifdef QT_DEBUG return lastExecutedQuery; #endif return QString(); } QSqlQuery Database::execQuery(const QString &query, bool ignoreErrors) const { #ifdef QT_NO_DEBUG return d->query(query); #else auto result = d->query(query); lastExecutedQuery = query; if (!ignoreErrors && result.lastError().isValid()) { - qWarning() << "SQL: " + qCWarning(KAMD_LOG_RESOURCES) << "SQL: " << "\n error: " << result.lastError() << "\n query: " << query; } return result; #endif } QSqlQuery Database::execQueries(const QStringList &queries) const { QSqlQuery result; for (const auto query: queries) { result = execQuery(query); } return result; } void Database::setPragma(const QString &pragma) { execQuery(QStringLiteral("PRAGMA ") + pragma); } QVariant Database::pragma(const QString &pragma) const { return value("PRAGMA " + pragma); } QVariant Database::value(const QString &query) const { auto result = execQuery(query); return result.next() ? result.value(0) : QVariant(); } } // namespace Common diff --git a/src/common/database/Database.h b/src/common/database/Database.h index 5a7df81..315c725 100644 --- a/src/common/database/Database.h +++ b/src/common/database/Database.h @@ -1,152 +1,152 @@ /* * Copyright 2014 Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COMMON_DATABASE_H #define COMMON_DATABASE_H #include #include #include #include namespace Common { class Database { public: typedef std::shared_ptr Ptr; enum Source { ResourcesDatabase }; enum OpenMode { ReadWrite, ReadOnly }; static Ptr instance(Source source, OpenMode openMode); QSqlQuery execQueries(const QStringList &queries) const; QSqlQuery execQuery(const QString &query, bool ignoreErrors = false) const; QSqlQuery createQuery() const; void setPragma(const QString &pragma); QVariant pragma(const QString &pragma) const; QVariant value(const QString &query) const; // For debugging purposes only QString lastQuery() const; ~Database(); Database(); friend class Locker; class Locker { public: Locker(Database &database); ~Locker(); private: QSqlDatabase &m_database; }; #define DATABASE_TRANSACTION(A) \ - /* enable this for debugging only: qDebug() << "Location:" << __FILE__ << __LINE__; */ \ + /* enable this for debugging only: qCDebug(KAMD_LOG_RESOURCES) << "Location:" << __FILE__ << __LINE__; */ \ Common::Database::Locker lock(A) private: D_PTR; }; template QString parseStarPattern(const QString &pattern, const QString &joker, EscapeFunction escape) { const auto begin = pattern.constBegin(); const auto end = pattern.constEnd(); auto currentStart = pattern.constBegin(); auto currentPosition = pattern.constBegin(); bool isEscaped = false; // This should be available in the QString class... auto stringFromIterators = [&](const QString::const_iterator ¤tStart, const QString::const_iterator ¤tPosition) { return pattern.mid( std::distance(begin, currentStart), std::distance(currentStart, currentPosition)); }; // Escaping % and _ for sql like // auto escape = [] (QString str) { // return str.replace("%", "\\%").replace("_", "\\_"); // }; QString resultPattern; resultPattern.reserve(pattern.size() * 1.5); for (; currentPosition != end; ++currentPosition) { if (isEscaped) { // Just skip the current character isEscaped = false; } else if (*currentPosition == '\\') { // Skip two characters isEscaped = true; } else if (*currentPosition == '*') { // Replacing the star with the sql like joker - % resultPattern.append(escape(stringFromIterators( currentStart, currentPosition)) + joker); currentStart = currentPosition + 1; } else { // This one is boring, nothing to do } } if (currentStart != currentPosition) { resultPattern.append(escape(stringFromIterators( currentStart, currentPosition))); } return resultPattern; } inline QString escapeSqliteLikePattern(QString pattern) { return pattern.replace(QLatin1String("%"), QLatin1String("\\%")).replace(QLatin1String("_"), QLatin1String("\\_")); } inline QString starPatternToLike(const QString &pattern) { return parseStarPattern(pattern, QStringLiteral("%"), escapeSqliteLikePattern); } inline QRegExp starPatternToRegex(const QString &pattern) { return QRegExp(parseStarPattern(pattern, QStringLiteral(".*"), QRegExp::escape)); } } // namespace Common #endif // COMMON_DATABASE_H diff --git a/src/service/Activities.cpp b/src/service/Activities.cpp index abdf263..e2504ec 100644 --- a/src/service/Activities.cpp +++ b/src/service/Activities.cpp @@ -1,599 +1,599 @@ /* * Copyright (C) 2010 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // Self #include #include "Activities.h" #include "Activities_p.h" // Qt #include #include #include #include #include #include // KDE #include #include #include #include #include // Utils #include #include // Local #include "Debug.h" #include "activitiesadaptor.h" #include "ksmserver/KSMServer.h" #include "common/dbus/common.h" // Private #define ACTIVITY_MANAGER_CONFIG_FILE_NAME QStringLiteral("kactivitymanagerdrc") Activities::Private::KDE4ConfigurationTransitionChecker::KDE4ConfigurationTransitionChecker() { // Checking whether we need to transfer the KActivities/KDE4 // configuration file to the new location. const QString newConfigLocation = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + '/' + ACTIVITY_MANAGER_CONFIG_FILE_NAME; if (QFile(newConfigLocation).exists()) { return; } // Testing for kdehome Kdelibs4Migration migration; if (!migration.kdeHomeFound()) { return; } QString oldConfigFile(migration.locateLocal("config", "activitymanagerrc")); if (!oldConfigFile.isEmpty()) { QFile(oldConfigFile).copy(newConfigLocation); } } Activities::Private::Private(Activities *parent) : kde4ConfigurationTransitionChecker() , config(QStringLiteral("kactivitymanagerdrc")) , q(parent) { // qCDebug(KAMD_ACTIVITIES) << "Using this configuration file:" // << config.name() // << config.locationType() // << QStandardPaths::standardLocations(config.locationType()) // ; // Reading activities from the config file. // Saving only the running activities means that if we have any // errors in the config, we might end up with all activities // stopped const auto defaultState = !mainConfig().hasKey("runningActivities") ? Activities::Running : !mainConfig().hasKey("stoppedActivities") ? Activities::Stopped : Activities::Running; const auto runningActivities = mainConfig().readEntry("runningActivities", QStringList()).toSet(); const auto stoppedActivities = mainConfig().readEntry("stoppedActivities", QStringList()).toSet(); // Do we have a running activity? bool atLeastOneRunning = false; for (const auto &activity: activityNameConfig().keyList()) { auto state = runningActivities.contains(activity) ? Activities::Running : stoppedActivities.contains(activity) ? Activities::Stopped : defaultState; activities[activity] = state; if (state == Activities::Running) { atLeastOneRunning = true; } } // Is this our first start? if (activities.isEmpty()) { // We need to add this only after the service has been properly started KConfigGroup cg(KSharedConfig::openConfig("kdeglobals"), "Activities"); //NOTE: config key still singular for retrocompatibility const QStringList names = cg.readEntry("defaultActivityName", QStringList{i18n("Default")}); for (const auto &name : names) { QMetaObject::invokeMethod( q, "AddActivity", Qt::QueuedConnection, Q_ARG(QString, name)); } } else if (!atLeastOneRunning) { // If we have no running activities, but we have activities, // we are in a problem. This should not happen unless the // configuration file is in a big problem and told us there // are no running activities, and enlists all of them as stopped. // In that case, we will pretend all of them are running - qWarning() << "The config file enlisted all activities as stopped"; + qCWarning(KAMD_LOG_ACTIVITIES) << "The config file enlisted all activities as stopped"; for (const auto &keys: activities.keys()) { activities[keys] = Activities::Running; } } } void Activities::Private::loadLastActivity() { // This is called from constructor, no need for locking // If there are no public activities, try to load the last used activity const auto lastUsedActivity = mainConfig().readEntry("currentActivity", QString()); setCurrentActivity( (lastUsedActivity.isEmpty() && activities.size() > 0) ? activities.keys().at(0) : lastUsedActivity); } Activities::Private::~Private() { configSync(); } bool Activities::Private::setCurrentActivity(const QString &activity) { { // There is nothing expensive in this block, not a problem to lock QWriteLocker lock(&activitiesLock); // Should we change the activity at all? if (currentActivity == activity) { return true; } // If the activity is empty, this means we are entering a limbo state if (activity.isEmpty()) { currentActivity.clear(); emit q->CurrentActivityChanged(currentActivity); return true; } // Does the requested activity exist? if (!activities.contains(activity)) { return false; } } // Start activity q->StartActivity(activity); // Saving the current activity, and notifying // clients of the change currentActivity = activity; mainConfig().writeEntry("currentActivity", activity); scheduleConfigSync(); emit q->CurrentActivityChanged(activity); return true; } QString Activities::Private::addActivity(const QString &name) { QString activity; if (name.isEmpty()) { Q_ASSERT(!name.isEmpty()); return activity; } int activitiesCount = 0; { QWriteLocker lock(&activitiesLock); // Ensuring a new Uuid. The loop should usually end after only // one iteration while (activity.isEmpty() || activities.contains(activity)) { activity = QUuid::createUuid().toString().mid(1, 36); } // Saves the activity info to the config activities[activity] = Invalid; activitiesCount = activities.size(); } setActivityState(activity, Running); q->SetActivityName(activity, name); emit q->ActivityAdded(activity); scheduleConfigSync(); if (activitiesCount == 1) { q->SetCurrentActivity(activity); } return activity; } void Activities::Private::removeActivity(const QString &activity) { Q_ASSERT(!activity.isEmpty()); // Sanity checks { QWriteLocker lock(&activitiesLock); if (!activities.contains(activity)) { return; } // Is somebody trying to remove the last activity? if (activities.size() == 1) { return; } } // If the activity is running, stash it q->StopActivity(activity); setActivityState(activity, Activities::Invalid); bool currentActivityDeleted = false; { QWriteLocker lock(&activitiesLock); // Removing the activity activities.remove(activity); // If the removed activity was the current one, // set another activity as current currentActivityDeleted = (currentActivity == activity); } activityNameConfig().deleteEntry(activity); activityDescriptionConfig().deleteEntry(activity); activityIconConfig().deleteEntry(activity); if (currentActivityDeleted) { ensureCurrentActivityIsRunning(); } emit q->ActivityRemoved(activity); QMetaObject::invokeMethod(q, "ActivityRemoved", Qt::QueuedConnection, Q_ARG(QString, activity)); QMetaObject::invokeMethod(this, "configSync", Qt::QueuedConnection); } void Activities::Private::scheduleConfigSync() { static const auto shortInterval = 1000; // If the timer is not running, or has a longer interval than we need, // start it // Note: If you want to add multiple different delays for different // events based on the importance of how quickly something needs // to be synced to the config, don't. Since the QTimer lives in a // separate thread, we have to communicate with it in via // queued connections, which means that we don't know whether // the timer was already started when this method was invoked, // we do not know whether the interval is properly set etc. if (!configSyncTimer.isActive()) { QMetaObject::invokeMethod( &configSyncTimer, "start", Qt::QueuedConnection, Q_ARG(int, shortInterval)); } } void Activities::Private::configSync() { // Stop the timer and reset the interval to zero QMetaObject::invokeMethod(&configSyncTimer, "stop", Qt::QueuedConnection); config.sync(); } void Activities::Private::setActivityState(const QString &activity, Activities::State state) { bool configNeedsUpdating = false; { QWriteLocker lock(&activitiesLock); Q_ASSERT(activities.contains(activity)); if (activities.value(activity) == state) { return; } // Treating 'Starting' as 'Running', and 'Stopping' as 'Stopped' // as far as the config file is concerned configNeedsUpdating = ((activities[activity] & 4) != (state & 4)); activities[activity] = state; } switch (state) { case Activities::Running: emit q->ActivityStarted(activity); break; case Activities::Stopped: emit q->ActivityStopped(activity); break; default: break; } emit q->ActivityStateChanged(activity, state); if (configNeedsUpdating) { QReadLocker lock(&activitiesLock); mainConfig().writeEntry("runningActivities", activities.keys(Activities::Running) + activities.keys(Activities::Starting)); mainConfig().writeEntry("stoppedActivities", activities.keys(Activities::Stopped) + activities.keys(Activities::Stopping)); scheduleConfigSync(); } } void Activities::Private::ensureCurrentActivityIsRunning() { // If the current activity is not running, // make some other activity current const auto runningActivities = q->ListActivities(Activities::Running); if (!runningActivities.contains(currentActivity) && runningActivities.size() > 0) { setCurrentActivity(runningActivities.first()); } } void Activities::Private::activitySessionStateChanged(const QString &activity, int status) { QString currentActivity = this->currentActivity; { QReadLocker lock(&activitiesLock); if (!activities.contains(activity)) { return; } } switch (status) { case KSMServer::Started: case KSMServer::FailedToStop: setActivityState(activity, Activities::Running); break; case KSMServer::Stopped: setActivityState(activity, Activities::Stopped); if (currentActivity == activity) { ensureCurrentActivityIsRunning(); } break; } QMetaObject::invokeMethod(this, "configSync", Qt::QueuedConnection); } // Main Activities::Activities(QObject *parent) : Module(QStringLiteral("activities"), parent) , d(this) { qCDebug(KAMD_LOG_ACTIVITIES) << "Starting the KDE Activity Manager daemon" << QDateTime::currentDateTime(); // Basic initialization //////////////////////////////////////////////////// // Initializing D-Bus service new ActivitiesAdaptor(this); KDBusConnectionPool::threadConnection().registerObject( KAMD_DBUS_OBJECT_PATH(Activities), this); // Initializing config - qDebug() << "Config timer connecting..."; + qCDebug(KAMD_LOG_ACTIVITIES) << "Config timer connecting..."; d->connect(&d->configSyncTimer, SIGNAL(timeout()), SLOT(configSync()), Qt::QueuedConnection); d->configSyncTimer.setSingleShot(true); d->ksmserver = new KSMServer(this); d->connect(d->ksmserver, SIGNAL(activitySessionStateChanged(QString, int)), SLOT(activitySessionStateChanged(QString, int))); // Loading the last used activity, if possible d->loadLastActivity(); } Activities::~Activities() { } QString Activities::CurrentActivity() const { QReadLocker lock(&d->activitiesLock); return d->currentActivity; } bool Activities::SetCurrentActivity(const QString &activity) { // Public method can not put us in a limbo state if (activity.isEmpty()) { return false; } return d->setCurrentActivity(activity); } QString Activities::AddActivity(const QString &name) { // We do not care about authorization if this is the first start if (!d->activities.isEmpty() && !KAuthorized::authorize("plasma-desktop/add_activities")) { return QString(); } return d->addActivity(name); } void Activities::RemoveActivity(const QString &activity) { if (!KAuthorized::authorize("plasma-desktop/add_activities")) { return; } d->removeActivity(activity); } QStringList Activities::ListActivities() const { QReadLocker lock(&d->activitiesLock); return d->activities.keys(); } QStringList Activities::ListActivities(int state) const { QReadLocker lock(&d->activitiesLock); return d->activities.keys((State)state); } QList Activities::ListActivitiesWithInformation() const { using namespace kamd::utils; // Mapping activity ids to info return as_collection>( ListActivities() | transformed(&Activities::ActivityInformation, this) ); } ActivityInfo Activities::ActivityInformation(const QString &activity) const { return ActivityInfo { activity, ActivityName(activity), ActivityDescription(activity), ActivityIcon(activity), ActivityState(activity) }; } #define CREATE_GETTER_AND_SETTER(What) \ QString Activities::Activity##What(const QString &activity) const \ { \ QReadLocker lock(&d->activitiesLock); \ return d->activities.contains(activity) ? d->activity##What(activity) \ : QString(); \ } \ \ void Activities::SetActivity##What(const QString &activity, \ const QString &value) \ { \ { \ QReadLocker lock(&d->activitiesLock); \ if (value == d->activity##What(activity) \ || !d->activities.contains(activity)) { \ return; \ } \ } \ \ d->activity##What##Config().writeEntry(activity, value); \ d->scheduleConfigSync(); \ \ emit Activity##What##Changed(activity, value); \ emit ActivityChanged(activity); \ } CREATE_GETTER_AND_SETTER(Name) CREATE_GETTER_AND_SETTER(Description) CREATE_GETTER_AND_SETTER(Icon) #undef CREATE_GETTE_AND_SETTERR // Main void Activities::StartActivity(const QString &activity) { { QReadLocker lock(&d->activitiesLock); if (!d->activities.contains(activity) || d->activities[activity] != Stopped) { return; } } d->setActivityState(activity, Starting); d->ksmserver->startActivitySession(activity); } void Activities::StopActivity(const QString &activity) { { QReadLocker lock(&d->activitiesLock); if (!d->activities.contains(activity) || d->activities[activity] == Stopped || d->activities.size() == 1 || d->activities.keys(Activities::Running).size() <= 1 ) { return; } } d->setActivityState(activity, Stopping); d->ksmserver->stopActivitySession(activity); } int Activities::ActivityState(const QString &activity) const { QReadLocker lock(&d->activitiesLock); return d->activities.contains(activity) ? d->activities[activity] : Invalid; } diff --git a/src/service/Application.cpp b/src/service/Application.cpp index 7ae5d6f..8c332cb 100644 --- a/src/service/Application.cpp +++ b/src/service/Application.cpp @@ -1,425 +1,425 @@ /* * Copyright (C) 2010 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // Self #include #include "Application.h" // Qt #include #include #include #include #include #include // KDE // #include // #include // #include #include #include #include #include #include // Boost and utils #include #include #include // System #include #include #include #include // Local #include "Activities.h" #include "Resources.h" #include "Features.h" #include "Config.h" #include "Plugin.h" #include "Debug.h" #include "common/dbus/common.h" namespace { QList s_moduleThreads; } // Runs a QObject inside a QThread template T *runInQThread() { T *object = new T(); class Thread : public QThread { public: Thread(T *ptr = Q_NULLPTR) : QThread() , object(ptr) { } void run() Q_DECL_OVERRIDE { std::unique_ptr o(object); exec(); } private: T *object; } *thread = new Thread(object); s_moduleThreads << thread; object->moveToThread(thread); thread->start(); return object; } class Application::Private { public: Private() { } static inline bool isPluginEnabled(const KConfigGroup &config, const KPluginMetaData& plugin) { const auto pluginName = plugin.pluginId(); qCDebug(KAMD_LOG_APPLICATION) << "Plugin Name is " << pluginName << plugin.fileName(); if (pluginName == "org.kde.ActivityManager.ResourceScoring") { // SQLite plugin is necessary for the proper workspace behaviour return true; } else { return config.readEntry(pluginName + "Enabled", plugin.isEnabledByDefault()); } } bool loadPlugin(const KPluginMetaData& plugin); Resources *resources; Activities *activities; Features *features; QStringList pluginIds; QList plugins; static Application *s_instance; }; Application *Application::Private::s_instance = Q_NULLPTR; Application::Application(int &argc, char **argv) : QApplication(argc, argv) { } void Application::init() { if (!KDBusConnectionPool::threadConnection().registerService( KAMD_DBUS_SERVICE)) { QCoreApplication::exit(EXIT_SUCCESS); } // KAMD is a daemon, if it crashes it is not a problem as // long as it restarts properly // TODO: Restart on crash // KCrash::setFlags(KCrash::AutoRestart); d->resources = runInQThread(); d->activities = runInQThread(); d->features = runInQThread(); /* d->config */ new Config(this); // this does not need a separate thread QMetaObject::invokeMethod(this, "loadPlugins", Qt::QueuedConnection); QDBusConnection::sessionBus().registerObject("/ActivityManager", this, QDBusConnection::ExportAllSlots); } bool Application::Private::loadPlugin(const KPluginMetaData& plugin) { if (!plugin.isValid()) { qCWarning(KAMD_LOG_APPLICATION) << "[ FAILED ] plugin offer not valid"; return false; } if (pluginIds.contains(plugin.pluginId())) { qCDebug(KAMD_LOG_APPLICATION) << "[ OK ] already loaded: " << plugin.pluginId(); return true; } KPluginLoader loader(plugin.fileName()); KPluginFactory* factory = loader.factory(); if (!factory) { qCWarning(KAMD_LOG_APPLICATION) << "[ FAILED ] Could not load KPluginFactory for:" << plugin.pluginId() << loader.errorString(); return false; } auto pluginInstance = factory->create(); auto &modules = Module::get(); if (pluginInstance) { bool success = pluginInstance->init(modules); if (success) { pluginIds << plugin.pluginId(); plugins << pluginInstance; qCDebug(KAMD_LOG_APPLICATION) << "[ OK ] loaded: " << plugin.pluginId(); return true; } else { qCWarning(KAMD_LOG_APPLICATION) << "[ FAILED ] init: " << plugin.pluginId() << loader.errorString(); // TODO: Show a notification for a plugin that failed to load delete pluginInstance; return false; } } else { qCWarning(KAMD_LOG_APPLICATION) << "[ FAILED ] loading: " << plugin.pluginId() << loader.errorString(); // TODO: Show a notification for a plugin that failed to load return false; } } void Application::loadPlugins() { using namespace std::placeholders; const auto config = KSharedConfig::openConfig(QStringLiteral("kactivitymanagerdrc")) ->group("Plugins"); const auto offers = KPluginLoader::findPlugins(QStringLiteral(KAMD_PLUGIN_DIR), std::bind(Private::isPluginEnabled, config, _1)); qCDebug(KAMD_LOG_APPLICATION) << "Found" << offers.size() << "enabled plugins:"; for (const auto &offer : offers) { d->loadPlugin(offer); } } bool Application::loadPlugin(const QString &pluginId) { auto offers = KPluginLoader::findPluginsById(QStringLiteral(KAMD_PLUGIN_DIR), pluginId); if (offers.isEmpty()) { qCWarning(KAMD_LOG_APPLICATION) << "[ FAILED ] not found: " << pluginId; return false; } return d->loadPlugin(offers.first()); } Application::~Application() { - qDebug() << "Cleaning up..."; + qCDebug(KAMD_LOG_APPLICATION) << "Cleaning up..."; // Waiting for the threads to finish for (const auto thread : s_moduleThreads) { thread->quit(); thread->wait(); delete thread; } // Deleting plugin objects for (const auto plugin : d->plugins) { delete plugin; } Private::s_instance = Q_NULLPTR; } int Application::newInstance() { //We don't want to show the mainWindow() return 0; } Activities &Application::activities() const { return *d->activities; } Resources &Application::resources() const { return *d->resources; } // void Application::quit() // { // if (Private::s_instance) { // Private::s_instance->exit(); // delete Private::s_instance; // } // } void Application::quit() { QApplication::quit(); } #include "Version.h" QString Application::serviceVersion() const { return KACTIVITIES_VERSION_STRING; } // Leaving object oriented world :) namespace { template Return callOnRunningService(const QString &method) { static QDBusInterface remote(KAMD_DBUS_SERVICE, "/ActivityManager", "org.kde.ActivityManager.Application"); QDBusReply reply = remote.call(method); return (Return)reply; } QString runningServiceVersion() { return callOnRunningService("serviceVersion"); } bool isServiceRunning() { return QDBusConnection::sessionBus().interface()->isServiceRegistered( KAMD_DBUS_SERVICE); } } int main(int argc, char **argv) { // Disable session management for this process qunsetenv("SESSION_MANAGER"); QGuiApplication::setDesktopSettingsAware(false); Application application(argc, argv); application.setApplicationName(QStringLiteral("ActivityManager")); application.setOrganizationDomain(QStringLiteral("kde.org")); // KAboutData about("kactivitymanagerd", Q_NULLPTR, ki18n("KDE Activity Manager"), "3.0", // ki18n("KDE Activity Management Service"), // KAboutData::License_GPL, // ki18n("(c) 2010, 2011, 2012 Ivan Cukic"), KLocalizedString(), // "http://www.kde.org/"); // KCmdLineArgs::init(argc, argv, &about); const auto arguments = application.arguments(); if (arguments.size() == 0) { QCoreApplication::exit(EXIT_FAILURE); } else if (arguments.size() != 1 && (arguments.size() != 2 || arguments[1] == "--help")) { QTextStream(stdout) << "start\tStarts the service\n" << "stop\tStops the server\n" << "status\tPrints basic server information\n" << "start-daemon\tStarts the service without forking (use with caution)\n" << "--help\tThis help message\n"; QCoreApplication::exit(EXIT_SUCCESS); } else if (arguments.size() == 1 || arguments[1] == "start") { // Checking whether the service is already running if (isServiceRunning()) { QTextStream(stdout) << "Already running\n"; QCoreApplication::exit(EXIT_SUCCESS); } // Creating the watcher, but not on the wall QDBusServiceWatcher watcher(KAMD_DBUS_SERVICE, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForRegistration); QObject::connect(&watcher, &QDBusServiceWatcher::serviceRegistered, [] (const QString &service) { QTextStream(stdout) << "Service started, version: " << runningServiceVersion() << "\n"; QCoreApplication::exit(EXIT_SUCCESS); }); // Starting the dameon QProcess::startDetached( KAMD_INSTALL_PREFIX "/bin/kactivitymanagerd", QStringList{"start-daemon"} ); return application.exec(); } else if (arguments[1] == "stop") { if (!isServiceRunning()) { QTextStream(stdout) << "Service not running\n"; QCoreApplication::exit(EXIT_SUCCESS); } callOnRunningService("quit"); QTextStream(stdout) << "Service stopped\n"; return EXIT_SUCCESS; } else if (arguments[1] == "status") { // Checking whether the service is already running if (isServiceRunning()) { QTextStream(stdout) << "The service is running, version: " << runningServiceVersion() << "\n"; } else { QTextStream(stdout) << "The service is not running\n"; } return EXIT_SUCCESS; } else if (arguments[1] == "start-daemon") { // Really starting the activity manager KDBusService service(KDBusService::Unique); application.init(); return application.exec(); } else { QTextStream(stdout) << "Unrecognized command: " << arguments[1] << '\n'; return EXIT_FAILURE; } } diff --git a/src/service/Plugin.cpp b/src/service/Plugin.cpp index 5dbb940..323cc77 100644 --- a/src/service/Plugin.cpp +++ b/src/service/Plugin.cpp @@ -1,91 +1,91 @@ /* * Copyright (C) 2011 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // Self #include "Plugin.h" // KDE #include // Utils #include // Local #include "Debug.h" class Plugin::Private { public: Private() : config(Q_NULLPTR) { } QString name; KSharedConfig::Ptr config; }; Plugin::Plugin(QObject *parent) : Module(QString(), parent) , d() { } Plugin::~Plugin() { } KConfigGroup Plugin::config() const { if (d->name.isEmpty()) { - qWarning() << "The plugin needs a name in order to have a config section"; + qCWarning(KAMD_LOG_APPLICATION) << "The plugin needs a name in order to have a config section"; return KConfigGroup(); } if (!d->config) { d->config = KSharedConfig::openConfig(QStringLiteral("kactivitymanagerd-pluginsrc")); } return d->config->group(QStringLiteral("Plugin-") + d->name); } void Plugin::setName(const QString &name) { Q_ASSERT_X(d->name.isEmpty(), "Plugin::setName", "The name can not be set twice"); Q_ASSERT_X(!name.isEmpty(), "Plugin::setName", "The name can not be empty"); - qDebug() << "Setting the name of " << (void*)this << " to " << name; + qCDebug(KAMD_LOG_APPLICATION) << "Setting the name of " << (void*)this << " to " << name; d->name = name; } QString Plugin::name() const { return d->name; } bool Plugin::init(QHash &modules) { if (!name().isEmpty()) { modules[name()] = this; } return true; } diff --git a/src/service/ksmserver/KSMServer.cpp b/src/service/ksmserver/KSMServer.cpp index 3dec16b..6d59af5 100644 --- a/src/service/ksmserver/KSMServer.cpp +++ b/src/service/ksmserver/KSMServer.cpp @@ -1,236 +1,236 @@ /* * Copyright (C) 2012 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // Self #include "KSMServer.h" #include "KSMServer_p.h" // Qt #include #include #include #include #include #include // KDE #include // Utils #include // Local #include #define KWIN_SERVICE QStringLiteral("org.kde.KWin") KSMServer::Private::Private(KSMServer *parent) : serviceWatcher(new QDBusServiceWatcher(this)) , kwin(Q_NULLPTR) , processing(false) , q(parent) { serviceWatcher->setConnection(KDBusConnectionPool::threadConnection()); serviceWatcher->addWatchedService(KWIN_SERVICE); connect(serviceWatcher.get(), &QDBusServiceWatcher::serviceOwnerChanged, this, &Private::serviceOwnerChanged); serviceOwnerChanged(KWIN_SERVICE, QString(), QString()); } void KSMServer::Private::serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner) { Q_UNUSED(oldOwner); Q_UNUSED(newOwner); if (service == KWIN_SERVICE) { // Delete the old object, just in case delete kwin; kwin = Q_NULLPTR; if (KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(KWIN_SERVICE)) { // Creating the new dbus interface // TODO: in multi-head environment there are multiple kwin instances // running and they will export different dbus name on different // root window. We have no support for that currently. // In future, the session management for Wayland may also need to be // reimplemented in some way. kwin = new QDBusInterface(KWIN_SERVICE, QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin")); // If the service is valid, initialize it // otherwise delete the object if (kwin->isValid()) { kwin->setParent(this); } else { delete kwin; kwin = Q_NULLPTR; } } } } KSMServer::KSMServer(QObject *parent) : QObject(parent) , d(this) { } KSMServer::~KSMServer() { } void KSMServer::startActivitySession(const QString &activity) { d->processLater(activity, true); } void KSMServer::stopActivitySession(const QString &activity) { d->processLater(activity, false); } void KSMServer::Private::processLater(const QString &activity, bool start) { if (kwin) { for (const auto &item: queue) { if (item.first == activity) { return; } } queue << qMakePair(activity, start); if (!processing) { processing = true; QMetaObject::invokeMethod(this, "process", Qt::QueuedConnection); } } else { // We don't have kwin. No way to invoke the session stuff subSessionSendEvent(start ? KSMServer::Started : KSMServer::Stopped); } } void KSMServer::Private::process() { // If the queue is empty, we have nothing more to do if (queue.isEmpty()) { processing = false; return; } const auto item = queue.takeFirst(); processingActivity = item.first; makeRunning(item.second); // Calling process again for the rest of the list QMetaObject::invokeMethod(this, "process", Qt::QueuedConnection); } void KSMServer::Private::makeRunning(bool value) { if (!kwin) { - qDebug() << "Activities KSM: No kwin, marking activity as: " << value; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: No kwin, marking activity as: " << value; subSessionSendEvent(value ? KSMServer::Started : KSMServer::Stopped); return; } const auto call = kwin->asyncCall( value ? QLatin1String("startActivity") : QLatin1String("stopActivity"), processingActivity); const auto watcher = new QDBusPendingCallWatcher(call, this); - qDebug() << "Activities KSM: Telling kwin to start/stop activity : " << processingActivity << value; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: Telling kwin to start/stop activity : " << processingActivity << value; QObject::connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, value ? SLOT(startCallFinished(QDBusPendingCallWatcher *)) : SLOT(stopCallFinished(QDBusPendingCallWatcher *))); } void KSMServer::Private::startCallFinished(QDBusPendingCallWatcher *call) { - qDebug() << "Activities KSM: Start call is finished"; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: Start call is finished"; QDBusPendingReply reply = *call; if (reply.isError()) { - qDebug() << "Activities KSM: Error in getting a reply for start, marking as started"; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: Error in getting a reply for start, marking as started"; subSessionSendEvent(KSMServer::Started); } else { // If we got false, it means something is going on with ksmserver // and it didn't start our activity const auto retval = reply.argumentAt<0>(); if (!retval) { - qDebug() << "Activities KSM: Error starting, marking as stopped"; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: Error starting, marking as stopped"; subSessionSendEvent(KSMServer::Stopped); } else { - qDebug() << "Activities KSM: All OK starting, marking as starting"; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: All OK starting, marking as starting"; subSessionSendEvent(KSMServer::Started); } } call->deleteLater(); } void KSMServer::Private::stopCallFinished(QDBusPendingCallWatcher *call) { - qDebug() << "Activities KSM: Stop call is finished"; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: Stop call is finished"; QDBusPendingReply reply = *call; if (reply.isError()) { - qDebug() << "Activities KSM: Error in getting a reply for stop, marking as stopped"; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: Error in getting a reply for stop, marking as stopped"; subSessionSendEvent(KSMServer::Stopped); } else { // If we got false, it means something is going on with ksmserver // and it didn't stop our activity const auto retval = reply.argumentAt<0>(); if (!retval) { - qDebug() << "Activities KSM: Error stopping, marking as started"; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: Error stopping, marking as started"; subSessionSendEvent(KSMServer::FailedToStop); } else { - qDebug() << "Activities KSM: All OK stopping, marking as stopped"; + qCDebug(KAMD_LOG_ACTIVITIES) << "Activities KSM: All OK stopping, marking as stopped"; subSessionSendEvent(KSMServer::Stopped); } } call->deleteLater(); } void KSMServer::Private::subSessionSendEvent(int event) { if (processingActivity.isEmpty()) { return; } emit q->activitySessionStateChanged(processingActivity, event); processingActivity.clear(); } diff --git a/src/service/plugins/runapplication/CMakeLists.txt b/src/service/plugins/runapplication/CMakeLists.txt index f656415..fcafccb 100644 --- a/src/service/plugins/runapplication/CMakeLists.txt +++ b/src/service/plugins/runapplication/CMakeLists.txt @@ -1,42 +1,43 @@ # vim:set softtabstop=3 shiftwidth=3 tabstop=3 expandtab: project (kactivitymanagerd-runapplication) include_directories ( ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_BINARY_DIR} ${KConfig_INCLUDE_DIR} ) set ( runapplication_SRCS RunApplicationPlugin.cpp + ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/service/Debug.cpp ${plugin_implementation_SRCS} ) kcoreaddons_add_plugin ( kactivitymanagerd_plugin_runapplication JSON kactivitymanagerd-plugin-runapplication.json SOURCES ${runapplication_SRCS} INSTALL_NAMESPACE ${KAMD_PLUGIN_DIR} ) target_link_libraries ( kactivitymanagerd_plugin_runapplication Qt5::Core Qt5::DBus Qt5::Gui KF5::CoreAddons KF5::ConfigCore KF5::Service kactivitymanagerd_plugin ) set_target_properties ( kactivitymanagerd_plugin_runapplication PROPERTIES PREFIX "" ) diff --git a/src/service/plugins/runapplication/RunApplicationPlugin.cpp b/src/service/plugins/runapplication/RunApplicationPlugin.cpp index 6a0899b..4c88b0d 100644 --- a/src/service/plugins/runapplication/RunApplicationPlugin.cpp +++ b/src/service/plugins/runapplication/RunApplicationPlugin.cpp @@ -1,137 +1,137 @@ /* * Copyright (C) 2012, 2013, 2014 Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "RunApplicationPlugin.h" #include #include #include #include #include #include #include #include namespace { enum ActivityState { Running = 2, Stopped = 4 }; } KAMD_EXPORT_PLUGIN(runapplicationplugin, RunApplicationPlugin, "kactivitymanagerd-plugin-runapplication.json") RunApplicationPlugin::RunApplicationPlugin(QObject *parent, const QVariantList &args) : Plugin(parent) , m_activitiesService(Q_NULLPTR) { Q_UNUSED(args); setName("org.kde.ActivityManager.RunApplication"); } RunApplicationPlugin::~RunApplicationPlugin() { } bool RunApplicationPlugin::init(QHash &modules) { Plugin::init(modules); m_activitiesService = modules["activities"]; connect(m_activitiesService, SIGNAL(CurrentActivityChanged(QString)), this, SLOT(currentActivityChanged(QString))); connect(m_activitiesService, SIGNAL(ActivityStateChanged(QString, int)), this, SLOT(activityStateChanged(QString, int))); const auto currentActivity = Plugin::retrieve( m_activitiesService, "CurrentActivity", "QString"); currentActivityChanged(currentActivity); return true; } QString RunApplicationPlugin::activityDirectory(const QString &activity) const { return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kactivitymanagerd/activities/") + activity + '/'; } void RunApplicationPlugin::currentActivityChanged(const QString &activity) { if (m_currentActivity == activity) { return; } if (!m_currentActivity.isEmpty()) { executeIn(activityDirectory(activity) + "deactivated"); } m_currentActivity = activity; executeIn(activityDirectory(activity) + "activated"); if (!m_previousActivities.contains(activity)) { // This is the first time we have switched // to this activity in the current session, // pretending it has just been started activityStateChanged(activity, Running); m_previousActivities << activity; } } void RunApplicationPlugin::activityStateChanged(const QString &activity, int state) { auto directory = (state == Running) ? QStringLiteral("started") : (state == Stopped) ? QStringLiteral("stopped") : QString(); if (directory == "") { return; } executeIn(activityDirectory(activity) + directory); } void RunApplicationPlugin::executeIn(const QString &path) const { QDir directory(path); for (const auto& item: directory.entryList(QDir::Files)) { QString filePath = directory.filePath(item); KService service(filePath); if (service.isValid() && service.isApplication()) { - qDebug() << "Starting: " << service.exec(); + qCDebug(KAMD_LOG_APPLICATION) << "Starting: " << service.exec(); QProcess::startDetached(service.exec()); } else { - qDebug() << "Openning file: " << QUrl::fromLocalFile(filePath); + qCDebug(KAMD_LOG_APPLICATION) << "Openning file: " << QUrl::fromLocalFile(filePath); QDesktopServices::openUrl(QUrl::fromLocalFile(filePath)); } } } // void RunApplicationPlugin::activityRemoved(const QString &activity) // { // // TODO: Clean up the directory // } #include "RunApplicationPlugin.moc" diff --git a/src/service/plugins/sqlite/CMakeLists.txt b/src/service/plugins/sqlite/CMakeLists.txt index 4442e51..f50e71b 100644 --- a/src/service/plugins/sqlite/CMakeLists.txt +++ b/src/service/plugins/sqlite/CMakeLists.txt @@ -1,64 +1,65 @@ # vim:set softtabstop=3 shiftwidth=3 tabstop=3 expandtab: project (kactivitymanagerd-plugin-sqlite) set ( sqliteplugin_SRCS Database.cpp StatsPlugin.cpp ResourceScoreCache.cpp ResourceScoreMaintainer.cpp ResourceLinking.cpp + ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/service/Debug.cpp ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/database/Database.cpp ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/database/schema/ResourcesDatabaseSchema.cpp ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/utils/qsqlquery_iterator.cpp ) qt5_add_dbus_adaptor ( sqliteplugin_SRCS ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.ResourcesLinking.xml ResourceLinking.h ResourceLinking resourcelinkingadaptor ) qt5_add_dbus_adaptor ( sqliteplugin_SRCS ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.ResourcesScoring.xml StatsPlugin.h StatsPlugin resourcescoringadaptor ) include_directories ( ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/../.. ${KConfig_INCLUDE_DIR} ) kcoreaddons_add_plugin( kactivitymanagerd_plugin_sqlite JSON kactivitymanagerd-plugin-sqlite.json SOURCES ${sqliteplugin_SRCS} INSTALL_NAMESPACE ${KAMD_PLUGIN_DIR} ) target_link_libraries ( kactivitymanagerd_plugin_sqlite Qt5::Core Qt5::Sql KF5::ConfigCore KF5::KIOCore KF5::DBusAddons KF5::CoreAddons kactivitymanagerd_plugin ) set_target_properties ( kactivitymanagerd_plugin_sqlite PROPERTIES PREFIX "" ) diff --git a/src/service/plugins/sqlite/Database.cpp b/src/service/plugins/sqlite/Database.cpp index f63bd36..7182c3b 100644 --- a/src/service/plugins/sqlite/Database.cpp +++ b/src/service/plugins/sqlite/Database.cpp @@ -1,87 +1,87 @@ /* * Copyright (C) 2011, 2012 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program 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 General Public License for more details * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Self #include #include "Database.h" // Qt #include #include #include #include #include #include // KDE #include // Utils #include #include // System #include #include // Local #include "Debug.h" #include "Utils.h" #include #include class ResourcesDatabaseMigrator::Private { public: Common::Database::Ptr database; }; Common::Database::Ptr resourcesDatabase() { static ResourcesDatabaseMigrator instance; return instance.d->database; } ResourcesDatabaseMigrator::ResourcesDatabaseMigrator() { const QString databaseDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kactivitymanagerd/resources/"); - qDebug() << "Creating directory: " << databaseDir; + qCDebug(KAMD_LOG_RESOURCES) << "Creating directory: " << databaseDir; auto created = QDir().mkpath(databaseDir); if (!created || !QDir(databaseDir).exists()) { - qWarning() << "Database folder can not be created!"; + qCWarning(KAMD_LOG_RESOURCES) << "Database folder can not be created!"; } d->database = Common::Database::instance( Common::Database::ResourcesDatabase, Common::Database::ReadWrite); if (d->database) { Common::ResourcesDatabaseSchema::initSchema(*d->database); } } ResourcesDatabaseMigrator::~ResourcesDatabaseMigrator() { } diff --git a/src/service/plugins/sqlite/ResourceLinking.cpp b/src/service/plugins/sqlite/ResourceLinking.cpp index 6d8fd47..1ad64df 100644 --- a/src/service/plugins/sqlite/ResourceLinking.cpp +++ b/src/service/plugins/sqlite/ResourceLinking.cpp @@ -1,316 +1,316 @@ /* * Copyright (C) 2011, 2012, 2013, 2014, 2015 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program 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 General Public License for more details * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Self #include #include "ResourceLinking.h" // Qt #include #include // KDE #include #include #include // Boost #include #include // Local #include "Debug.h" #include "Database.h" #include "Utils.h" #include "StatsPlugin.h" #include "resourcelinkingadaptor.h" ResourceLinking::ResourceLinking(QObject *parent) : QObject(parent) { new ResourcesLinkingAdaptor(this); KDBusConnectionPool::threadConnection().registerObject( QStringLiteral("/ActivityManager/Resources/Linking"), this); } void ResourceLinking::init() { auto activities = StatsPlugin::self()->activitiesInterface(); connect(activities, SIGNAL(CurrentActivityChanged(QString)), this, SLOT(onCurrentActivityChanged(QString))); connect(activities, SIGNAL(ActivityAdded(QString)), this, SLOT(onActivityAdded(QString))); connect(activities, SIGNAL(ActivityRemoved(QString)), this, SLOT(onActivityRemoved(QString))); } void ResourceLinking::LinkResourceToActivity(QString initiatingAgent, QString targettedResource, QString usedActivity) { - qDebug() << "Linking " << targettedResource << " to " << usedActivity << " from " << initiatingAgent; + qCDebug(KAMD_LOG_RESOURCES) << "Linking " << targettedResource << " to " << usedActivity << " from " << initiatingAgent; if (!validateArguments(initiatingAgent, targettedResource, usedActivity)) { - qWarning() << "Invalid arguments" << initiatingAgent - << targettedResource << usedActivity; + qCWarning(KAMD_LOG_RESOURCES) << "Invalid arguments" << initiatingAgent + << targettedResource << usedActivity; return; } if (usedActivity == ":any") { usedActivity = ":global"; } Q_ASSERT_X(!initiatingAgent.isEmpty(), "ResourceLinking::LinkResourceToActivity", "Agent shoud not be empty"); Q_ASSERT_X(!usedActivity.isEmpty(), "ResourceLinking::LinkResourceToActivity", "Activity shoud not be empty"); Q_ASSERT_X(!targettedResource.isEmpty(), "ResourceLinking::LinkResourceToActivity", "Resource shoud not be empty"); Utils::prepare(*resourcesDatabase(), linkResourceToActivityQuery, QStringLiteral( "INSERT OR REPLACE INTO ResourceLink" " (usedActivity, initiatingAgent, targettedResource) " "VALUES ( " "COALESCE(:usedActivity,'')," "COALESCE(:initiatingAgent,'')," "COALESCE(:targettedResource,'')" ")" )); DATABASE_TRANSACTION(*resourcesDatabase()); Utils::exec(Utils::FailOnError, *linkResourceToActivityQuery, ":usedActivity" , usedActivity, ":initiatingAgent" , initiatingAgent, ":targettedResource" , targettedResource ); if (!usedActivity.isEmpty()) { - // qDebug() << "Sending link event added: activities:/" << usedActivity; + // qCDebug(KAMD_LOG_RESOURCES) << "Sending link event added: activities:/" << usedActivity; org::kde::KDirNotify::emitFilesAdded(QUrl(QStringLiteral("activities:/") + usedActivity)); if (usedActivity == StatsPlugin::self()->currentActivity()) { - // qDebug() << "Sending link event added: activities:/current"; + // qCDebug(KAMD_LOG_RESOURCES) << "Sending link event added: activities:/current"; org::kde::KDirNotify::emitFilesAdded( QUrl(QStringLiteral("activities:/current"))); } } emit ResourceLinkedToActivity(initiatingAgent, targettedResource, usedActivity); } void ResourceLinking::UnlinkResourceFromActivity(QString initiatingAgent, QString targettedResource, QString usedActivity) { - // qDebug() << "Unlinking " << targettedResource << " from " << usedActivity << " from " << initiatingAgent; + // qCDebug(KAMD_LOG_RESOURCES) << "Unlinking " << targettedResource << " from " << usedActivity << " from " << initiatingAgent; if (!validateArguments(initiatingAgent, targettedResource, usedActivity)) { - qWarning() << "Invalid arguments" << initiatingAgent - << targettedResource << usedActivity; + qCWarning(KAMD_LOG_RESOURCES) << "Invalid arguments" << initiatingAgent + << targettedResource << usedActivity; return; } Q_ASSERT_X(!initiatingAgent.isEmpty(), "ResourceLinking::UnlinkResourceFromActivity", "Agent shoud not be empty"); Q_ASSERT_X(!usedActivity.isEmpty(), "ResourceLinking::UnlinkResourceFromActivity", "Activity shoud not be empty"); Q_ASSERT_X(!targettedResource.isEmpty(), "ResourceLinking::UnlinkResourceFromActivity", "Resource shoud not be empty"); QSqlQuery *query = nullptr; if (usedActivity == ":any") { Utils::prepare(*resourcesDatabase(), unlinkResourceFromAllActivitiesQuery, QStringLiteral( "DELETE FROM ResourceLink " "WHERE " "initiatingAgent = COALESCE(:initiatingAgent , '') AND " "targettedResource = COALESCE(:targettedResource, '') " )); query = unlinkResourceFromAllActivitiesQuery.get(); } else { Utils::prepare(*resourcesDatabase(), unlinkResourceFromActivityQuery, QStringLiteral( "DELETE FROM ResourceLink " "WHERE " "usedActivity = COALESCE(:usedActivity , '') AND " "initiatingAgent = COALESCE(:initiatingAgent , '') AND " "targettedResource = COALESCE(:targettedResource, '') " )); query = unlinkResourceFromActivityQuery.get(); } DATABASE_TRANSACTION(*resourcesDatabase()); Utils::exec(Utils::FailOnError, *query, ":usedActivity" , usedActivity, ":initiatingAgent" , initiatingAgent, ":targettedResource" , targettedResource ); if (!usedActivity.isEmpty()) { // auto mangled = QString::fromUtf8(QUrl::toPercentEncoding(targettedResource)); auto mangled = QString::fromLatin1(targettedResource.toUtf8().toBase64( QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)); - // qDebug() << "Sending link event removed: activities:/" << usedActivity << '/' << mangled; + // qCDebug(KAMD_LOG_RESOURCES) << "Sending link event removed: activities:/" << usedActivity << '/' << mangled; org::kde::KDirNotify::emitFilesRemoved( { QUrl(QStringLiteral("activities:/") + usedActivity + '/' + mangled) }); if (usedActivity == StatsPlugin::self()->currentActivity()) { - // qDebug() << "Sending link event removed: activities:/current/" << mangled; + // qCDebug(KAMD_LOG_RESOURCES) << "Sending link event removed: activities:/current/" << mangled; org::kde::KDirNotify::emitFilesRemoved({ QUrl(QStringLiteral("activities:/current/") + mangled) }); } } emit ResourceUnlinkedFromActivity(initiatingAgent, targettedResource, usedActivity); } bool ResourceLinking::IsResourceLinkedToActivity(QString initiatingAgent, QString targettedResource, QString usedActivity) { if (!validateArguments(initiatingAgent, targettedResource, usedActivity)) { return false; } Q_ASSERT_X(!initiatingAgent.isEmpty(), "ResourceLinking::IsResourceLinkedToActivity", "Agent shoud not be empty"); Q_ASSERT_X(!usedActivity.isEmpty(), "ResourceLinking::IsResourceLinkedToActivity", "Activity shoud not be empty"); Q_ASSERT_X(!targettedResource.isEmpty(), "ResourceLinking::IsResourceLinkedToActivity", "Resource shoud not be empty"); Utils::prepare(*resourcesDatabase(), isResourceLinkedToActivityQuery, QStringLiteral( "SELECT * FROM ResourceLink " "WHERE " "usedActivity = COALESCE(:usedActivity , '') AND " "initiatingAgent = COALESCE(:initiatingAgent , '') AND " "targettedResource = COALESCE(:targettedResource, '') " )); Utils::exec(Utils::FailOnError, *isResourceLinkedToActivityQuery, ":usedActivity" , usedActivity, ":initiatingAgent" , initiatingAgent, ":targettedResource" , targettedResource ); return isResourceLinkedToActivityQuery->next(); } bool ResourceLinking::validateArguments(QString &initiatingAgent, QString &targettedResource, QString &usedActivity) { // Validating targetted resource if (targettedResource.isEmpty()) { - qDebug() << "Resource is invalid -- empty"; + qCDebug(KAMD_LOG_RESOURCES) << "Resource is invalid -- empty"; return false; } if (targettedResource.startsWith(QStringLiteral("file://"))) { targettedResource = QUrl(targettedResource).toLocalFile(); } if (targettedResource.startsWith(QStringLiteral("/"))) { QFileInfo file(targettedResource); if (!file.exists()) { - qDebug() << "Resource is invalid -- the file does not exist"; + qCDebug(KAMD_LOG_RESOURCES) << "Resource is invalid -- the file does not exist"; return false; } targettedResource = file.canonicalFilePath(); } // Handling special values for the agent if (initiatingAgent.isEmpty()) { initiatingAgent = ":global"; } // Handling special values for activities if (usedActivity == ":current") { usedActivity = StatsPlugin::self()->currentActivity(); } else if (usedActivity.isEmpty()) { usedActivity = ":global"; } // If the activity is not empty and the passed activity // does not exist, cancel the request if (!usedActivity.isEmpty() && usedActivity != ":global" && usedActivity != ":any" && !StatsPlugin::self()->listActivities().contains(usedActivity)) { - qDebug() << "Activity is invalid, it does not exist"; + qCDebug(KAMD_LOG_RESOURCES) << "Activity is invalid, it does not exist"; return false; } - // qDebug() << "agent" << initiatingAgent - // << "resource" << targettedResource - // << "activity" << usedActivity; + // qCDebug(KAMD_LOG_RESOURCES) << "agent" << initiatingAgent + // << "resource" << targettedResource + // << "activity" << usedActivity; return true; } void ResourceLinking::onActivityAdded(const QString &activity) { Q_UNUSED(activity); // Notify KIO - // qDebug() << "Added: activities:/ (" << activity << ")"; + // qCDebug(KAMD_LOG_RESOURCES) << "Added: activities:/ (" << activity << ")"; org::kde::KDirNotify::emitFilesAdded(QUrl(QStringLiteral("activities:/"))); } void ResourceLinking::onActivityRemoved(const QString &activity) { // Notify KIO - // qDebug() << "Removed: activities:/" << activity; + // qCDebug(KAMD_LOG_RESOURCES) << "Removed: activities:/" << activity; org::kde::KDirNotify::emitFilesRemoved( { QUrl(QStringLiteral("activities:/") + activity) }); // Remove statistics for the activity } void ResourceLinking::onCurrentActivityChanged(const QString &activity) { Q_UNUSED(activity); // Notify KIO - // qDebug() << "Changed: activities:/current -> " << activity; + // qCDebug(KAMD_LOG_RESOURCES) << "Changed: activities:/current -> " << activity; org::kde::KDirNotify::emitFilesAdded( { QUrl(QStringLiteral("activities:/current")) }); } diff --git a/src/service/plugins/sqlite/ResourceScoreCache.cpp b/src/service/plugins/sqlite/ResourceScoreCache.cpp index 32dd891..d6304d1 100644 --- a/src/service/plugins/sqlite/ResourceScoreCache.cpp +++ b/src/service/plugins/sqlite/ResourceScoreCache.cpp @@ -1,263 +1,263 @@ /* * Copyright (C) 2011, 2012 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program 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 General Public License for more details * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Self #include #include "ResourceScoreCache.h" // STD #include // Utils #include #include // Local #include "Debug.h" #include "StatsPlugin.h" #include "Database.h" #include "Utils.h" class ResourceScoreCache::Queries { private: Queries() : createResourceScoreCacheQuery(resourcesDatabase()->createQuery()) , getResourceScoreCacheQuery(resourcesDatabase()->createQuery()) , updateResourceScoreCacheQuery(resourcesDatabase()->createQuery()) , getScoreAdditionQuery(resourcesDatabase()->createQuery()) { Utils::prepare(*resourcesDatabase(), createResourceScoreCacheQuery, QStringLiteral( "INSERT INTO ResourceScoreCache " "VALUES (:usedActivity, :initiatingAgent, :targettedResource, " "0, 0, " // type, score ":firstUpdate, " // lastUpdate ":firstUpdate)" )); Utils::prepare(*resourcesDatabase(), getResourceScoreCacheQuery, QStringLiteral( "SELECT cachedScore, lastUpdate, firstUpdate FROM ResourceScoreCache " "WHERE " ":usedActivity = usedActivity AND " ":initiatingAgent = initiatingAgent AND " ":targettedResource = targettedResource " )); Utils::prepare(*resourcesDatabase(), updateResourceScoreCacheQuery, QStringLiteral( "UPDATE ResourceScoreCache SET " "cachedScore = :cachedScore, " "lastUpdate = :lastUpdate " "WHERE " ":usedActivity = usedActivity AND " ":initiatingAgent = initiatingAgent AND " ":targettedResource = targettedResource " )); Utils::prepare(*resourcesDatabase(), getScoreAdditionQuery, QStringLiteral( "SELECT start, end " "FROM ResourceEvent " "WHERE " ":usedActivity = usedActivity AND " ":initiatingAgent = initiatingAgent AND " ":targettedResource = targettedResource AND " "start > :start " "ORDER BY " "start ASC" )); } public: QSqlQuery createResourceScoreCacheQuery; QSqlQuery getResourceScoreCacheQuery; QSqlQuery updateResourceScoreCacheQuery; QSqlQuery getScoreAdditionQuery; static Queries &self(); }; ResourceScoreCache::Queries &ResourceScoreCache::Queries::self() { static Queries queries; return queries; } class ResourceScoreCache::Private { public: QString activity; QString application; QString resource; inline qreal timeFactor(int days) const { // Exp is falling rather quickly, we are slowing it 32 times return std::exp(-days / 32.0); } inline qreal timeFactor(QDateTime fromTime, QDateTime toTime) const { return timeFactor(fromTime.daysTo(toTime)); } }; ResourceScoreCache::ResourceScoreCache(const QString &activity, const QString &application, const QString &resource) { d->activity = activity; d->application = application; d->resource = resource; Q_ASSERT_X(!d->application.isEmpty(), "ResourceScoreCache::constructor", "Agent shoud not be empty"); Q_ASSERT_X(!d->activity.isEmpty(), "ResourceScoreCache::constructor", "Activity shoud not be empty"); Q_ASSERT_X(!d->resource.isEmpty(), "ResourceScoreCache::constructor", "Resource shoud not be empty"); } ResourceScoreCache::~ResourceScoreCache() { } void ResourceScoreCache::update() { QDateTime lastUpdate; QDateTime firstUpdate; QDateTime currentTime = QDateTime::currentDateTime(); qreal score = 0; DATABASE_TRANSACTION(*resourcesDatabase()); - qDebug() << "Creating the cache for: " << d->resource; + qCDebug(KAMD_LOG_RESOURCES) << "Creating the cache for: " << d->resource; // This can fail if we have the cache already made auto isCacheNew = Utils::exec( Utils::IgnoreError, Queries::self().createResourceScoreCacheQuery, ":usedActivity", d->activity, ":initiatingAgent", d->application, ":targettedResource", d->resource, ":firstUpdate", currentTime.toTime_t() ); // Getting the old score Utils::exec( Utils::FailOnError, Queries::self().getResourceScoreCacheQuery, ":usedActivity", d->activity, ":initiatingAgent", d->application, ":targettedResource", d->resource ); // Only and always one result for (const auto &result: Queries::self().getResourceScoreCacheQuery) { lastUpdate.setTime_t(result["lastUpdate"].toUInt()); firstUpdate.setTime_t(result["firstUpdate"].toUInt()); - qDebug() << "Already in database? " << (!isCacheNew); - qDebug() << " First update : " << firstUpdate; - qDebug() << " Last update : " << lastUpdate; + qCDebug(KAMD_LOG_RESOURCES) << "Already in database? " << (!isCacheNew); + qCDebug(KAMD_LOG_RESOURCES) << " First update : " << firstUpdate; + qCDebug(KAMD_LOG_RESOURCES) << " Last update : " << lastUpdate; if (isCacheNew) { // If we haven't had the cache before, set the score to 0 firstUpdate = currentTime; score = 0; } else { // Adjusting the score depending on the time that passed since the // last update score = result["cachedScore"].toReal(); score *= d->timeFactor(lastUpdate, currentTime); } } // Calculating the updated score // We are processing all events since the last cache update - qDebug() << "After the adjustment"; - qDebug() << " Current score : " << score; - qDebug() << " First update : " << firstUpdate; - qDebug() << " Last update : " << lastUpdate; + qCDebug(KAMD_LOG_RESOURCES) << "After the adjustment"; + qCDebug(KAMD_LOG_RESOURCES) << " Current score : " << score; + qCDebug(KAMD_LOG_RESOURCES) << " First update : " << firstUpdate; + qCDebug(KAMD_LOG_RESOURCES) << " Last update : " << lastUpdate; Utils::exec(Utils::FailOnError, Queries::self().getScoreAdditionQuery, ":usedActivity", d->activity, ":initiatingAgent", d->application, ":targettedResource", d->resource, ":start", lastUpdate.toTime_t() ); uint lastEventStart = currentTime.toTime_t(); for (const auto &result: Queries::self().getScoreAdditionQuery) { lastEventStart = result["start"].toUInt(); const auto end = result["end"].toUInt(); const auto intervalLength = end - lastEventStart; - qDebug() << "Interval length is " << intervalLength; + qCDebug(KAMD_LOG_RESOURCES) << "Interval length is " << intervalLength; if (intervalLength == 0) { // We have an Accessed event - otherwise, this wouldn't be 0 score += d->timeFactor(QDateTime::fromTime_t(end), currentTime); // like it is open for 1 minute } else { score += d->timeFactor(QDateTime::fromTime_t(end), currentTime) * intervalLength / 60.0; } } - qDebug() << " New score : " << score; + qCDebug(KAMD_LOG_RESOURCES) << " New score : " << score; // Updating the score Utils::exec(Utils::FailOnError, Queries::self().updateResourceScoreCacheQuery, ":usedActivity", d->activity, ":initiatingAgent", d->application, ":targettedResource", d->resource, ":cachedScore", score, ":lastUpdate", lastEventStart ); // Notifying the world - qDebug() << "ResourceScoreUpdated:" - << d->activity - << d->application - << d->resource + qCDebug(KAMD_LOG_RESOURCES) << "ResourceScoreUpdated:" + << d->activity + << d->application + << d->resource ; emit QMetaObject::invokeMethod(StatsPlugin::self(), "ResourceScoreUpdated", Qt::QueuedConnection, Q_ARG(QString, d->activity), Q_ARG(QString, d->application), Q_ARG(QString, d->resource), Q_ARG(double, score), Q_ARG(uint, lastEventStart), Q_ARG(uint, firstUpdate.toTime_t()) ); } diff --git a/src/service/plugins/sqlite/Utils.h b/src/service/plugins/sqlite/Utils.h index 9c03336..b6c8adb 100644 --- a/src/service/plugins/sqlite/Utils.h +++ b/src/service/plugins/sqlite/Utils.h @@ -1,85 +1,85 @@ /* * Copyright (C) 2014 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program 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 General Public License for more details * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PLUGINS_SQLITE_DATABASE_UTILS_H #define PLUGINS_SQLITE_DATABASE_UTILS_H #include #include #include namespace Utils { static unsigned int errorCount = 0; inline bool prepare(Common::Database &database, QSqlQuery &query, const QString &queryString) { Q_UNUSED(database); return query.prepare(queryString); } inline bool prepare(Common::Database &database, std::unique_ptr &query, const QString &queryString) { if (query) { return true; } query.reset(new QSqlQuery(database.createQuery())); return prepare(database, *query, queryString); } enum ErrorHandling { IgnoreError, FailOnError }; inline bool exec(ErrorHandling eh, QSqlQuery &query) { bool success = query.exec(); if (eh == FailOnError) { if ((!success) && (errorCount++ < 2)) { - qDebug() << query.lastQuery(); - qDebug() << query.lastError(); + qCDebug(KAMD_LOG_RESOURCES) << query.lastQuery(); + qCDebug(KAMD_LOG_RESOURCES) << query.lastError(); } Q_ASSERT_X(success, "Uils::exec", "Query failed"); } return success; } template inline bool exec(ErrorHandling eh, QSqlQuery &query, const T1 &variable, const T2 &value, Ts... ts) { query.bindValue(variable, value); return exec(eh, query, ts...); } } // namespace Utils #endif /* !PLUGINS_SQLITE_DATABASE_UTILS_H */ diff --git a/src/utils/continue_with.h b/src/utils/continue_with.h index ed555c8..023c9aa 100644 --- a/src/utils/continue_with.h +++ b/src/utils/continue_with.h @@ -1,110 +1,110 @@ /* * Copyright (C) 2014 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UTILS_CONTINUE_WITH_H #define UTILS_CONTINUE_WITH_H #include #include #include #include "utils/optional_view.h" // #include #ifdef ENABLE_QJSVALUE_CONTINUATION #include #endif namespace kamd { namespace utils { namespace detail { //_ #ifdef ENABLE_QJSVALUE_CONTINUATION inline void test_continuation(const QJSValue &continuation) { if (!continuation.isCallable()) { - qWarning() << "Passed handler is not callable: " << continuation.toString(); + qCWarning(KAMD_LOG_RESOURCES) << "Passed handler is not callable: " << continuation.toString(); } } template inline void pass_value(const QFuture<_ReturnType> &future, QJSValue continuation) { auto result = continuation.call({ future.result() }); if (result.isError()) { - qWarning() << "Handler returned this error: " << result.toString(); + qCWarning(KAMD_LOG_RESOURCES) << "Handler returned this error: " << result.toString(); } } inline void pass_value(const QFuture &future, QJSValue continuation) { Q_UNUSED(future); auto result = continuation.call({}); if (result.isError()) { - qWarning() << "Handler returned this error: " << result.toString(); + qCWarning(KAMD_LOG_RESOURCES) << "Handler returned this error: " << result.toString(); } } #endif template inline void test_continuation(_Continuation &&continuation) { Q_UNUSED(continuation); } template inline void pass_value(const QFuture<_ReturnType> &future, _Continuation &&continuation) { using namespace kamd::utils; continuation(future.resultCount() > 0 ? make_optional_view(future.result()) : none()); } template inline void pass_value(_Continuation &&continuation) { continuation(); } } //^ namespace detail template inline void continue_with(const QFuture<_ReturnType> &future, _Continuation &&continuation) { detail::test_continuation(continuation); auto watcher = new QFutureWatcher<_ReturnType>(); QObject::connect(watcher, &QFutureWatcherBase::finished, [=]() mutable { detail::pass_value(future, continuation); }); watcher->setFuture(future); } } // namespace utils } // namespace kamd #endif /* !UTILS_CONTINUE_WITH_H */ diff --git a/src/utils/dbusfuture_p.cpp b/src/utils/dbusfuture_p.cpp index a63a334..78a4eb5 100644 --- a/src/utils/dbusfuture_p.cpp +++ b/src/utils/dbusfuture_p.cpp @@ -1,64 +1,64 @@ /* * Copyright (C) 2013 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dbusfuture_p.h" namespace DBusFuture { namespace detail { //_ template <> void DBusCallFutureInterface::callFinished() { deleteLater(); - // qDebug() << "This is call end"; + // qCDebug(KAMD_LOG_RESOURCES) << "This is call end"; this->reportFinished(); } ValueFutureInterface::ValueFutureInterface() { } QFuture ValueFutureInterface::start() { auto future = this->future(); this->reportFinished(); deleteLater(); return future; } } //^ namespace detail QFuture fromVoid() { using namespace detail; auto valueFutureInterface = new ValueFutureInterface(); return valueFutureInterface->start(); } } // namespace DBusFuture diff --git a/src/utils/debug_and_return.h b/src/utils/debug_and_return.h index 846e33c..9faaeeb 100644 --- a/src/utils/debug_and_return.h +++ b/src/utils/debug_and_return.h @@ -1,55 +1,55 @@ /* * Copyright (C) 2015 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DEBUG_AND_RETURN_H #define DEBUG_AND_RETURN_H #ifdef QT_DEBUG #include #endif namespace kamd { namespace utils { template T debug_and_return(const char * message, T && value) { #ifdef QT_DEBUG - qDebug() << message << " " << value; + qCDebug(KAMD_LOG_RESOURCES) << message << " " << value; #endif return std::forward(value); } template T debug_and_return(bool debug, const char * message, T && value) { #ifdef QT_DEBUG if (debug) { - qDebug() << message << " " << value; + qCDebug(KAMD_LOG_RESOURCES) << message << " " << value; } #endif return std::forward(value); } } // namespace utils } // namespace kamd #endif // DEBUG_AND_RETURN_H