diff --git a/CMakeLists.txt b/CMakeLists.txt index e84c65fc..dcdbd89b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,118 +1,124 @@ # vim:set softtabstop=3 shiftwidth=3 tabstop=3 expandtab: cmake_minimum_required(VERSION 3.0) # KDE Frameworks set(KF5_VERSION "5.51.0") # handled by release scripts set(KF5_DEP_VERSION "5.50.0") # handled by release scripts project (KActivities VERSION ${KF5_VERSION}) option (KACTIVITIES_LIBRARY_ONLY "If true, compiles only the KActivities library, without the QML imports." OFF) option (KACTIVITIES_ENABLE_EXCEPTIONS "If you have Boost 1.53, you need to build KActivities with exceptions enabled. This is UNTESTED and EXPERIMENTAL!" OFF) set (REQUIRED_QT_VERSION 5.8.0) # We don't build in-source if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") message ( FATAL_ERROR "kactivities require an out of source build. Please create a separate build directory and run 'cmake path_to_plasma [options]' there." ) endif () set (KACTIVITIES_CURRENT_ROOT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # Extra CMake stuff include(FeatureSummary) find_package(ECM 5.50.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include (KDEInstallDirs) include (KDECMakeSettings) include (KDECompilerSettings NO_POLICY_SCOPE) include (GenerateExportHeader) include (ECMGenerateHeaders) include (ECMAddQch) option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") # Qt set (CMAKE_AUTOMOC ON) find_package (Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED COMPONENTS Core DBus) # Basic includes include (CPack) include (CMakePackageConfigHelpers) include (ECMSetupVersion) message ("We are using the ${CMAKE_CXX_COMPILER_ID} compiler") if ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (KACTIVITIES_OVERRIDE_VISIBILITY STREQUAL "default")) message ("Setting visibility preset to default") set(CMAKE_CXX_VISIBILITY_PRESET default) set(CMAKE_VISIBILITY_INLINES_HIDDEN 0) string (REPLACE "-fvisibility-inlines-hidden" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string (REPLACE "-fvisibility=hidden" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") endif () # libKActivities ecm_setup_version ( PROJECT VARIABLE_PREFIX KACTIVITIES VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kactivities_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5ActivitiesConfigVersion.cmake" SOVERSION 5 ) +add_definitions(-DQT_NO_CAST_FROM_ASCII) +add_definitions(-DQT_NO_CAST_TO_ASCII) +add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) +add_definitions(-DQT_NO_URL_CAST_FROM_STRING) +add_definitions(-DQT_USE_QSTRINGBUILDER) + add_subdirectory (src) if (BUILD_TESTING) add_subdirectory (autotests) add_subdirectory (tests) endif() set (CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Activities") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5Activities_QCH FILE KF5ActivitiesLibraryQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5ActivitiesLibraryQchTargets.cmake\")") endif() install ( EXPORT KF5ActivitiesLibraryTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5ActivitiesLibraryTargets.cmake NAMESPACE KF5:: ) configure_package_config_file ( "${CMAKE_CURRENT_SOURCE_DIR}/KF5ActivitiesConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5ActivitiesConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} PATH_VARS KF5_INCLUDE_INSTALL_DIR CMAKE_INSTALL_PREFIX ) install ( FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5ActivitiesConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5ActivitiesConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/kactivities_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) # Write out the features feature_summary (WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/cli/main.cpp b/src/cli/main.cpp index 827818dd..2e7a95a3 100644 --- a/src/cli/main.cpp +++ b/src/cli/main.cpp @@ -1,297 +1,297 @@ /* * Copyright (C) 2016 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. */ #include #include #include #include #include "utils.h" // Output modifiers DEFINE_COMMAND(bare, 0) { flags.bare = true; return 0; } DEFINE_COMMAND(noBare, 0) { flags.bare = false; return 0; } DEFINE_COMMAND(color, 0) { flags.color = true; return 0; } DEFINE_COMMAND(noColor, 0) { flags.color = false; return 0; } // Activity management DEFINE_COMMAND(createActivity, 1) { auto result = awaitFuture(controller->addActivity(args(1))); qDebug().noquote() << result; return 1; } DEFINE_COMMAND(removeActivity, 1) { awaitFuture(controller->removeActivity(args(1))); return 1; } DEFINE_COMMAND(startActivity, 1) { awaitFuture(controller->startActivity(args(1))); return 1; } DEFINE_COMMAND(stopActivity, 1) { awaitFuture(controller->stopActivity(args(1))); return 1; } DEFINE_COMMAND(listActivities, 0) { for (const auto& activity: controller->activities()) { printActivity(activity); } return 0; } DEFINE_COMMAND(currentActivity, 0) { printActivity(controller->currentActivity()); return 0; } DEFINE_COMMAND(setActivityProperty, 3) { const auto what = args(1); const auto id = args(2); const auto value = args(3); awaitFuture( - what == "name" ? controller->setActivityName(id, value) : - what == "description" ? controller->setActivityDescription(id, value) : - what == "icon" ? controller->setActivityIcon(id, value) : + what == QLatin1String("name") ? controller->setActivityName(id, value) : + what == QLatin1String("description") ? controller->setActivityDescription(id, value) : + what == QLatin1String("icon") ? controller->setActivityIcon(id, value) : QFuture() ); return 3; } DEFINE_COMMAND(activityProperty, 2) { const auto what = args(1); const auto id = args(2); KActivities::Info info(id); out << ( - what == "name" ? info.name() : - what == "description" ? info.description() : - what == "icon" ? info.icon() : + what == QLatin1String("name") ? info.name() : + what == QLatin1String("description") ? info.description() : + what == QLatin1String("icon") ? info.icon() : QString() ) << "\n"; return 2; } // Activity switching DEFINE_COMMAND(setCurrentActivity, 1) { switchToActivity(args(1)); return 1; } DEFINE_COMMAND(nextActivity, 0) { const auto activities = controller->activities(); const auto currentActivity = controller->currentActivity(); bool found = false; for (int i = 0; i < activities.count() - 1; ++i) { if (activities[i] == currentActivity) { found = true; switchToActivity(activities[i + 1]); break; } } if (!found) { switchToActivity(activities[0]); } return 0; } DEFINE_COMMAND(previousActivity, 0) { const auto activities = controller->activities(); const auto currentActivity = controller->currentActivity(); bool found = false; for (int i = 1; i < activities.count(); ++i) { if (activities[i] == currentActivity) { found = true; switchToActivity(activities[i - 1]); break; } } if (!found) { found = true; switchToActivity(activities.last()); } return 0; } void printHelp() { if (!flags.bare) { qDebug() << "\nModifiers (applied only to trailing commands):" << "\n --bare, --no-bare - show minimal info vs show everything" << "\n --color, --no-color - make the output pretty" << "\n\nCommands:" << "\n --list-activities - lists all activities" << "\n --create-activity Name - creates a new activity with the specified name" << "\n --remove-activity ID - removes the activity with the specified id" << "\n --start-activity ID - starts the specified activity" << "\n --stop-activity ID - stops the specified activity" << "\n --current-activity - show the current activity" << "\n --set-current-activity - sets the current activity" << "\n --next-activity - switches to the next activity (in list-activities order)" << "\n --previous-activity - switches to the previous activity (in list-activities order)" << "\n --activity-property What ID" << "\n - gets activity name, icon or description" << "\n --set-activity-property What ID Value" << "\n - changes activity name, icon or description" ; } else { qDebug() << "\n--bare" << "\n--no-bare" << "\n--color" << "\n--no-color" << "\n--list-activities" << "\n--create-activitya NAME" << "\n--remove-activity ID" << "\n--current-activity" << "\n--set-current-activity" << "\n--next-activity" << "\n--previous-activity" ; } } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QTimer::singleShot(0, &app, [] { const auto args = QCoreApplication::arguments(); controller = new KActivities::Controller(); while (controller->serviceStatus() != KActivities::Controller::Running) { QCoreApplication::processEvents(); } #define MATCH_COMMAND(Command) \ - else if (args[argId] == QStringLiteral("--") + toDashes(#Command)) \ + else if (args[argId] == QStringLiteral("--") + toDashes(QStringLiteral(#Command))) \ { \ argId += 1 + Command##_command({ args, argId })(); \ } if (args.count() <= 1) { printHelp(); } else for (int argId = 1; argId < args.count(); ) { - if (args[argId] == "--help") { + if (args[argId] == QLatin1String("--help")) { printHelp(); argId++; } MATCH_COMMAND(bare) MATCH_COMMAND(noBare) MATCH_COMMAND(color) MATCH_COMMAND(noColor) MATCH_COMMAND(listActivities) MATCH_COMMAND(currentActivity) MATCH_COMMAND(setCurrentActivity) MATCH_COMMAND(activityProperty) MATCH_COMMAND(setActivityProperty) MATCH_COMMAND(nextActivity) MATCH_COMMAND(previousActivity) MATCH_COMMAND(createActivity) MATCH_COMMAND(removeActivity) MATCH_COMMAND(startActivity) MATCH_COMMAND(stopActivity) else { qDebug() << "Skipping unknown argument" << args[argId]; argId++; } } delete controller; QCoreApplication::quit(); }); return app.exec(); } diff --git a/src/cli/utils.h b/src/cli/utils.h index 836c1800..742e7e8e 100644 --- a/src/cli/utils.h +++ b/src/cli/utils.h @@ -1,172 +1,172 @@ /* * Copyright (C) 2016 Ivan Čukić * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see . */ #ifndef KACTIVITIES_UTILS_H #define KACTIVITIES_UTILS_H QTextStream out(stdout); class StringListView { public: StringListView(const QStringList &list, int start, int end = -1) : m_list(list) , m_start(start) , m_size((end == -1 ? list.count() : end) - start) { } const QString &operator() (int index) const { return m_list[m_start + index]; } int count() const { return m_size; } private: const QStringList &m_list; int m_start; int m_size; }; KActivities::Controller *controller = nullptr; class Flags { public: Flags() : bare(false) , color(true) { } bool bare; bool color; } flags; QString toDashes(const QString &command) { QString result(command); for (int i = 0; i < result.size() - 1; ++i) { if (result[i].isLower() && result[i+1].isUpper()) { result[i+1] = result[i+1].toLower(); - result.insert(i+1, "-"); + result.insert(i+1, QStringLiteral("-")); } } return result; } void printActivity(const QString &id) { if (flags.bare) { out << id << "\n"; } else { using namespace KActivities; Info info(id); out << ( info.id() == controller->currentActivity() ? "[CURRENT] " : info.state() == Info::Running ? "[RUNNING] " : info.state() == Info::Stopped ? "[STOPPED] " : info.state() == Info::Starting ? "[STARTING]" : info.state() == Info::Stopping ? "[STOPPING]" : "unknown " ) << info.id() << " " << info.name() << " (" << info.icon() << ")\n" ; if (info.id() == controller->currentActivity() && info.state() != Info::Running) { qWarning() << "Activity is the current one, but its state is" << ( info.state() == Info::Running ? "running" : info.state() == Info::Stopped ? "stopped" : info.state() == Info::Starting ? "starting" : info.state() == Info::Stopping ? "stopping" : "unknown " ); } } } template T awaitFuture(const QFuture &future) { while (!future.isFinished()) { QCoreApplication::processEvents(); } return future.result(); } void awaitFuture(const QFuture &future) { while (!future.isFinished()) { QCoreApplication::processEvents(); } } void switchToActivity(const QString &id) { auto result = awaitFuture(controller->setCurrentActivity(id)); if (!flags.bare) { if (result) { qDebug() << "Current activity is" << id; } else { qDebug() << "Failed to change the activity"; } } } #define DEFINE_COMMAND(Command, MinArgCount) \ struct Command##_command { \ const StringListView &args; \ Command##_command(const StringListView &args) \ : args(args) \ { \ if (args.count() < MinArgCount + 1) { \ qFatal("not enough arguments for " #Command); \ } \ } \ \ int operator()(); \ }; \ \ int Command##_command::operator()() #endif diff --git a/src/imports/activityinfo.cpp b/src/imports/activityinfo.cpp index 144c7613..a170c5cb 100644 --- a/src/imports/activityinfo.cpp +++ b/src/imports/activityinfo.cpp @@ -1,109 +1,109 @@ /* * Copyright (C) 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 "activityinfo.h" namespace KActivities { namespace Imports { ActivityInfo::ActivityInfo(QObject *parent) : QObject(parent) , m_showCurrentActivity(false) { connect(&m_service, &KActivities::Controller::currentActivityChanged, this, &ActivityInfo::setCurrentActivity); } ActivityInfo::~ActivityInfo() { } void ActivityInfo::setCurrentActivity(const QString &id) { if (!m_showCurrentActivity) return; setIdInternal(id); emit nameChanged(m_info->name()); emit descriptionChanged(m_info->description()); emit iconChanged(m_info->icon()); } void ActivityInfo::setActivityId(const QString &id) { - m_showCurrentActivity = (id == ":current"); + m_showCurrentActivity = (id == QStringLiteral(":current")); setIdInternal(m_showCurrentActivity ? m_service.currentActivity() : id); } void ActivityInfo::setIdInternal(const QString &id) { using namespace KActivities; // We are killing the old info object, if any m_info.reset(new KActivities::Info(id)); auto ptr = m_info.get(); connect(ptr, &Info::nameChanged, this, &ActivityInfo::nameChanged); connect(ptr, &Info::descriptionChanged, this, &ActivityInfo::descriptionChanged); connect(ptr, &Info::iconChanged, this, &ActivityInfo::iconChanged); } #define CREATE_GETTER_AND_SETTER(WHAT, What) \ QString ActivityInfo::What() const \ { \ - return m_info ? m_info->What() : ""; \ + return m_info ? m_info->What() : QString(); \ } \ \ void ActivityInfo::set##WHAT(const QString &value) \ { \ if (!m_info) \ return; \ \ m_service.setActivity##WHAT(m_info->id(), value); \ } CREATE_GETTER_AND_SETTER(Name, name) CREATE_GETTER_AND_SETTER(Description, description) CREATE_GETTER_AND_SETTER(Icon, icon) #undef CREATE_GETTER_AND_SETTER QString ActivityInfo::activityId() const { - return m_info ? m_info->id() : ""; + return m_info ? m_info->id() : QString(); } bool ActivityInfo::valid() const { return true; } } // namespace Imports } // namespace KActivities // #include "activityinfo.moc" diff --git a/src/imports/activitymodel.cpp b/src/imports/activitymodel.cpp index 9aa8c13f..5cd81e92 100644 --- a/src/imports/activitymodel.cpp +++ b/src/imports/activitymodel.cpp @@ -1,654 +1,654 @@ /* * Copyright (C) 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 "activitymodel.h" // Qt #include #include #include #include #include #include #include #include #include // KDE #include #include #include // Boost #include #include #include #include // Local #include "utils/remove_if.h" #define ENABLE_QJSVALUE_CONTINUATION #include "utils/continue_with.h" #include "utils/model_updaters.h" using kamd::utils::continue_with; namespace KActivities { namespace Imports { class ActivityModel::Private { public: DECLARE_RAII_MODEL_UPDATERS(ActivityModel) /** * Returns whether the activity has a desired state. * If the state is 0, returns true */ template static inline bool matchingState(InfoPtr activity, T states) { // Are we filtering activities on their states? if (!states.empty() && !boost::binary_search(states, activity->state())) { return false; } return true; } /** * Searches for the activity. * Returns an option(index, iterator) for the found activity. */ template static inline boost::optional< std::pair > activityPosition(const _Container &container, const QString &activityId) { using ActivityPosition = decltype(activityPosition(container, activityId)); using ContainerElement = typename _Container::value_type; auto position = boost::find_if(container, [&] (const ContainerElement &activity) { return activity->id() == activityId; } ); return (position != container.end()) ? ActivityPosition( std::make_pair(position - container.begin(), position) ) : ActivityPosition(); } /** * Notifies the model that an activity was updated */ template static inline void emitActivityUpdated(_Model *model, const _Container &container, QObject *activityInfo, int role) { const auto activity = static_cast (activityInfo); emitActivityUpdated(model, container, activity->id(), role); } /** * Notifies the model that an activity was updated */ template static inline void emitActivityUpdated(_Model *model, const _Container &container, const QString &activity, int role) { auto position = Private::activityPosition(container, activity); if (position) { emit model->dataChanged( model->index(position->first), model->index(position->first), role == Qt::DecorationRole ? QVector {role, ActivityModel::ActivityIcon} : QVector {role} ); } } class BackgroundCache { public: BackgroundCache() : initialized(false) - , plasmaConfig("plasma-org.kde.plasma.desktop-appletsrc") + , plasmaConfig(QStringLiteral("plasma-org.kde.plasma.desktop-appletsrc")) { using namespace std::placeholders; const auto configFile = QStandardPaths::writableLocation( QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + plasmaConfig.name(); KDirWatch::self()->addFile(configFile); connect(KDirWatch::self(), &KDirWatch::dirty, std::bind(&BackgroundCache::settingsFileChanged, this, _1)); connect(KDirWatch::self(), &KDirWatch::created, std::bind(&BackgroundCache::settingsFileChanged, this, _1)); } void settingsFileChanged(const QString &file) { if (!file.endsWith(plasmaConfig.name())) return; plasmaConfig.reparseConfiguration(); if (initialized) { reload(false); } } void subscribe(ActivityModel *model) { if (!initialized) { reload(true); } models << model; } void unsubscribe(ActivityModel *model) { models.removeAll(model); if (models.isEmpty()) { initialized = false; forActivity.clear(); } } QString backgroundFromConfig(const KConfigGroup &config) const { auto wallpaperPlugin = config.readEntry("wallpaperplugin"); auto wallpaperConfig = config.group("Wallpaper").group(wallpaperPlugin).group("General"); if (wallpaperConfig.hasKey("Image")) { // Trying for the wallpaper auto wallpaper = wallpaperConfig.readEntry("Image", QString()); if (!wallpaper.isEmpty()) { return wallpaper; } } if (wallpaperConfig.hasKey("Color")) { auto backgroundColor = wallpaperConfig.readEntry("Color", QColor(0, 0, 0)); return backgroundColor.name(); } return QString(); } void reload(bool fullReload) { QHash newBackgrounds; if (fullReload) { forActivity.clear(); } QStringList changedBackgrounds; for (const auto &cont: plasmaConfigContainments().groupList()) { auto config = plasmaConfigContainments().group(cont); auto activityId = config.readEntry("activityId", QString()); // Ignore if it has no assigned activity if (activityId.isEmpty()) continue; // Ignore if we have already found the background if (newBackgrounds.contains(activityId) && - newBackgrounds[activityId][0] != '#') continue; + newBackgrounds[activityId][0] != QLatin1Char('#')) continue; auto newBackground = backgroundFromConfig(config); if (forActivity[activityId] != newBackground) { changedBackgrounds << activityId; if (!newBackground.isEmpty()) { newBackgrounds[activityId] = newBackground; } } } initialized = true; if (!changedBackgrounds.isEmpty()) { forActivity = newBackgrounds; for (auto model: models) { model->backgroundsUpdated(changedBackgrounds); } } } KConfigGroup plasmaConfigContainments() { return plasmaConfig.group("Containments"); } QHash forActivity; QList models; bool initialized; KConfig plasmaConfig; }; static BackgroundCache &backgrounds() { // If you convert this to a shared pointer, // fix the connections to KDirWatcher static BackgroundCache cache; return cache; } }; ActivityModel::ActivityModel(QObject *parent) : QAbstractListModel(parent) { // Initializing role names for qml connect(&m_service, &Consumer::serviceStatusChanged, this, &ActivityModel::setServiceStatus); connect(&m_service, SIGNAL(activityAdded(QString)), this, SLOT(onActivityAdded(QString))); connect(&m_service, SIGNAL(activityRemoved(QString)), this, SLOT(onActivityRemoved(QString))); connect(&m_service, SIGNAL(currentActivityChanged(QString)), this, SLOT(onCurrentActivityChanged(QString))); setServiceStatus(m_service.serviceStatus()); Private::backgrounds().subscribe(this); } ActivityModel::~ActivityModel() { Private::backgrounds().unsubscribe(this); } QHash ActivityModel::roleNames() const { return { {Qt::DisplayRole, "name"}, {Qt::DecorationRole, "icon"}, {ActivityState, "state"}, {ActivityId, "id"}, {ActivityIcon, "iconSource"}, {ActivityDescription, "description"}, {ActivityBackground, "background"}, {ActivityCurrent, "current"} }; } void ActivityModel::setServiceStatus(Consumer::ServiceStatus) { replaceActivities(m_service.activities()); } void ActivityModel::replaceActivities(const QStringList &activities) { // qDebug() << m_shownStatesString << "New list of activities: " // << activities; // qDebug() << m_shownStatesString << " -- RESET MODEL -- "; Private::model_reset m(this); m_knownActivities.clear(); m_shownActivities.clear(); for (const QString &activity: activities) { onActivityAdded(activity, false); } } void ActivityModel::onActivityAdded(const QString &id, bool notifyClients) { auto info = registerActivity(id); // qDebug() << m_shownStatesString << "Added a new activity:" << info->id() // << " " << info->name(); showActivity(info, notifyClients); } void ActivityModel::onActivityRemoved(const QString &id) { // qDebug() << m_shownStatesString << "Removed an activity:" << id; hideActivity(id); unregisterActivity(id); } void ActivityModel::onCurrentActivityChanged(const QString &id) { Q_UNUSED(id); for (const auto &activity: m_shownActivities) { Private::emitActivityUpdated(this, m_shownActivities, activity->id(), ActivityCurrent); } } ActivityModel::InfoPtr ActivityModel::registerActivity(const QString &id) { auto position = Private::activityPosition(m_knownActivities, id); // qDebug() << m_shownStatesString << "Registering activity: " << id // << " new? not " << (bool)position; if (position) { return *(position->second); } else { auto activityInfo = std::make_shared(id); auto ptr = activityInfo.get(); connect(ptr, &Info::nameChanged, this, &ActivityModel::onActivityNameChanged); connect(ptr, &Info::descriptionChanged, this, &ActivityModel::onActivityDescriptionChanged); connect(ptr, &Info::iconChanged, this, &ActivityModel::onActivityIconChanged); connect(ptr, &Info::stateChanged, this, &ActivityModel::onActivityStateChanged); m_knownActivities.insert(InfoPtr(activityInfo)); return activityInfo; } } void ActivityModel::unregisterActivity(const QString &id) { // qDebug() << m_shownStatesString << "Deregistering activity: " << id; auto position = Private::activityPosition(m_knownActivities, id); if (position) { if (auto shown = Private::activityPosition(m_shownActivities, id)) { Private::model_remove(this, QModelIndex(), shown->first, shown->first); m_shownActivities.erase(shown->second); } m_knownActivities.erase(position->second); } } void ActivityModel::showActivity(InfoPtr activityInfo, bool notifyClients) { // Should it really be shown? if (!Private::matchingState(activityInfo, m_shownStates)) return; // Is it already shown? if (boost::binary_search(m_shownActivities, activityInfo, InfoPtrComparator())) return; auto registeredPosition = Private::activityPosition(m_knownActivities, activityInfo->id()); if (!registeredPosition) { qDebug() << "Got a request to show an unknown activity, ignoring"; return; } auto activityInfoPtr = *(registeredPosition->second); // qDebug() << m_shownStatesString << "Setting activity visibility to true:" // << activityInfoPtr->id() << activityInfoPtr->name(); auto position = m_shownActivities.insert(activityInfoPtr); if (notifyClients) { unsigned int index = (position.second ? position.first : m_shownActivities.end()) - m_shownActivities.begin(); // qDebug() << m_shownStatesString << " -- MODEL INSERT -- " << index; Private::model_insert(this, QModelIndex(), index, index); } } void ActivityModel::hideActivity(const QString &id) { auto position = Private::activityPosition(m_shownActivities, id); // qDebug() << m_shownStatesString // << "Setting activity visibility to false: " << id; if (position) { // qDebug() << m_shownStatesString << " -- MODEL REMOVE -- " // << position->first; Private::model_remove(this, QModelIndex(), position->first, position->first); m_shownActivities.erase(position->second); } } #define CREATE_SIGNAL_EMITTER(What,Role) \ void ActivityModel::onActivity##What##Changed(const QString &) \ { \ Private::emitActivityUpdated(this, m_shownActivities, sender(), Role); \ } CREATE_SIGNAL_EMITTER(Name,Qt::DisplayRole) CREATE_SIGNAL_EMITTER(Description,ActivityDescription) CREATE_SIGNAL_EMITTER(Icon,Qt::DecorationRole) #undef CREATE_SIGNAL_EMITTER void ActivityModel::onActivityStateChanged(Info::State state) { if (m_shownStates.empty()) { Private::emitActivityUpdated(this, m_shownActivities, sender(), ActivityState); } else { auto info = findActivity(sender()); if (!info) { return; } if (boost::binary_search(m_shownStates, state)) { showActivity(info, true); } else { hideActivity(info->id()); } } } void ActivityModel::backgroundsUpdated(const QStringList &activities) { for (const auto &activity: activities) { Private::emitActivityUpdated(this, m_shownActivities, activity, ActivityBackground); } } void ActivityModel::setShownStates(const QString &states) { m_shownStates.clear(); m_shownStatesString = states; - for (const auto &state: states.split(',')) { + for (const auto &state: states.split(QLatin1Char(','))) { if (state == QStringLiteral("Running")) { m_shownStates.insert(Running); } else if (state == QStringLiteral("Starting")) { m_shownStates.insert(Starting); } else if (state == QStringLiteral("Stopped")) { m_shownStates.insert(Stopped); } else if (state == QStringLiteral("Stopping")) { m_shownStates.insert(Stopping); } } replaceActivities(m_service.activities()); emit shownStatesChanged(states); } QString ActivityModel::shownStates() const { return m_shownStatesString; } int ActivityModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_shownActivities.size(); } QVariant ActivityModel::data(const QModelIndex &index, int role) const { const int row = index.row(); const auto &item = *(m_shownActivities.cbegin() + row); switch (role) { case Qt::DisplayRole: return item->name(); case Qt::DecorationRole: return QIcon::fromTheme(data(index, ActivityIcon).toString()); case ActivityId: return item->id(); case ActivityState: return item->state(); case ActivityIcon: { const QString &icon = item->icon(); // We need a default icon for activities - return icon.isEmpty() ? "preferences-activities" : icon; + return icon.isEmpty() ? QStringLiteral("preferences-activities") : icon; } case ActivityDescription: return item->description(); case ActivityCurrent: return m_service.currentActivity() == item->id(); case ActivityBackground: return Private::backgrounds().forActivity[item->id()]; default: return QVariant(); } } QVariant ActivityModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(section); Q_UNUSED(orientation); Q_UNUSED(role); return QVariant(); } ActivityModel::InfoPtr ActivityModel::findActivity(QObject *ptr) const { auto info = boost::find_if(m_knownActivities, [ptr] (const InfoPtr &info) { return ptr == info.get(); }); if (info == m_knownActivities.end()) { return nullptr; } else { return *info; } } // QFuture Controller::setActivityWhat(id, value) #define CREATE_SETTER(What) \ void ActivityModel::setActivity##What( \ const QString &id, const QString &value, const QJSValue &callback) \ { \ continue_with(m_service.setActivity##What(id, value), callback); \ } CREATE_SETTER(Name) CREATE_SETTER(Description) CREATE_SETTER(Icon) #undef CREATE_SETTER // QFuture Controller::setCurrentActivity(id) void ActivityModel::setCurrentActivity(const QString &id, const QJSValue &callback) { continue_with(m_service.setCurrentActivity(id), callback); } // QFuture Controller::addActivity(name) void ActivityModel::addActivity(const QString &name, const QJSValue &callback) { continue_with(m_service.addActivity(name), callback); } // QFuture Controller::removeActivity(id) void ActivityModel::removeActivity(const QString &id, const QJSValue &callback) { continue_with(m_service.removeActivity(id), callback); } // QFuture Controller::stopActivity(id) void ActivityModel::stopActivity(const QString &id, const QJSValue &callback) { continue_with(m_service.stopActivity(id), callback); } // QFuture Controller::startActivity(id) void ActivityModel::startActivity(const QString &id, const QJSValue &callback) { continue_with(m_service.startActivity(id), callback); } } // namespace Imports } // namespace KActivities // #include "activitymodel.moc" diff --git a/src/imports/resourceinstance.cpp b/src/imports/resourceinstance.cpp index a6e2251f..734ad730 100644 --- a/src/imports/resourceinstance.cpp +++ b/src/imports/resourceinstance.cpp @@ -1,140 +1,140 @@ /*************************************************************************** * Copyright 2011-2015 Marco Martin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public License for more details. * * * * You should have received a copy of the GNU Library 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 . * ***************************************************************************/ #include "resourceinstance.h" #include #include #include #include namespace KActivities { namespace Imports { ResourceInstance::ResourceInstance(QQuickItem *parent) : QQuickItem(parent) { m_syncTimer = new QTimer(this); m_syncTimer->setSingleShot(true); connect(m_syncTimer, SIGNAL(timeout()), this, SLOT(syncWid())); } ResourceInstance::~ResourceInstance() { } void ResourceInstance::syncWid() { QWindow *w = window(); if (!w) { return; } WId wid = w->winId(); if (!m_resourceInstance || m_resourceInstance->winId() != wid) { // qDebug() << "Creating a new instance of the resource" << m_uri << "window id" << wid; m_resourceInstance.reset(new KActivities::ResourceInstance(wid, m_uri, m_mimetype, m_title)); } else { - if (m_uri.scheme().startsWith(QLatin1String("http")) && !m_uri.hasQuery() && m_uri.path().endsWith('/')) { + if (m_uri.scheme().startsWith(QLatin1String("http")) && !m_uri.hasQuery() && m_uri.path().endsWith(QLatin1Char('/'))) { const QString &oldPath = m_uri.path(); m_uri.setPath(oldPath.left(oldPath.length() - 1)); // qDebug() << "Old and new path" << oldPath << m_uri; } else { m_resourceInstance->setUri(m_uri); } // qDebug() << "Setting" << m_uri << m_mimetype << "to window" << wid; m_resourceInstance->setMimetype(m_mimetype); m_resourceInstance->setTitle(m_title); } } QUrl ResourceInstance::uri() const { return m_uri; } void ResourceInstance::setUri(const QUrl &uri) { if (m_uri == uri) { return; } m_uri = uri; m_syncTimer->start(100); } QString ResourceInstance::mimetype() const { return m_mimetype; } void ResourceInstance::setMimetype(const QString &mimetype) { if (m_mimetype == mimetype) { return; } m_mimetype = mimetype; m_syncTimer->start(100); } QString ResourceInstance::title() const { return m_title; } void ResourceInstance::setTitle(const QString &title) { if (m_title == title) { return; } m_title = title; m_syncTimer->start(100); } void ResourceInstance::notifyModified() { //ensure the resource instance exists syncWid(); m_resourceInstance->notifyModified(); } void ResourceInstance::notifyFocusedIn() { //ensure the resource instance exists syncWid(); m_resourceInstance->notifyFocusedIn(); } void ResourceInstance::notifyFocusedOut() { //ensure the resource instance exists syncWid(); m_resourceInstance->notifyFocusedOut(); } } } diff --git a/src/lib/activitiesmodel.cpp b/src/lib/activitiesmodel.cpp index aef2811e..85bafc1d 100644 --- a/src/lib/activitiesmodel.cpp +++ b/src/lib/activitiesmodel.cpp @@ -1,445 +1,445 @@ /* * Copyright (C) 2012 - 2016 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 "activitiesmodel.h" #include "activitiesmodel_p.h" // Qt #include #include #include #include #include #include #include #include // Local #include "utils/remove_if.h" namespace KActivities { namespace Private { template struct ActivityPosition { ActivityPosition() : isValid(false) , index(0) , iterator() { } ActivityPosition(unsigned int index, typename _Container::const_iterator iterator) : isValid(true) , index(index) , iterator(iterator) { } operator bool() const { return isValid; } const bool isValid; const unsigned int index; const typename _Container::const_iterator iterator; typedef typename _Container::value_type ContainerElement; }; /** * Returns whether the activity has a desired state. * If the state is 0, returns true */ template inline bool matchingState(ActivitiesModelPrivate::InfoPtr activity, const T &states) { return states.empty() || states.contains(activity->state()); } /** * Searches for the activity. * Returns an option(index, iterator) for the found activity. */ template inline ActivityPosition<_Container> activityPosition(const _Container &container, const QString &activityId) { auto position = std::find_if(container.begin(), container.end(), [&] (const typename ActivityPosition<_Container>::ContainerElement &activity) { return activity->id() == activityId; } ); return (position != container.end()) ? ActivityPosition<_Container>(position - container.begin(), position) : ActivityPosition<_Container>(); } /** * Notifies the model that an activity was updated */ template inline void emitActivityUpdated(_Model *model, const _Container &container, const QString &activity, int role) { auto position = Private::activityPosition(container, activity); if (position) { emit model->q->dataChanged( model->q->index(position.index), model->q->index(position.index), role == Qt::DecorationRole ? QVector {role, ActivitiesModel::ActivityIconSource} : QVector {role} ); } } /** * Notifies the model that an activity was updated */ template inline void emitActivityUpdated(_Model *model, const _Container &container, QObject *activityInfo, int role) { const auto activity = static_cast (activityInfo); emitActivityUpdated(model, container, activity->id(), role); } } ActivitiesModelPrivate::ActivitiesModelPrivate(ActivitiesModel *parent) : q(parent) { } ActivitiesModel::ActivitiesModel(QObject *parent) : QAbstractListModel(parent) , d(new ActivitiesModelPrivate(this)) { // Initializing role names for qml connect(&d->activities, &Consumer::serviceStatusChanged, this, [this] (Consumer::ServiceStatus status) { d->setServiceStatus(status); }); connect(&d->activities, &Consumer::activityAdded, this, [this] (const QString &activity) { d->onActivityAdded(activity); }); connect(&d->activities, &Consumer::activityRemoved, this, [this] (const QString &activity) { d->onActivityRemoved(activity); }); connect(&d->activities, &Consumer::currentActivityChanged, this, [this] (const QString &activity) { d->onCurrentActivityChanged(activity); }); d->setServiceStatus(d->activities.serviceStatus()); } ActivitiesModel::ActivitiesModel(QVector shownStates, QObject *parent) : QAbstractListModel(parent) , d(new ActivitiesModelPrivate(this)) { d->shownStates = shownStates; // Initializing role names for qml connect(&d->activities, &Consumer::serviceStatusChanged, this, [this] (Consumer::ServiceStatus status) { d->setServiceStatus(status); }); connect(&d->activities, &Consumer::activityAdded, this, [this] (const QString &activity) { d->onActivityAdded(activity); }); connect(&d->activities, &Consumer::activityRemoved, this, [this] (const QString &activity) { d->onActivityRemoved(activity); }); connect(&d->activities, &Consumer::currentActivityChanged, this, [this] (const QString &activity) { d->onCurrentActivityChanged(activity); }); d->setServiceStatus(d->activities.serviceStatus()); } ActivitiesModel::~ActivitiesModel() { delete d; } QHash ActivitiesModel::roleNames() const { return { {ActivityName, "name"}, {ActivityState, "state"}, {ActivityId, "id"}, {ActivityIconSource, "iconSource"}, {ActivityDescription, "description"}, {ActivityBackground, "background"}, {ActivityIsCurrent, "isCurrent"} }; } void ActivitiesModelPrivate::setServiceStatus(Consumer::ServiceStatus) { replaceActivities(activities.activities()); } void ActivitiesModelPrivate::replaceActivities(const QStringList &activities) { q->beginResetModel(); knownActivities.clear(); shownActivities.clear(); for (const QString &activity: activities) { onActivityAdded(activity, false); } q->endResetModel(); } void ActivitiesModelPrivate::onActivityAdded(const QString &id, bool notifyClients) { auto info = registerActivity(id); showActivity(info, notifyClients); } void ActivitiesModelPrivate::onActivityRemoved(const QString &id) { hideActivity(id); unregisterActivity(id); } void ActivitiesModelPrivate::onCurrentActivityChanged(const QString &id) { Q_UNUSED(id); for (const auto &activity: shownActivities) { Private::emitActivityUpdated(this, shownActivities, activity->id(), ActivitiesModel::ActivityIsCurrent); } } ActivitiesModelPrivate::InfoPtr ActivitiesModelPrivate::registerActivity(const QString &id) { auto position = Private::activityPosition(knownActivities, id); if (position) { return *(position.iterator); } else { auto activityInfo = std::make_shared(id); auto ptr = activityInfo.get(); connect(ptr, &Info::nameChanged, this, &ActivitiesModelPrivate::onActivityNameChanged); connect(ptr, &Info::descriptionChanged, this, &ActivitiesModelPrivate::onActivityDescriptionChanged); connect(ptr, &Info::iconChanged, this, &ActivitiesModelPrivate::onActivityIconChanged); connect(ptr, &Info::stateChanged, this, &ActivitiesModelPrivate::onActivityStateChanged); knownActivities.insert(InfoPtr(activityInfo)); return activityInfo; } } void ActivitiesModelPrivate::unregisterActivity(const QString &id) { auto position = Private::activityPosition(knownActivities, id); if (position) { if (auto shown = Private::activityPosition(shownActivities, id)) { q->beginRemoveRows(QModelIndex(), shown.index, shown.index); shownActivities.removeAt(shown.index); q->endRemoveRows(); } knownActivities.removeAt(position.index); } } void ActivitiesModelPrivate::showActivity(InfoPtr activityInfo, bool notifyClients) { // Should it really be shown? if (!Private::matchingState(activityInfo, shownStates)) return; // Is it already shown? if (std::binary_search(shownActivities.cbegin(), shownActivities.cend(), activityInfo, InfoPtrComparator())) return; auto registeredPosition = Private::activityPosition(knownActivities, activityInfo->id()); if (!registeredPosition) { qDebug() << "Got a request to show an unknown activity, ignoring"; return; } const auto activityInfoPtr = *(registeredPosition.iterator); // In C++17, this would be: // const auto [iterator, index, found] = shownActivities.insert(...); const auto _result = shownActivities.insert(activityInfoPtr); // const auto iterator = std::get<0>(_result); const auto index = std::get<1>(_result); const auto found = std::get<2>(_result); if (notifyClients) { q->beginInsertRows(QModelIndex(), index, index); q->endInsertRows(); } } void ActivitiesModelPrivate::hideActivity(const QString &id) { auto position = Private::activityPosition(shownActivities, id); if (position) { q->beginRemoveRows(QModelIndex(), position.index, position.index); shownActivities.removeAt(position.index); q->endRemoveRows(); } } #define CREATE_SIGNAL_EMITTER(What,Role) \ void ActivitiesModelPrivate::onActivity##What##Changed(const QString &) \ { \ Private::emitActivityUpdated(this, shownActivities, sender(), Role); \ } CREATE_SIGNAL_EMITTER(Name,Qt::DisplayRole) CREATE_SIGNAL_EMITTER(Description,ActivitiesModel::ActivityDescription) CREATE_SIGNAL_EMITTER(Icon,Qt::DecorationRole) #undef CREATE_SIGNAL_EMITTER void ActivitiesModelPrivate::onActivityStateChanged(Info::State state) { if (shownStates.empty()) { Private::emitActivityUpdated(this, shownActivities, sender(), ActivitiesModel::ActivityState); } else { auto info = findActivity(sender()); if (!info) { return; } if (shownStates.contains(state)) { showActivity(info, true); } else { hideActivity(info->id()); } } } void ActivitiesModel::setShownStates(const QVector &states) { d->shownStates = states; d->replaceActivities(d->activities.activities()); emit shownStatesChanged(states); } QVector ActivitiesModel::shownStates() const { return d->shownStates; } int ActivitiesModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return d->shownActivities.size(); } QVariant ActivitiesModel::data(const QModelIndex &index, int role) const { const int row = index.row(); const auto &item = d->shownActivities.at(row); switch (role) { case Qt::DisplayRole: case ActivityName: return item->name(); case ActivityId: return item->id(); case ActivityState: return item->state(); case Qt::DecorationRole: case ActivityIconSource: { const QString &icon = item->icon(); // We need a default icon for activities - return icon.isEmpty() ? "preferences-activities" : icon; + return icon.isEmpty() ? QStringLiteral("preferences-activities") : icon; } case ActivityDescription: return item->description(); case ActivityIsCurrent: return d->activities.currentActivity() == item->id(); default: return QVariant(); } } QVariant ActivitiesModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(section); Q_UNUSED(orientation); Q_UNUSED(role); return QVariant(); } ActivitiesModelPrivate::InfoPtr ActivitiesModelPrivate::findActivity(QObject *ptr) const { auto info = std::find_if(knownActivities.cbegin(), knownActivities.cend(), [ptr] (const InfoPtr &info) { return ptr == info.get(); } ); if (info == knownActivities.end()) { return nullptr; } else { return *info; } } } // namespace KActivities // #include "activitiesmodel.moc" diff --git a/src/lib/manager_p.cpp b/src/lib/manager_p.cpp index b4967dad..e4e49c17 100644 --- a/src/lib/manager_p.cpp +++ b/src/lib/manager_p.cpp @@ -1,180 +1,180 @@ /* * Copyright (C) 2010 - 2016 by Ivan Cukic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see . */ #include "manager_p.h" #include #include #include #include #include #include "debug_p.h" #include "mainthreadexecutor_p.h" #include "common/dbus/common.h" #include "utils/dbusfuture_p.h" #include "utils/continue_with.h" #include "version.h" namespace KActivities { Manager *Manager::s_instance = nullptr; Manager::Manager() : QObject() , m_watcher(KAMD_DBUS_SERVICE, QDBusConnection::sessionBus()) , m_service(new KAMD_DBUS_CLASS_INTERFACE(/, Application, this)) , m_activities(new KAMD_DBUS_CLASS_INTERFACE(Activities, Activities, this)) , m_resources(new KAMD_DBUS_CLASS_INTERFACE(Resources, Resources, this)) , m_resourcesLinking(new KAMD_DBUS_CLASS_INTERFACE(Resources/Linking, ResourcesLinking, this)) , m_features(new KAMD_DBUS_CLASS_INTERFACE(Features, Features, this)) , m_serviceRunning(false) { connect(&m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &Manager::serviceOwnerChanged); if (isServiceRunning()) { serviceOwnerChanged(KAMD_DBUS_SERVICE, QString(), KAMD_DBUS_SERVICE); } } Manager *Manager::self() { static std::mutex singleton; std::lock_guard singleton_lock(singleton); #if defined(QT_DEBUG) QLoggingCategory::setFilterRules(QStringLiteral("org.kde.kactivities.lib.core.debug=true")); #endif if (!s_instance) { runInMainThread([] () { // check if the activity manager is already running if (!Manager::isServiceRunning()) { bool disableAutolaunch = QCoreApplication::instance()->property("org.kde.KActivities.core.disableAutostart").toBool(); qCDebug(KAMD_CORELIB) << "Should we start the daemon?"; // start only if not disabled and we have a dbus connection at all if (!disableAutolaunch && QDBusConnection::sessionBus().interface()) { qCDebug(KAMD_CORELIB) << "Starting the activity manager daemon"; auto reply = QDBusConnection::sessionBus().interface()->startService(KAMD_DBUS_SERVICE); if (!reply.isValid()) { //pre Plasma 5.12 the daemon did not support DBus activation. Fall back to manually forking QProcess::startDetached(QStringLiteral("kactivitymanagerd")); } } } // creating a new instance of the class Manager::s_instance = new Manager(); }); } return s_instance; } bool Manager::isServiceRunning() { return (s_instance ? s_instance->m_serviceRunning : true) && QDBusConnection::sessionBus().interface() && QDBusConnection::sessionBus().interface()->isServiceRegistered(KAMD_DBUS_SERVICE); } void Manager::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner) { Q_UNUSED(oldOwner); if (serviceName == KAMD_DBUS_SERVICE) { m_serviceRunning = !newOwner.isEmpty(); emit serviceStatusChanged(m_serviceRunning); if (m_serviceRunning) { using namespace kamd::utils; continue_with( DBusFuture::fromReply(m_service->serviceVersion()), [this] (const optional_view &serviceVersion) { // Test whether the service is older than the library. // If it is, we need to end this if (!serviceVersion.is_initialized()) { qWarning() << "KActivities: FATAL ERROR: Failed to contact the activity manager daemon"; m_serviceRunning = false; return; } - auto split = serviceVersion->split('.'); + auto split = serviceVersion->split(QLatin1Char('.')); QList version; // We require kactivitymanagerd version to be at least the // one before the repository split const int requiredVersion[] = { 6, 2, 0 }; std::transform( split.cbegin(), split.cend(), std::back_inserter(version), [] (const QString &component) { return component.toInt(); }); // if required version is greater than the current version if (std::lexicographical_compare( version.cbegin(), version.cend(), std::begin(requiredVersion), std::end(requiredVersion) )) { - QString libraryVersion = QString::number(requiredVersion[0]) + '.' - + QString::number(requiredVersion[1]) + '.' + QString libraryVersion = QString::number(requiredVersion[0]) + QLatin1Char('.') + + QString::number(requiredVersion[1]) + QLatin1Char('.') + QString::number(requiredVersion[2]); qDebug() << "KActivities service version: " << serviceVersion.get(); qDebug() << "KActivities library version: " << libraryVersion; qFatal("KActivities: FATAL ERROR: The service is older than the library"); } }); } } } Service::Activities *Manager::activities() { return self()->m_activities; } Service::Resources *Manager::resources() { return self()->m_resources; } Service::ResourcesLinking *Manager::resourcesLinking() { return self()->m_resourcesLinking; } Service::Features *Manager::features() { return self()->m_features; } } // namespace KActivities diff --git a/tests/activities-model/window.cpp b/tests/activities-model/window.cpp index ddb36b6d..d551539a 100644 --- a/tests/activities-model/window.cpp +++ b/tests/activities-model/window.cpp @@ -1,127 +1,127 @@ /* * Copyright (C) 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. */ #include "window.h" #include "ui_window.h" #include #include #include class Delegate: public QItemDelegate { public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { painter->save(); const QString title = index.data().toString(); QRect titleRect = painter->fontMetrics().boundingRect(title); //unused int lineHeight = titleRect.height(); // Header background auto rect = option.rect; rect.setHeight(64); titleRect.moveTop(option.rect.top()); titleRect.setWidth(option.rect.width()); if (index.data(KActivities::ActivitiesModel::ActivityIsCurrent).toBool()) { painter->fillRect(rect, QColor(64, 64, 64)); } else { painter->fillRect(rect, QColor(32, 32, 32)); } // Painting the title painter->setPen(QColor(255,255,255)); titleRect.moveTop(titleRect.top() + 8); titleRect.setLeft(64 + 8); titleRect.setWidth(titleRect.width() - 64 - 8); painter->drawText(titleRect, title); titleRect.moveTop(titleRect.bottom() + 16); const QString description = index.data(KActivities::ActivitiesModel::ActivityDescription).toString(); if (!description.isEmpty()) { painter->drawText(titleRect, index.data(KActivities::ActivitiesModel::ActivityDescription).toString()); } else { painter->setPen(QColor(128,128,128)); painter->drawText(titleRect, index.data(KActivities::ActivitiesModel::ActivityId).toString()); } const QString iconName = index.data(KActivities::ActivitiesModel::ActivityIconSource).toString(); if (!iconName.isEmpty()) { painter->drawPixmap(option.rect.x(), option.rect.y(), QIcon::fromTheme(iconName).pixmap(64, 64)); } painter->restore(); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override { Q_UNUSED(option); Q_UNUSED(index); return QSize(0, 70); } }; Window::Window() : ui(new Ui::MainWindow()) , activities(new KActivities::Consumer(this)) , modelRunningActivities(new KActivities::ActivitiesModel({ KActivities::Info::Running, KActivities::Info::Stopping }, this)) , modelStoppedActivities(new KActivities::ActivitiesModel({ KActivities::Info::Stopped, KActivities::Info::Starting }, this)) { ui->setupUi(this); - modelRunningActivities->setObjectName("RUNNING"); + modelRunningActivities->setObjectName(QStringLiteral("RUNNING")); ui->listRunningActivities->setModel(modelRunningActivities); ui->listRunningActivities->setItemDelegate(new Delegate()); - modelStoppedActivities->setObjectName("STOPPED"); + modelStoppedActivities->setObjectName(QStringLiteral("STOPPED")); ui->listStoppedActivities->setModel(modelStoppedActivities); ui->listStoppedActivities->setItemDelegate(new Delegate()); qDebug() << connect(activities, &KActivities::Consumer::runningActivitiesChanged, this, [] (const QStringList &running) { qDebug() << running; }); } void Window::showEvent(QShowEvent * event) { Q_UNUSED(event); KWindowSystem::self()->setOnActivities(effectiveWinId(), QStringList()); KWindowSystem::self()->setOnAllDesktops(effectiveWinId(), true); } Window::~Window() { delete ui; }