diff --git a/applets/kicker/plugin/appentry.cpp b/applets/kicker/plugin/appentry.cpp index f783c34f4..54ba2bfd6 100644 --- a/applets/kicker/plugin/appentry.cpp +++ b/applets/kicker/plugin/appentry.cpp @@ -1,301 +1,301 @@ /*************************************************************************** * Copyright (C) 201 by Eike Hein * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include #include "appentry.h" #include "actionlist.h" #include "appsmodel.h" #include "containmentinterface.h" #include #include #include #include #if HAVE_X11 #include #endif #include #include #include #include #include #include #include #include #include #include #include AppEntry::AppEntry(AbstractModel *owner, KService::Ptr service, NameFormat nameFormat) : AbstractEntry(owner) , m_service(service) { if (m_service) { init(nameFormat); } } AppEntry::AppEntry(AbstractModel *owner, const QString &id) : AbstractEntry(owner) { const QUrl url(id); - if (url.scheme() == QStringLiteral("preferred")) { + if (url.scheme() == QLatin1String("preferred")) { m_service = defaultAppByName(url.host()); m_id = id; } else { m_service = KService::serviceByStorageId(id); } if (m_service) { init((NameFormat)owner->rootModel()->property("appNameFormat").toInt()); } } void AppEntry::init(NameFormat nameFormat) { m_name = nameFromService(m_service, nameFormat); if (nameFormat == GenericNameOnly) { m_description = nameFromService(m_service, NameOnly); } else { m_description = nameFromService(m_service, GenericNameOnly); } } bool AppEntry::isValid() const { return m_service; } QIcon AppEntry::icon() const { if (m_icon.isNull()) { m_icon = QIcon::fromTheme(m_service->icon(), QIcon::fromTheme(QStringLiteral("unknown"))); } return m_icon; } QString AppEntry::name() const { return m_name; } QString AppEntry::description() const { return m_description; } KService::Ptr AppEntry::service() const { return m_service; } QString AppEntry::id() const { if (!m_id.isEmpty()) { return m_id; } return m_service->storageId(); } QString AppEntry::menuId() const { return m_service->menuId(); } QUrl AppEntry::url() const { return QUrl::fromLocalFile(Kicker::resolvedServiceEntryPath(m_service)); } bool AppEntry::hasActions() const { return true; } QVariantList AppEntry::actions() const { QVariantList actionList; actionList << Kicker::jumpListActions(m_service); if (!actionList.isEmpty()) { actionList << Kicker::createSeparatorActionItem(); } QObject *appletInterface = m_owner->rootModel()->property("appletInterface").value(); const bool systemImmutable = appletInterface->property("immutability").toInt() == Plasma::Types::SystemImmutable; const QVariantList &addLauncherActions = Kicker::createAddLauncherActionList(appletInterface, m_service); if (!systemImmutable && !addLauncherActions.isEmpty()) { actionList << addLauncherActions << Kicker::createSeparatorActionItem(); } const QVariantList &recentDocuments = Kicker::recentDocumentActions(m_service); if (!recentDocuments.isEmpty()) { actionList << recentDocuments << Kicker::createSeparatorActionItem(); } // Don't allow adding launchers, editing, hiding, or uninstalling applications // when system is immutable. if (systemImmutable) { return actionList; } if (m_service->isApplication()) { actionList << Kicker::createSeparatorActionItem(); actionList << Kicker::editApplicationAction(m_service); actionList << Kicker::appstreamActions(m_service); } QQmlPropertyMap *appletConfig = qobject_cast(appletInterface->property("configuration").value()); if (appletConfig && appletConfig->contains(QLatin1String("hiddenApplications")) && qobject_cast(m_owner)) { const QStringList &hiddenApps = appletConfig->value(QLatin1String("hiddenApplications")).toStringList(); if (!hiddenApps.contains(m_service->menuId())) { actionList << Kicker::createActionItem(i18n("Hide Application"), QStringLiteral("hideApplication")); } } return actionList; } bool AppEntry::run(const QString& actionId, const QVariant &argument) { if (!m_service->isValid()) { return false; } if (actionId.isEmpty()) { quint32 timeStamp = 0; #if HAVE_X11 if (QX11Info::isPlatformX11()) { timeStamp = QX11Info::appUserTime(); } #endif KRun::runApplication(*m_service, {}, nullptr, KRun::DeleteTemporaryFiles, {}, KStartupInfo::createNewStartupIdForTimestamp(timeStamp)); KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("applications:") + m_service->storageId()), QStringLiteral("org.kde.plasma.kicker")); return true; } QObject *appletInterface = m_owner->rootModel()->property("appletInterface").value(); if (Kicker::handleAddLauncherAction(actionId, appletInterface, m_service)) { return true; } else if (Kicker::handleEditApplicationAction(actionId, m_service)) { return true; } else if (Kicker::handleAppstreamActions(actionId, argument)) { return true; } else if (actionId == QLatin1String("_kicker_jumpListAction")) { return KRun::run(argument.toString(), {}, nullptr, m_service->name(), m_service->icon()); } return Kicker::handleRecentDocumentAction(m_service, actionId, argument); } QString AppEntry::nameFromService(const KService::Ptr service, NameFormat nameFormat) { const QString &name = service->name(); QString genericName = service->genericName(); if (genericName.isEmpty()) { genericName = service->comment(); } if (nameFormat == NameOnly || genericName.isEmpty() || name == genericName) { return name; } else if (nameFormat == GenericNameOnly) { return genericName; } else if (nameFormat == NameAndGenericName) { return i18nc("App name (Generic name)", "%1 (%2)", name, genericName); } else { return i18nc("Generic name (App name)", "%1 (%2)", genericName, name); } } KService::Ptr AppEntry::defaultAppByName(const QString& name) { if (name == QLatin1String("browser")) { KConfigGroup config(KSharedConfig::openConfig(), "General"); QString browser = config.readPathEntry("BrowserApplication", QString()); if (browser.isEmpty()) { return KMimeTypeTrader::self()->preferredService(QLatin1String("text/html")); } else if (browser.startsWith(QLatin1Char('!'))) { browser = browser.mid(1); } return KService::serviceByStorageId(browser); } return KService::Ptr(); } AppGroupEntry::AppGroupEntry(AppsModel *parentModel, KServiceGroup::Ptr group, bool paginate, int pageSize, bool flat, bool sorted, bool separators, int appNameFormat) : AbstractGroupEntry(parentModel), m_group(group) { AppsModel* model = new AppsModel(group->entryPath(), paginate, pageSize, flat, sorted, separators, parentModel); model->setAppNameFormat(appNameFormat); m_childModel = model; QObject::connect(parentModel, &AppsModel::cleared, model, &AppsModel::deleteLater); QObject::connect(model, &AppsModel::countChanged, [parentModel, this] { if (parentModel) { parentModel->entryChanged(this); } } ); QObject::connect(model, &AppsModel::hiddenEntriesChanged, [parentModel, this] { if (parentModel) { parentModel->entryChanged(this); } } ); } QIcon AppGroupEntry::icon() const { if (m_icon.isNull()) { m_icon = QIcon::fromTheme(m_group->icon(), QIcon::fromTheme(QStringLiteral("unknown"))); } return m_icon; } QString AppGroupEntry::name() const { return m_group->caption(); } bool AppGroupEntry::hasChildren() const { return m_childModel && m_childModel->count() > 0; } AbstractModel *AppGroupEntry::childModel() const { return m_childModel; } diff --git a/applets/kicker/plugin/containmentinterface.cpp b/applets/kicker/plugin/containmentinterface.cpp index adc942c12..e01a97f8e 100644 --- a/applets/kicker/plugin/containmentinterface.cpp +++ b/applets/kicker/plugin/containmentinterface.cpp @@ -1,252 +1,252 @@ /*************************************************************************** * Copyright (C) 2014 by Eike Hein * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "containmentinterface.h" #include #include #include #include #include // FIXME HACK TODO: Unfortunately we have no choice but to hard-code a list of // applets we know to expose the correct interface right now -- this is slated // for replacement with some form of generic service. QStringList ContainmentInterface::m_knownTaskManagers = QStringList() << QLatin1String("org.kde.plasma.taskmanager") << QLatin1String("org.kde.plasma.icontasks") << QLatin1String("org.kde.plasma.expandingiconstaskmanager"); ContainmentInterface::ContainmentInterface(QObject *parent) : QObject(parent) { } ContainmentInterface::~ContainmentInterface() { } bool ContainmentInterface::mayAddLauncher(QObject *appletInterface, ContainmentInterface::Target target, const QString &entryPath) { if (!appletInterface) { return false; } Plasma::Applet *applet = appletInterface->property("_plasma_applet").value(); Plasma::Containment *containment = applet->containment(); if (!containment) { return false; } Plasma::Corona *corona = containment->corona(); if (!corona) { return false; } switch (target) { case Desktop: { containment = corona->containmentForScreen(containment->screen()); if (containment) { return (containment->immutability() == Plasma::Types::Mutable); } break; } case Panel: { if (containment->pluginMetaData().pluginId() == QLatin1String("org.kde.panel")) { return (containment->immutability() == Plasma::Types::Mutable); } break; } case TaskManager: { if (!entryPath.isEmpty() && containment->pluginMetaData().pluginId() == QLatin1String("org.kde.panel")) { const Plasma::Applet *taskManager = nullptr; foreach(const Plasma::Applet *applet, containment->applets()) { if (m_knownTaskManagers.contains(applet->pluginMetaData().pluginId())) { taskManager = applet; break; } } if (taskManager) { QQuickItem* gObj = qobject_cast(taskManager->property("_plasma_graphicObject").value()); if (!gObj || !gObj->childItems().count()) { return false; } QQuickItem *rootItem = gObj->childItems().first(); QVariant ret; QMetaObject::invokeMethod(rootItem, "hasLauncher", Q_RETURN_ARG(QVariant, ret), Q_ARG(QVariant, QUrl::fromLocalFile(entryPath))); return !ret.toBool(); } } break; } } return false; } void ContainmentInterface::addLauncher(QObject *appletInterface, ContainmentInterface::Target target, const QString &entryPath) { if (!appletInterface) { return; } Plasma::Applet *applet = appletInterface->property("_plasma_applet").value(); Plasma::Containment *containment = applet->containment(); if (!containment) { return; } Plasma::Corona *corona = containment->corona(); if (!corona) { return; } switch (target) { case Desktop: { containment = corona->containmentForScreen(containment->screen()); if (!containment) { return; } const QStringList &containmentProvides = KPluginMetaData::readStringList(containment->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")); if (containmentProvides.contains(QLatin1String("org.kde.plasma.filemanagement"))) { QQuickItem* gObj = qobject_cast(containment->property("_plasma_graphicObject").value()); if (!gObj || !gObj->childItems().count()) { return; } QQuickItem *rootItem = nullptr; foreach(QQuickItem *item, gObj->childItems()) { - if (item->objectName() == QStringLiteral("folder")) { + if (item->objectName() == QLatin1String("folder")) { rootItem = item; break; } } if (rootItem) { QMetaObject::invokeMethod(rootItem, "addLauncher", Q_ARG(QVariant, QUrl::fromLocalFile(entryPath))); } } else { containment->createApplet(QStringLiteral("org.kde.plasma.icon"), QVariantList() << entryPath); } break; } case Panel: { if (containment->pluginMetaData().pluginId() == QLatin1String("org.kde.panel")) { containment->createApplet(QStringLiteral("org.kde.plasma.icon"), QVariantList() << entryPath); } break; } case TaskManager: { if (containment->pluginMetaData().pluginId() == QLatin1String("org.kde.panel")) { const Plasma::Applet *taskManager = nullptr; foreach(const Plasma::Applet *applet, containment->applets()) { if (m_knownTaskManagers.contains(applet->pluginMetaData().pluginId())) { taskManager = applet; break; } } if (taskManager) { QQuickItem* gObj = qobject_cast(taskManager->property("_plasma_graphicObject").value()); if (!gObj || !gObj->childItems().count()) { return; } QQuickItem *rootItem = gObj->childItems().first(); QMetaObject::invokeMethod(rootItem, "addLauncher", Q_ARG(QVariant, QUrl::fromLocalFile(entryPath))); } } break; } } } QObject* ContainmentInterface::screenContainment(QObject *appletInterface) { if (!appletInterface) { return nullptr; } const Plasma::Applet *applet = appletInterface->property("_plasma_applet").value(); Plasma::Containment *containment = applet->containment(); if (!containment) { return nullptr; } Plasma::Corona *corona = containment->corona(); if (!corona) { return nullptr; } return corona->containmentForScreen(containment->screen()); } bool ContainmentInterface::screenContainmentMutable(QObject *appletInterface) { const Plasma::Containment *containment = static_cast(screenContainment(appletInterface)); if (containment) { return (containment->immutability() == Plasma::Types::Mutable); } return false; } void ContainmentInterface::ensureMutable(Plasma::Containment *containment) { if (containment && containment->immutability() != Plasma::Types::Mutable) { containment->actions()->action(QStringLiteral("lock widgets"))->trigger(); } } diff --git a/applets/kicker/plugin/kastatsfavoritesmodel.cpp b/applets/kicker/plugin/kastatsfavoritesmodel.cpp index bcb67ce9e..fe49c54a1 100644 --- a/applets/kicker/plugin/kastatsfavoritesmodel.cpp +++ b/applets/kicker/plugin/kastatsfavoritesmodel.cpp @@ -1,719 +1,719 @@ /*************************************************************************** * Copyright (C) 2014-2015 by Eike Hein * * Copyright (C) 2016-2017 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) 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "kastatsfavoritesmodel.h" #include "appentry.h" #include "contactentry.h" #include "fileentry.h" #include "actionlist.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #include namespace KAStats = KActivities::Stats; using namespace KAStats; using namespace KAStats::Terms; #define AGENT_APPLICATIONS QStringLiteral("org.kde.plasma.favorites.applications") #define AGENT_CONTACTS QStringLiteral("org.kde.plasma.favorites.contacts") #define AGENT_DOCUMENTS QStringLiteral("org.kde.plasma.favorites.documents") QString agentForUrl(const QString &url) { return url.startsWith(QLatin1String("ktp:")) ? AGENT_CONTACTS : url.startsWith(QLatin1String("preferred:")) ? AGENT_APPLICATIONS : url.startsWith(QLatin1String("applications:")) ? AGENT_APPLICATIONS : (url.startsWith(QLatin1Char('/')) && !url.endsWith(QLatin1String(".desktop"))) ? AGENT_DOCUMENTS : (url.startsWith(QLatin1String("file:/")) && !url.endsWith(QLatin1String(".desktop"))) ? AGENT_DOCUMENTS // use applications as the default : AGENT_APPLICATIONS; } class KAStatsFavoritesModel::Private: public QAbstractListModel { public: class NormalizedId { public: NormalizedId() { } NormalizedId(const Private *parent, const QString &id) { if (id.isEmpty()) return; QSharedPointer entry = nullptr; if (parent->m_itemEntries.contains(id)) { entry = parent->m_itemEntries[id]; } else { // This entry is not cached - it is temporary, // so let's clean up when we exit this function entry = parent->entryForResource(id); } if (!entry || !entry->isValid()) { qWarning() << "Entry is not valid" << id << entry; m_id = id; return; } const auto url = entry->url(); qCDebug(KICKER_DEBUG) << "Original id is: " << id << ", and the url is" << url; // Preferred applications need special handling if (entry->id().startsWith(QLatin1String("preferred:"))) { m_id = entry->id(); return; } // If this is an application, use the applications:-format url auto appEntry = dynamic_cast(entry.data()); if (appEntry && !appEntry->menuId().isEmpty()) { m_id = QStringLiteral("applications:") + appEntry->menuId(); return; } // We want to resolve symbolic links not to have two paths // refer to the same .desktop file if (url.isLocalFile()) { QFileInfo file(url.toLocalFile()); if (file.exists()) { m_id = QUrl::fromLocalFile(file.canonicalFilePath()).toString(); return; } } // If this is a file, we should have already covered it if (url.scheme() == QLatin1String("file")) { return; } m_id = url.toString(); } const QString& value() const { return m_id; } bool operator==(const NormalizedId &other) const { return m_id == other.m_id; } private: QString m_id; }; NormalizedId normalizedId(const QString &id) const { return NormalizedId(this, id); } QSharedPointer entryForResource(const QString &resource) const { using SP = QSharedPointer; const auto agent = agentForUrl(resource); if (agent == AGENT_CONTACTS) { return SP(new ContactEntry(q, resource)); } else if (agent == AGENT_DOCUMENTS) { if (resource.startsWith(QLatin1String("/"))) { return SP(new FileEntry(q, QUrl::fromLocalFile(resource))); } else { return SP(new FileEntry(q, QUrl(resource))); } } else if (agent == AGENT_APPLICATIONS) { if (resource.startsWith(QLatin1String("applications:"))) { return SP(new AppEntry(q, resource.mid(13))); } else { return SP(new AppEntry(q, resource)); } } else { return {}; } } Private(KAStatsFavoritesModel *parent, QString clientId) : q(parent) , m_query( LinkedResources | Agent { AGENT_APPLICATIONS, AGENT_CONTACTS, AGENT_DOCUMENTS } | Type::any() | Activity::current() | Activity::global() | Limit::all() ) , m_watcher(m_query) , m_clientId(clientId) { // Connecting the watcher connect(&m_watcher, &ResultWatcher::resultLinked, [this] (const QString &resource) { addResult(resource, -1); }); connect(&m_watcher, &ResultWatcher::resultUnlinked, [this] (const QString &resource) { removeResult(resource); }); // Loading the items order const auto cfg = KSharedConfig::openConfig(QStringLiteral("kactivitymanagerd-statsrc")); // We want first to check whether we have an ordering for this activity. // If not, we will try to get a global one for this applet const QString thisGroupName = QStringLiteral("Favorites-") + clientId + QStringLiteral("-") + m_activities.currentActivity(); const QString globalGroupName = QStringLiteral("Favorites-") + clientId + QStringLiteral("-global"); KConfigGroup thisCfgGroup(cfg, thisGroupName); KConfigGroup globalCfgGroup(cfg, globalGroupName); QStringList ordering = thisCfgGroup.readEntry("ordering", QStringList()) + globalCfgGroup.readEntry("ordering", QStringList()); qCDebug(KICKER_DEBUG) << "Loading the ordering " << ordering; // Loading the results without emitting any model signals qCDebug(KICKER_DEBUG) << "Query is" << m_query; ResultSet results(m_query); for (const auto& result: results) { qCDebug(KICKER_DEBUG) << "Got " << result.resource() << " -->"; addResult(result.resource(), -1, false); } // Normalizing all the ids std::transform(ordering.begin(), ordering.end(), ordering.begin(), [&] (const QString &item) { return normalizedId(item).value(); }); // Sorting the items in the cache std::sort(m_items.begin(), m_items.end(), [&] (const NormalizedId &left, const NormalizedId &right) { auto leftIndex = ordering.indexOf(left.value()); auto rightIndex = ordering.indexOf(right.value()); return (leftIndex == -1 && rightIndex == -1) ? left.value() < right.value() : (leftIndex == -1) ? false : (rightIndex == -1) ? true : // otherwise leftIndex < rightIndex; }); // Debugging: QVector itemStrings(m_items.size()); std::transform(m_items.cbegin(), m_items.cend(), itemStrings.begin(), [] (const NormalizedId &item) { return item.value(); }); qCDebug(KICKER_DEBUG) << "After ordering: " << itemStrings; } void addResult(const QString &_resource, int index, bool notifyModel = true) { // We want even files to have a proper URL const auto resource = _resource.startsWith(QLatin1Char('/')) ? QUrl::fromLocalFile(_resource).toString() : _resource; qCDebug(KICKER_DEBUG) << "Adding result" << resource << "already present?" << m_itemEntries.contains(resource); if (m_itemEntries.contains(resource)) return; auto entry = entryForResource(resource); if (!entry || !entry->isValid()) { qCDebug(KICKER_DEBUG) << "Entry is not valid!"; return; } if (index == -1) { index = m_items.count(); } if (notifyModel) { beginInsertRows(QModelIndex(), index, index); } auto url = entry->url(); m_itemEntries[resource] = m_itemEntries[entry->id()] = m_itemEntries[url.toString()] = m_itemEntries[url.toLocalFile()] = entry; auto normalized = normalizedId(resource); m_items.insert(index, normalized); m_itemEntries[normalized.value()] = entry; if (notifyModel) { endInsertRows(); saveOrdering(); } } void removeResult(const QString &resource) { auto normalized = normalizedId(resource); // If we know this item will not really be removed, // but only that activities it is on have changed, // lets leave it if (m_ignoredItems.contains(normalized.value())) { m_ignoredItems.removeAll(normalized.value()); return; } qCDebug(KICKER_DEBUG) << "Removing result" << resource; auto index = m_items.indexOf(normalizedId(resource)); if (index == -1) return; beginRemoveRows(QModelIndex(), index, index); auto entry = m_itemEntries[resource]; m_items.removeAt(index); // Removing the entry from the cache QMutableHashIterator> i(m_itemEntries); while (i.hasNext()) { i.next(); if (i.value() == entry) { i.remove(); } } endRemoveRows(); } int rowCount(const QModelIndex &parent = QModelIndex()) const override { if (parent.isValid()) return 0; return m_items.count(); } QVariant data(const QModelIndex &item, int role = Qt::DisplayRole) const override { if (item.parent().isValid()) return QVariant(); const auto index = item.row(); const auto entry = m_itemEntries[m_items[index].value()]; return entry == nullptr ? QVariant() : role == Qt::DisplayRole ? entry->name() : role == Qt::DecorationRole ? entry->icon() : role == Kicker::DescriptionRole ? entry->description() : role == Kicker::FavoriteIdRole ? entry->id() : role == Kicker::UrlRole ? entry->url() : role == Kicker::HasActionListRole ? entry->hasActions() : role == Kicker::ActionListRole ? entry->actions() : QVariant(); } bool trigger(int row, const QString &actionId, const QVariant &argument) { if (row < 0 || row >= rowCount()) { return false; } const QString id = data(index(row, 0), Kicker::UrlRole).toString(); return m_itemEntries.contains(id) ? m_itemEntries[id]->run(actionId, argument) : false; } void move(int from, int to) { if (from < 0) return; if (from >= m_items.count()) return; if (to < 0) return; if (to >= m_items.count()) return; if (from == to) return; const int modelTo = to + (to > from ? 1 : 0); if (q->beginMoveRows(QModelIndex(), from, from, QModelIndex(), modelTo)) { m_items.move(from, to); q->endMoveRows(); qCDebug(KICKER_DEBUG) << "Save ordering (from Private::move) -->"; saveOrdering(); } } void saveOrdering() { QStringList ids; for (const auto& item: m_items) { ids << item.value(); } qCDebug(KICKER_DEBUG) << "Save ordering (from Private::saveOrdering) -->"; saveOrdering(ids, m_clientId, m_activities.currentActivity()); } static void saveOrdering(const QStringList &ids, const QString &clientId, const QString ¤tActivity) { const auto cfg = KSharedConfig::openConfig(QStringLiteral("kactivitymanagerd-statsrc")); QStringList activities { currentActivity, QStringLiteral("global") }; qCDebug(KICKER_DEBUG) << "Saving ordering for" << currentActivity << "and global" << ids; for (const auto& activity: activities) { const QString groupName = QStringLiteral("Favorites-") + clientId + QStringLiteral("-") + activity; KConfigGroup cfgGroup(cfg, groupName); cfgGroup.writeEntry("ordering", ids); } cfg->sync(); } KAStatsFavoritesModel *const q; KActivities::Consumer m_activities; Query m_query; ResultWatcher m_watcher; QString m_clientId; QVector m_items; QHash> m_itemEntries; QStringList m_ignoredItems; }; KAStatsFavoritesModel::KAStatsFavoritesModel(QObject *parent) : PlaceholderModel(parent) , d(nullptr) // we have no client id yet , m_enabled(true) , m_maxFavorites(-1) , m_activities(new KActivities::Consumer(this)) { connect(m_activities, &KActivities::Consumer::currentActivityChanged, this, [&] (const QString ¤tActivity) { qCDebug(KICKER_DEBUG) << "Activity just got changed to" << currentActivity; Q_UNUSED(currentActivity); if (d) { auto clientId = d->m_clientId; initForClient(clientId); } }); } KAStatsFavoritesModel::~KAStatsFavoritesModel() { delete d; } void KAStatsFavoritesModel::initForClient(const QString &clientId) { qCDebug(KICKER_DEBUG) << "initForClient" << clientId; setSourceModel(nullptr); delete d; d = new Private( this, clientId ); setSourceModel(d); } QString KAStatsFavoritesModel::description() const { return i18n("Favorites"); } bool KAStatsFavoritesModel::trigger(int row, const QString &actionId, const QVariant &argument) { return d && d->trigger(row, actionId, argument); } bool KAStatsFavoritesModel::enabled() const { return m_enabled; } int KAStatsFavoritesModel::maxFavorites() const { return m_maxFavorites; } void KAStatsFavoritesModel::setMaxFavorites(int max) { Q_UNUSED(max); } void KAStatsFavoritesModel::setEnabled(bool enable) { if (m_enabled != enable) { m_enabled = enable; emit enabledChanged(); } } QStringList KAStatsFavoritesModel::favorites() const { qWarning() << "KAStatsFavoritesModel::favorites returns nothing, it is here just to keep the API backwards-compatible"; return QStringList(); } void KAStatsFavoritesModel::setFavorites(const QStringList& favorites) { Q_UNUSED(favorites); qWarning() << "KAStatsFavoritesModel::setFavorites is ignored"; } bool KAStatsFavoritesModel::isFavorite(const QString &id) const { return d && d->m_itemEntries.contains(id); } void KAStatsFavoritesModel::portOldFavorites(const QStringList &ids) { if (!d) return; qCDebug(KICKER_DEBUG) << "portOldFavorites" << ids; const QString activityId = QStringLiteral(":global"); std::for_each(ids.begin(), ids.end(), [&] (const QString &id) { addFavoriteTo(id, activityId); }); // Resetting the model auto clientId = d->m_clientId; setSourceModel(nullptr); delete d; d = nullptr; qCDebug(KICKER_DEBUG) << "Save ordering (from portOldFavorites) -->"; Private::saveOrdering(ids, clientId, m_activities->currentActivity()); QTimer::singleShot(500, std::bind(&KAStatsFavoritesModel::initForClient, this, clientId)); } void KAStatsFavoritesModel::addFavorite(const QString &id, int index) { qCDebug(KICKER_DEBUG) << "addFavorite" << id << index << " -->"; addFavoriteTo(id, QStringLiteral(":global"), index); } void KAStatsFavoritesModel::removeFavorite(const QString &id) { qCDebug(KICKER_DEBUG) << "removeFavorite" << id << " -->"; removeFavoriteFrom(id, QStringLiteral(":any")); } void KAStatsFavoritesModel::addFavoriteTo(const QString &id, const QString &activityId, int index) { qCDebug(KICKER_DEBUG) << "addFavoriteTo" << id << activityId << index << " -->"; addFavoriteTo(id, Activity(activityId), index); } void KAStatsFavoritesModel::removeFavoriteFrom(const QString &id, const QString &activityId) { qCDebug(KICKER_DEBUG) << "removeFavoriteFrom" << id << activityId << " -->"; removeFavoriteFrom(id, Activity(activityId)); } void KAStatsFavoritesModel::addFavoriteTo(const QString &id, const Activity &activity, int index) { if (!d || id.isEmpty()) return; Q_ASSERT(!activity.values.isEmpty()); setDropPlaceholderIndex(-1); QStringList matchers { d->m_activities.currentActivity(), QStringLiteral(":global"), QStringLiteral(":current") }; if (std::find_first_of(activity.values.cbegin(), activity.values.cend(), matchers.cbegin(), matchers.cend()) != activity.values.cend()) { d->addResult(id, index); } const auto url = d->normalizedId(id).value(); qCDebug(KICKER_DEBUG) << "addFavoriteTo" << id << activity << index << url << " (actual)"; if (url.isEmpty()) return; d->m_watcher.linkToActivity(QUrl(url), activity, Agent(agentForUrl(url))); } void KAStatsFavoritesModel::removeFavoriteFrom(const QString &id, const Activity &activity) { if (!d || id.isEmpty()) return; const auto url = d->normalizedId(id).value(); Q_ASSERT(!activity.values.isEmpty()); qCDebug(KICKER_DEBUG) << "addFavoriteTo" << id << activity << url << " (actual)"; if (url.isEmpty()) return; d->m_watcher.unlinkFromActivity(QUrl(url), activity, Agent(agentForUrl(url))); } void KAStatsFavoritesModel::setFavoriteOn(const QString &id, const QString &activityId) { if (!d || id.isEmpty()) return; const auto url = d->normalizedId(id).value(); qCDebug(KICKER_DEBUG) << "setFavoriteOn" << id << activityId << url << " (actual)"; qCDebug(KICKER_DEBUG) << "%%%%%%%%%%% Activity is" << activityId; if (activityId.isEmpty() || activityId == QLatin1String(":any") || - activityId == QStringLiteral(":global") || + activityId == QLatin1String(":global") || activityId == m_activities->currentActivity()) { d->m_ignoredItems << url; } d->m_watcher.unlinkFromActivity(QUrl(url), Activity::any(), Agent(agentForUrl(url))); d->m_watcher.linkToActivity(QUrl(url), activityId, Agent(agentForUrl(url))); } void KAStatsFavoritesModel::moveRow(int from, int to) { if (!d) return; d->move(from, to); } AbstractModel *KAStatsFavoritesModel::favoritesModel() { return this; } void KAStatsFavoritesModel::refresh() { } QObject *KAStatsFavoritesModel::activities() const { return m_activities; } QString KAStatsFavoritesModel::activityNameForId(const QString &activityId) const { // It is safe to use a short-lived object here, // we are always synced with KAMD in plasma KActivities::Info info(activityId); return info.name(); } QStringList KAStatsFavoritesModel::linkedActivitiesFor(const QString &id) const { if (!d) { qCDebug(KICKER_DEBUG) << "Linked for" << id << "is empty, no Private instance"; return {}; } auto url = d->normalizedId(id).value(); if (url.startsWith(QLatin1String("file:"))) { url = QUrl(url).toLocalFile(); } if (url.isEmpty()) { qCDebug(KICKER_DEBUG) << "The url for" << id << "is empty"; return {}; } auto query = LinkedResources | Agent { AGENT_APPLICATIONS, AGENT_CONTACTS, AGENT_DOCUMENTS } | Type::any() | Activity::any() | Url(url) | Limit::all(); ResultSet results(query); for (const auto &result: results) { qCDebug(KICKER_DEBUG) << "Returning" << result.linkedActivities() << "for" << id << url; return result.linkedActivities(); } qCDebug(KICKER_DEBUG) << "Returning empty list of activities for" << id << url; return {}; } diff --git a/applets/kicker/plugin/simplefavoritesmodel.cpp b/applets/kicker/plugin/simplefavoritesmodel.cpp index a2e68abff..9bcbcdee1 100644 --- a/applets/kicker/plugin/simplefavoritesmodel.cpp +++ b/applets/kicker/plugin/simplefavoritesmodel.cpp @@ -1,333 +1,333 @@ /*************************************************************************** * Copyright (C) 2014-2015 by Eike Hein * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "simplefavoritesmodel.h" #include "appentry.h" #include "contactentry.h" #include "fileentry.h" #include "systementry.h" #include "actionlist.h" #include SimpleFavoritesModel::SimpleFavoritesModel(QObject *parent) : AbstractModel(parent) , m_enabled(true) , m_maxFavorites(-1) , m_dropPlaceholderIndex(-1) { } SimpleFavoritesModel::~SimpleFavoritesModel() { qDeleteAll(m_entryList); } QString SimpleFavoritesModel::description() const { return i18n("Favorites"); } QVariant SimpleFavoritesModel::data(const QModelIndex& index, int role) const { if (!index.isValid() || index.row() >= rowCount()) { return QVariant(); } if (index.row() == m_dropPlaceholderIndex) { if (role == Kicker::IsDropPlaceholderRole) { return true; } else { return QVariant(); } } int mappedIndex = index.row(); if (m_dropPlaceholderIndex != -1 && mappedIndex > m_dropPlaceholderIndex) { --mappedIndex; } const AbstractEntry *entry = m_entryList.at(mappedIndex); if (role == Qt::DisplayRole) { return entry->name(); } else if (role == Qt::DecorationRole) { return entry->icon(); } else if (role == Kicker::DescriptionRole) { return entry->description(); } else if (role == Kicker::FavoriteIdRole) { return entry->id(); } else if (role == Kicker::UrlRole) { return entry->url(); } else if (role == Kicker::HasActionListRole) { return entry->hasActions(); } else if (role == Kicker::ActionListRole) { return entry->actions(); } return QVariant(); } int SimpleFavoritesModel::rowCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : m_entryList.count() + (m_dropPlaceholderIndex != -1 ? 1 : 0); } bool SimpleFavoritesModel::trigger(int row, const QString &actionId, const QVariant &argument) { if (row < 0 || row >= m_entryList.count()) { return false; } return m_entryList.at(row)->run(actionId, argument); } bool SimpleFavoritesModel::enabled() const { return m_enabled; } void SimpleFavoritesModel::setEnabled(bool enable) { if (m_enabled != enable) { m_enabled = enable; emit enabledChanged(); } } QStringList SimpleFavoritesModel::favorites() const { return m_favorites; } void SimpleFavoritesModel::setFavorites(const QStringList& favorites) { QStringList _favorites(favorites); _favorites.removeDuplicates(); if (_favorites != m_favorites) { m_favorites = _favorites; refresh(); } } int SimpleFavoritesModel::maxFavorites() const { return m_maxFavorites; } void SimpleFavoritesModel::setMaxFavorites(int max) { if (m_maxFavorites != max) { m_maxFavorites = max; if (m_maxFavorites != -1 && m_favorites.count() > m_maxFavorites) { refresh(); } emit maxFavoritesChanged(); } } bool SimpleFavoritesModel::isFavorite(const QString &id) const { return m_favorites.contains(id); } void SimpleFavoritesModel::addFavorite(const QString &id, int index) { if (!m_enabled || id.isEmpty()) { return; } if (m_maxFavorites != -1 && m_favorites.count() == m_maxFavorites) { return; } AbstractEntry *entry = favoriteFromId(id); if (!entry || !entry->isValid()) { delete entry; return; } setDropPlaceholderIndex(-1); int insertIndex = (index != -1) ? index : m_entryList.count(); beginInsertRows(QModelIndex(), insertIndex, insertIndex); m_entryList.insert(insertIndex, entry); m_favorites.insert(insertIndex, entry->id()); endInsertRows(); emit countChanged(); emit favoritesChanged(); } void SimpleFavoritesModel::removeFavorite(const QString &id) { if (!m_enabled || id.isEmpty()) { return; } int index = m_favorites.indexOf(id); if (index != -1) { setDropPlaceholderIndex(-1); beginRemoveRows(QModelIndex(), index, index); delete m_entryList[index]; m_entryList.removeAt(index); m_favorites.removeAt(index); endRemoveRows(); emit countChanged(); emit favoritesChanged(); } } void SimpleFavoritesModel::moveRow(int from, int to) { if (from >= m_favorites.count() || to >= m_favorites.count()) { return; } if (from == to) { return; } setDropPlaceholderIndex(-1); int modelTo = to + (to > from ? 1 : 0); bool ok = beginMoveRows(QModelIndex(), from, from, QModelIndex(), modelTo); if (ok) { m_entryList.move(from, to); m_favorites.move(from, to); endMoveRows(); emit favoritesChanged(); } } int SimpleFavoritesModel::dropPlaceholderIndex() const { return m_dropPlaceholderIndex; } void SimpleFavoritesModel::setDropPlaceholderIndex(int index) { if (index == -1 && m_dropPlaceholderIndex != -1) { beginRemoveRows(QModelIndex(), m_dropPlaceholderIndex, m_dropPlaceholderIndex); m_dropPlaceholderIndex = index; endRemoveRows(); emit countChanged(); } else if (index != -1 && m_dropPlaceholderIndex == -1) { beginInsertRows(QModelIndex(), index, index); m_dropPlaceholderIndex = index; endInsertRows(); emit countChanged(); } else if (m_dropPlaceholderIndex != index) { int modelTo = index + (index > m_dropPlaceholderIndex ? 1 : 0); bool ok = beginMoveRows(QModelIndex(), m_dropPlaceholderIndex, m_dropPlaceholderIndex, QModelIndex(), modelTo); if (ok) { m_dropPlaceholderIndex = index; endMoveRows(); } } } AbstractModel *SimpleFavoritesModel::favoritesModel() { return this; } void SimpleFavoritesModel::refresh() { beginResetModel(); setDropPlaceholderIndex(-1); int oldCount = m_entryList.count(); qDeleteAll(m_entryList); m_entryList.clear(); QStringList newFavorites; foreach(const QString &id, m_favorites) { AbstractEntry *entry = favoriteFromId(id); if (entry && entry->isValid()) { m_entryList << entry; newFavorites << entry->id(); if (m_maxFavorites != -1 && newFavorites.count() == m_maxFavorites) { break; } } else if (entry) { delete entry; } } m_favorites = newFavorites; endResetModel(); if (oldCount != m_entryList.count()) { emit countChanged(); } emit favoritesChanged(); } AbstractEntry *SimpleFavoritesModel::favoriteFromId(const QString &id) { const QUrl url(id); const QString &s = url.scheme(); - if ((s.isEmpty() && id.contains(QStringLiteral(".desktop"))) || s == QStringLiteral("preferred")) { + if ((s.isEmpty() && id.contains(QLatin1String(".desktop"))) || s == QLatin1String("preferred")) { return new AppEntry(this, id); - } else if (s == QStringLiteral("ktp")) { + } else if (s == QLatin1String("ktp")) { return new ContactEntry(this, id); } else if (url.isValid() && !url.scheme().isEmpty()) { return new FileEntry(this, url); } else { return new SystemEntry(this, id); } return nullptr; } diff --git a/applets/kimpanel/plugin/kimpanelplugin.cpp b/applets/kimpanel/plugin/kimpanelplugin.cpp index c3f686250..2ea092b90 100644 --- a/applets/kimpanel/plugin/kimpanelplugin.cpp +++ b/applets/kimpanel/plugin/kimpanelplugin.cpp @@ -1,30 +1,30 @@ /* * Copyright 2014 Weng Xuetian * * 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 "kimpanelplugin.h" #include "screen.h" #include void KimpanelPlugin::registerTypes(const char* uri) { Q_UNUSED(uri); - Q_ASSERT(QLatin1String(uri) == QStringLiteral("org.kde.plasma.private.kimpanel")); + Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.plasma.private.kimpanel")); qmlRegisterType(uri, 0, 1, "Screen"); } diff --git a/applets/taskmanager/plugin/backend.cpp b/applets/taskmanager/plugin/backend.cpp index db1b11b60..d8cc4eafa 100644 --- a/applets/taskmanager/plugin/backend.cpp +++ b/applets/taskmanager/plugin/backend.cpp @@ -1,588 +1,588 @@ /*************************************************************************** * Copyright (C) 2012-2016 by Eike Hein * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "backend.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KAStats = KActivities::Stats; using namespace KAStats; using namespace KAStats::Terms; Backend::Backend(QObject* parent) : QObject(parent) , m_panelWinId(0) , m_highlightWindows(false) , m_actionGroup(new QActionGroup(this)) { } Backend::~Backend() { } QQuickItem *Backend::taskManagerItem() const { return m_taskManagerItem; } void Backend::setTaskManagerItem(QQuickItem* item) { if (item != m_taskManagerItem) { m_taskManagerItem = item; emit taskManagerItemChanged(); } } QQuickItem *Backend::toolTipItem() const { return m_toolTipItem; } void Backend::setToolTipItem(QQuickItem *item) { if (item != m_toolTipItem) { m_toolTipItem = item; connect(item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(toolTipWindowChanged(QQuickWindow*))); emit toolTipItemChanged(); } } QQuickWindow *Backend::groupDialog() const { return m_groupDialog; } void Backend::setGroupDialog(QQuickWindow *dialog) { if (dialog != m_groupDialog) { m_groupDialog = dialog; emit groupDialogChanged(); } } bool Backend::highlightWindows() const { return m_highlightWindows; } void Backend::setHighlightWindows(bool highlight) { if (highlight != m_highlightWindows) { m_highlightWindows = highlight; updateWindowHighlight(); emit highlightWindowsChanged(); } } QUrl Backend::tryDecodeApplicationsUrl(const QUrl &launcherUrl) { - if (launcherUrl.isValid() && launcherUrl.scheme() == QStringLiteral("applications")) { + if (launcherUrl.isValid() && launcherUrl.scheme() == QLatin1String("applications")) { const KService::Ptr service = KService::serviceByMenuId(launcherUrl.path()); if (service) { return QUrl::fromLocalFile(service->entryPath()); } } return launcherUrl; } QVariantList Backend::jumpListActions(const QUrl &launcherUrl, QObject *parent) { if (!parent) { return QVariantList(); } QUrl desktopEntryUrl = tryDecodeApplicationsUrl(launcherUrl); if (!desktopEntryUrl.isValid() || !desktopEntryUrl.isLocalFile() || !KDesktopFile::isDesktopFile(desktopEntryUrl.toLocalFile())) { return QVariantList(); } QVariantList actions; KDesktopFile desktopFile(desktopEntryUrl.toLocalFile()); const QStringList &jumpListActions = desktopFile.readActions(); const QLatin1String kde("KDE"); foreach (const QString &actionName, jumpListActions) { const KConfigGroup &actionGroup = desktopFile.actionGroup(actionName); if (!actionGroup.isValid() || !actionGroup.exists()) { continue; } const QStringList ¬ShowIn = actionGroup.readXdgListEntry(QStringLiteral("NotShowIn")); if (notShowIn.contains(kde)) { continue; } const QStringList &onlyShowIn = actionGroup.readXdgListEntry(QStringLiteral("OnlyShowIn")); if (!onlyShowIn.isEmpty() && !onlyShowIn.contains(kde)) { continue; } const QString &name = actionGroup.readEntry(QStringLiteral("Name")); const QString &exec = actionGroup.readEntry(QStringLiteral("Exec")); if (name.isEmpty() || exec.isEmpty()) { continue; } QAction *action = new QAction(parent); action->setText(name); action->setIcon(QIcon::fromTheme(actionGroup.readEntry("Icon"))); action->setProperty("exec", exec); // so we can show the proper application name and icon when it launches action->setProperty("applicationName", desktopFile.readName()); action->setProperty("applicationIcon", desktopFile.readIcon()); connect(action, &QAction::triggered, this, &Backend::handleJumpListAction); actions << QVariant::fromValue(action); } return actions; } QVariantList Backend::placesActions(const QUrl &launcherUrl, bool showAllPlaces, QObject *parent) { if (!parent) { return QVariantList(); } QUrl desktopEntryUrl = tryDecodeApplicationsUrl(launcherUrl); if (!desktopEntryUrl.isValid() || !desktopEntryUrl.isLocalFile() || !KDesktopFile::isDesktopFile(desktopEntryUrl.toLocalFile())) { return QVariantList(); } QVariantList actions; KDesktopFile desktopFile(desktopEntryUrl.toLocalFile()); // Since we can't have dynamic jump list actions, at least add the user's "Places" for file managers. const QStringList &categories = desktopFile.desktopGroup().readXdgListEntry(QStringLiteral("Categories")); if (!categories.contains(QLatin1String("FileManager"))) { return actions; } QString previousGroup; QMenu *subMenu = nullptr; QScopedPointer placesModel(new KFilePlacesModel()); for (int i = 0; i < placesModel->rowCount(); ++i) { QModelIndex idx = placesModel->index(i, 0); if (placesModel->isHidden(idx)) { continue; } const QString &title = idx.data(Qt::DisplayRole).toString(); const QIcon &icon = idx.data(Qt::DecorationRole).value(); const QUrl &url = idx.data(KFilePlacesModel::UrlRole).toUrl(); QAction *placeAction = new QAction(icon, title, parent); connect(placeAction, &QAction::triggered, this, [url, desktopEntryUrl] { KService::Ptr service = KService::serviceByDesktopPath(desktopEntryUrl.toLocalFile()); if (!service) { return; } KRun::runService(*service, {url}, QApplication::activeWindow()); }); const QString &groupName = idx.data(KFilePlacesModel::GroupRole).toString(); if (previousGroup.isEmpty()) { // Skip first group heading. previousGroup = groupName; } // Put all subsequent categories into a submenu. if (previousGroup != groupName) { QAction *subMenuAction = new QAction(groupName, parent); subMenu = new QMenu(); // Cannot parent a QMenu to a QAction, need to delete it manually. connect(parent, &QObject::destroyed, subMenu, &QObject::deleteLater); subMenuAction->setMenu(subMenu); actions << QVariant::fromValue(subMenuAction); previousGroup = groupName; } if (subMenu) { subMenu->addAction(placeAction); } else { actions << QVariant::fromValue(placeAction); } } // There is nothing more frustrating than having a "More" entry that ends up showing just one or two // additional entries. Therefore we truncate to max. 5 entries only if there are more than 7 in total. if (!showAllPlaces && actions.count() > 7) { const int totalActionCount = actions.count(); while (actions.count() > 5) { actions.removeLast(); } QAction *action = new QAction(parent); action->setText(i18ncp("Show all user Places", "%1 more Place", "%1 more Places", totalActionCount - actions.count())); connect(action, &QAction::triggered, this, &Backend::showAllPlaces); actions << QVariant::fromValue(action); } return actions; } QVariantList Backend::recentDocumentActions(const QUrl &launcherUrl, QObject *parent) { if (!parent) { return QVariantList(); } QUrl desktopEntryUrl = tryDecodeApplicationsUrl(launcherUrl); if (!desktopEntryUrl.isValid() || !desktopEntryUrl.isLocalFile() || !KDesktopFile::isDesktopFile(desktopEntryUrl.toLocalFile())) { return QVariantList(); } QVariantList actions; QString desktopName = desktopEntryUrl.fileName(); QString storageId = desktopName; if (storageId.endsWith(QLatin1String(".desktop"))) { storageId = storageId.left(storageId.length() - 8); } auto query = UsedResources | RecentlyUsedFirst | Agent(storageId) | Type::any() | Activity::current() | Url::file(); ResultSet results(query); ResultSet::const_iterator resultIt = results.begin(); int actionCount = 0; while (actionCount < 5 && resultIt != results.end()) { const QString resource = (*resultIt).resource(); ++resultIt; const QUrl url(resource); if (!url.isValid()) { continue; } const KFileItem fileItem(url); if (!fileItem.isFile()) { continue; } QAction *action = new QAction(parent); action->setText(url.fileName()); action->setIcon(QIcon::fromTheme(fileItem.iconName(), QIcon::fromTheme(QStringLiteral("unknown")))); action->setProperty("agent", storageId); action->setProperty("entryPath", desktopEntryUrl); action->setData(resource); connect(action, &QAction::triggered, this, &Backend::handleRecentDocumentAction); actions << QVariant::fromValue(action); ++actionCount; } if (actionCount > 0) { QAction *action = new QAction(parent); action->setText(i18n("Forget Recent Documents")); action->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear-history"))); action->setProperty("agent", storageId); connect(action, &QAction::triggered, this, &Backend::handleRecentDocumentAction); actions << QVariant::fromValue(action); } return actions; } void Backend::toolTipWindowChanged(QQuickWindow *window) { Q_UNUSED(window) updateWindowHighlight(); } void Backend::handleJumpListAction() const { const QAction *action = qobject_cast(sender()); if (!action) { return; } KRun::run(action->property("exec").toString(), {}, nullptr, action->property("applicationName").toString(), action->property("applicationIcon").toString()); } void Backend::handleRecentDocumentAction() const { const QAction *action = qobject_cast(sender()); if (!action) { return; } const QString agent = action->property("agent").toString(); if (agent.isEmpty()) { return; } const QString desktopPath = action->property("entryPath").toUrl().toLocalFile(); const QString resource = action->data().toString(); if (desktopPath.isEmpty() || resource.isEmpty()) { auto query = UsedResources | Agent(agent) | Type::any() | Activity::current() | Url::file(); KAStats::forgetResources(query); return; } KService::Ptr service = KService::serviceByDesktopPath(desktopPath); qDebug() << service; if (!service) { return; } KRun::runService(*service, QList() << QUrl(resource), QApplication::activeWindow()); } void Backend::setActionGroup(QAction *action) const { if (action) { action->setActionGroup(m_actionGroup); } } QRect Backend::globalRect(QQuickItem *item) const { if (!item || !item->window()) { return QRect(); } QRect iconRect(item->x(), item->y(), item->width(), item->height()); iconRect.moveTopLeft(item->parentItem()->mapToScene(iconRect.topLeft()).toPoint()); iconRect.moveTopLeft(item->window()->mapToGlobal(iconRect.topLeft())); return iconRect; } void Backend::ungrabMouse(QQuickItem *item) const { //this is a workaround where Qt will fail to realize a mouse has been released // this happens if a window which does not accept focus spawns a new window that takes focus and X grab // whilst the mouse is depressed // https://bugreports.qt.io/browse/QTBUG-59044 // this causes the next click to go missing //by releasing manually we avoid that situation auto ungrabMouseHack = [item]() { if (item && item->window() && item->window()->mouseGrabberItem()) { item->window()->mouseGrabberItem()->ungrabMouse(); } }; //pre 5.8.0 QQuickWindow code is "item->grabMouse(); sendEvent(item, mouseEvent)" //post 5.8.0 QQuickWindow code is sendEvent(item, mouseEvent); item->grabMouse() if (QVersionNumber::fromString(QString::fromLatin1(qVersion())) > QVersionNumber(5, 8, 0)) { QTimer::singleShot(0, item, ungrabMouseHack); } else { ungrabMouseHack(); } //end workaround } bool Backend::canPresentWindows() const { return (KWindowSystem::compositingActive() && KWindowEffects::isEffectAvailable(KWindowEffects::PresentWindowsGroup)); } void Backend::presentWindows(const QVariant &_winIds) { if (!m_taskManagerItem || !m_taskManagerItem->window()) { return; } QList winIds; const QVariantList &_winIdsList = _winIds.toList(); foreach(const QVariant &_winId, _winIdsList) { bool ok = false; qlonglong winId = _winId.toLongLong(&ok); if (ok) { winIds.append(winId); } } if (winIds.isEmpty()) { return; } if (m_windowsToHighlight.count()) { m_windowsToHighlight.clear(); updateWindowHighlight(); } KWindowEffects::presentWindows(m_taskManagerItem->window()->winId(), winIds); } bool Backend::isApplication(const QUrl &url) const { if (!url.isValid() || !url.isLocalFile()) { return false; } const QString &localPath = url.toLocalFile(); if (!KDesktopFile::isDesktopFile(localPath)) { return false; } KDesktopFile desktopFile(localPath); return desktopFile.hasApplicationType(); } QList Backend::jsonArrayToUrlList(const QJsonArray &array) const { QList urls; urls.reserve(array.count()); for (auto it = array.constBegin(), end = array.constEnd(); it != end; ++it) { urls << QUrl(it->toString()); } return urls; } void Backend::cancelHighlightWindows() { m_windowsToHighlight.clear(); updateWindowHighlight(); } void Backend::windowsHovered(const QVariant &_winIds, bool hovered) { m_windowsToHighlight.clear(); if (hovered) { const QVariantList &winIds = _winIds.toList(); foreach(const QVariant &_winId, winIds) { bool ok = false; qlonglong winId = _winId.toLongLong(&ok); if (ok) { m_windowsToHighlight.append(winId); } } } updateWindowHighlight(); } void Backend::updateWindowHighlight() { if (!m_highlightWindows) { if (m_panelWinId) { KWindowEffects::highlightWindows(m_panelWinId, QList()); m_panelWinId = 0; } return; } if (m_taskManagerItem && m_taskManagerItem->window()) { m_panelWinId = m_taskManagerItem->window()->winId(); } else { return; } QList windows = m_windowsToHighlight; if (!windows.isEmpty() && m_toolTipItem && m_toolTipItem->window()) { windows.append(m_toolTipItem->window()->winId()); } if (!windows.isEmpty() && m_groupDialog) { windows.append(m_groupDialog->winId()); } KWindowEffects::highlightWindows(m_panelWinId, windows); } diff --git a/applets/taskmanager/plugin/smartlaunchers/smartlauncheritem.cpp b/applets/taskmanager/plugin/smartlaunchers/smartlauncheritem.cpp index fdd1197e8..a4d747eca 100644 --- a/applets/taskmanager/plugin/smartlaunchers/smartlauncheritem.cpp +++ b/applets/taskmanager/plugin/smartlaunchers/smartlauncheritem.cpp @@ -1,228 +1,228 @@ /*************************************************************************** * Copyright (C) 2016, 2019 Kai Uwe Broulik * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "smartlauncheritem.h" #include #include using namespace SmartLauncher; Item::Item(QObject *parent) : QObject(parent) { m_backendPtr = s_backend.toStrongRef(); if (!m_backendPtr) { QSharedPointer backendSharedPtr(new Backend); s_backend = backendSharedPtr; m_backendPtr = s_backend.toStrongRef(); } } QWeakPointer Item::s_backend; void Item::init() { if (m_inited || m_storageId.isEmpty() || !m_backendPtr) { return; } connect(m_backendPtr.data(), &Backend::reloadRequested, this, [this](const QString &uri) { if (uri.isEmpty() || m_storageId == uri) { populate(); } }); connect(m_backendPtr.data(), &Backend::launcherRemoved, this, [this](const QString &uri) { if (uri.isEmpty() || m_storageId == uri) { clear(); } }); connect(m_backendPtr.data(), &Backend::countChanged, this, [this](const QString &uri, int count) { if (uri.isEmpty() || m_storageId == uri) { setCount(count); } }); connect(m_backendPtr.data(), &Backend::countVisibleChanged, this, [this](const QString &uri, bool countVisible) { if (uri.isEmpty() || m_storageId == uri) { setCountVisible(countVisible); } }); connect(m_backendPtr.data(), &Backend::progressChanged, this, [this](const QString &uri, int progress) { if (uri.isEmpty() || m_storageId == uri) { setProgress(progress); } }); connect(m_backendPtr.data(), &Backend::progressVisibleChanged, this, [this](const QString &uri, bool progressVisible) { if (uri.isEmpty() || m_storageId == uri) { setProgressVisible(progressVisible); } }); connect(m_backendPtr.data(), &Backend::urgentChanged, this, [this](const QString &uri, bool urgent) { if (uri.isEmpty() || m_storageId == uri) { setUrgent(urgent); } }); m_inited = true; } void Item::populate() { if (!m_backendPtr || m_storageId.isEmpty()) { return; } if (!m_backendPtr->hasLauncher(m_storageId)) { return; } setCount(m_backendPtr->count(m_storageId)); setCountVisible(m_backendPtr->countVisible(m_storageId)); setProgress(m_backendPtr->progress(m_storageId)); setProgressVisible(m_backendPtr->progressVisible(m_storageId)); setUrgent(m_backendPtr->urgent(m_storageId)); } void Item::clear() { setCount(0); setCountVisible(false); setProgress(0); setProgressVisible(false); setUrgent(false); } QUrl Item::launcherUrl() const { return m_launcherUrl; } void Item::setLauncherUrl(const QUrl &launcherUrl) { if (launcherUrl != m_launcherUrl) { m_launcherUrl = launcherUrl; emit launcherUrlChanged(launcherUrl); m_storageId.clear(); clear(); - if (launcherUrl.scheme() == QStringLiteral("applications")) { + if (launcherUrl.scheme() == QLatin1String("applications")) { const KService::Ptr service = KService::serviceByMenuId(launcherUrl.path()); if (service && launcherUrl.path() == service->menuId()) { m_storageId = service->menuId(); } } if (launcherUrl.isLocalFile() && KDesktopFile::isDesktopFile(launcherUrl.toLocalFile())) { KDesktopFile f(launcherUrl.toLocalFile()); const KService::Ptr service = KService::serviceByStorageId(f.fileName()); if (service) { m_storageId = service->storageId(); } } if (m_storageId.isEmpty()) { return; } if (m_backendPtr) { // check if we have a mapping to a different desktop file const QString &overrideStorageId = m_backendPtr->unityMappingRules().value(m_storageId); if (!overrideStorageId.isEmpty()) { m_storageId = overrideStorageId; } } init(); populate(); } } int Item::count() const { return m_count; } void Item::setCount(int count) { if (m_count != count) { m_count = count; emit countChanged(count); } } bool Item::countVisible() const { return m_countVisible; } void Item::setCountVisible(bool countVisible) { if (m_countVisible != countVisible) { m_countVisible = countVisible; emit countVisibleChanged(countVisible); } } int Item::progress() const { return m_progress; } void Item::setProgress(int progress) { if (m_progress != progress) { m_progress = progress; emit progressChanged(progress); } } bool Item::progressVisible() const { return m_progressVisible; } void Item::setProgressVisible(bool progressVisible) { if (m_progressVisible != progressVisible) { m_progressVisible = progressVisible; emit progressVisibleChanged(progressVisible); } } bool Item::urgent() const { return m_urgent; } void Item::setUrgent(bool urgent) { if (m_urgent != urgent) { m_urgent = urgent; emit urgentChanged(urgent); } } diff --git a/containments/desktop/plugins/folder/foldermodel.cpp b/containments/desktop/plugins/folder/foldermodel.cpp index 50bf23d9f..9acc59357 100644 --- a/containments/desktop/plugins/folder/foldermodel.cpp +++ b/containments/desktop/plugins/folder/foldermodel.cpp @@ -1,2107 +1,2107 @@ /*************************************************************************** * Copyright (C) 2006 David Faure * * Copyright (C) 2008 Fredrik Höglund * * Copyright (C) 2008 Rafael Fernández López * * Copyright (C) 2011 Marco Martin * * Copyright (C) 2014 by Eike Hein * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "foldermodel.h" #include "itemviewadapter.h" #include "positioner.h" #include "screenmapper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_LOGGING_CATEGORY(FOLDERMODEL, "plasma.containments.desktop.folder.foldermodel") DirLister::DirLister(QObject *parent) : KDirLister(parent) { } DirLister:: ~DirLister() { } void DirLister::handleError(KIO::Job *job) { if (!autoErrorHandlingEnabled()) { emit error(job->errorString()); return; } KDirLister::handleError(job); } FolderModel::FolderModel(QObject *parent) : QSortFilterProxyModel(parent), m_dirWatch(nullptr), m_dragInProgress(false), m_urlChangedWhileDragging(false), m_dropTargetPositionsCleanup(new QTimer(this)), m_previewGenerator(nullptr), m_viewAdapter(nullptr), m_actionCollection(this), m_newMenu(nullptr), m_fileItemActions(nullptr), m_usedByContainment(false), m_locked(true), m_sortMode(0), m_sortDesc(false), m_sortDirsFirst(true), m_parseDesktopFiles(false), m_previews(false), m_filterMode(NoFilter), m_filterPatternMatchAll(true), m_screenMapper(ScreenMapper::instance()), m_complete(false), m_screenUsed(false) { //needed to pass the job around with qml qmlRegisterType(); DirLister *dirLister = new DirLister(this); dirLister->setDelayedMimeTypes(true); dirLister->setAutoErrorHandlingEnabled(false, nullptr); connect(dirLister, &DirLister::error, this, &FolderModel::dirListFailed); connect(dirLister, &KCoreDirLister::itemsDeleted, this, &FolderModel::evictFromIsDirCache); connect(dirLister, &KCoreDirLister::started, this, std::bind(&FolderModel::setStatus, this, Status::Listing)); void (KCoreDirLister::*myCompletedSignal)() = &KCoreDirLister::completed; QObject::connect(dirLister, myCompletedSignal, this, [this] { setStatus(Status::Ready); emit listingCompleted(); }); void (KCoreDirLister::*myCanceledSignal)() = &KCoreDirLister::canceled; QObject::connect(dirLister, myCanceledSignal, this, [this] { setStatus(Status::Canceled); emit listingCanceled(); }); m_dirModel = new KDirModel(this); m_dirModel->setDirLister(dirLister); m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory | KDirModel::DropOnLocalExecutable); // If we have dropped items queued for moving, go unsorted now. connect(this, &QAbstractItemModel::rowsAboutToBeInserted, this, [this]() { if (!m_dropTargetPositions.isEmpty()) { setSortMode(-1); } }); // Position dropped items at the desired target position. connect(this, &QAbstractItemModel::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) { for (int i = first; i <= last; ++i) { const auto idx = index(i, 0, parent); const auto url = itemForIndex(idx).url(); auto it = m_dropTargetPositions.find(url.fileName()); if (it != m_dropTargetPositions.end()) { const auto pos = it.value(); m_dropTargetPositions.erase(it); emit move(pos.x(), pos.y(), {url}); } } }); /* * Dropped files may not actually show up as new files, e.g. when we overwrite * an existing file. Or files that fail to be listed by the dirLister, or... * To ensure we don't grow the map indefinitely, clean it up periodically. * The cleanup timer is (re)started whenever we modify the map. We use a quite * high interval of 10s. This should ensure, that we don't accidentally wipe * the mapping when we actually still want to use it. Since the time between * adding an entry in the map and it showing up in the model should be * small, this should rarely, if ever happen. */ m_dropTargetPositionsCleanup->setInterval(10000); m_dropTargetPositionsCleanup->setSingleShot(true); connect(m_dropTargetPositionsCleanup, &QTimer::timeout, this, [this]() { if (!m_dropTargetPositions.isEmpty()) { qCDebug(FOLDERMODEL) << "clearing drop target positions after timeout:" << m_dropTargetPositions; m_dropTargetPositions.clear(); } }); m_selectionModel = new QItemSelectionModel(this, this); connect(m_selectionModel, &QItemSelectionModel::selectionChanged, this, &FolderModel::selectionChanged); setSourceModel(m_dirModel); setSortLocaleAware(true); setFilterCaseSensitivity(Qt::CaseInsensitive); setDynamicSortFilter(true); sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder); createActions(); } FolderModel::~FolderModel() { if (m_usedByContainment) { // disconnect so we don't handle signals from the screen mapper when // removeScreen is called m_screenMapper->disconnect(this); m_screenMapper->removeScreen(m_screen, resolvedUrl()); } } QHash< int, QByteArray > FolderModel::roleNames() const { return staticRoleNames(); } QHash< int, QByteArray > FolderModel::staticRoleNames() { QHash roleNames; roleNames[Qt::DisplayRole] = "display"; roleNames[Qt::DecorationRole] = "decoration"; roleNames[BlankRole] = "blank"; roleNames[OverlaysRole] = "overlays"; roleNames[SelectedRole] = "selected"; roleNames[IsDirRole] = "isDir"; roleNames[IsLinkRole] = "isLink"; roleNames[IsHiddenRole] = "isHidden"; roleNames[UrlRole] = "url"; roleNames[LinkDestinationUrl] = "linkDestinationUrl"; roleNames[SizeRole] = "size"; roleNames[TypeRole] = "type"; return roleNames; } void FolderModel::classBegin() { } void FolderModel::componentComplete() { m_complete = true; invalidate(); } void FolderModel::invalidateIfComplete() { if (!m_complete) { return; } invalidate(); } void FolderModel::invalidateFilterIfComplete() { if (!m_complete) { return; } invalidateFilter(); } void FolderModel::newFileMenuItemCreated(const QUrl &url) { if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { m_screenMapper->addMapping(url, m_screen, ScreenMapper::DelayedSignal); m_dropTargetPositions.insert(url.fileName(), m_menuPosition); m_menuPosition = {}; m_dropTargetPositionsCleanup->start(); } } QString FolderModel::url() const { return m_url; } void FolderModel::setUrl(const QString& url) { const QUrl &resolvedNewUrl = resolve(url); if (url == m_url) { m_dirModel->dirLister()->updateDirectory(resolvedNewUrl); return; } const auto oldUrl = resolvedUrl(); beginResetModel(); m_url = url; m_isDirCache.clear(); m_dirModel->dirLister()->openUrl(resolvedNewUrl); clearDragImages(); m_dragIndexes.clear(); endResetModel(); emit urlChanged(); emit resolvedUrlChanged(); m_errorString.clear(); emit errorStringChanged(); if (m_dirWatch) { delete m_dirWatch; m_dirWatch = nullptr; } if (resolvedNewUrl.isValid()) { m_dirWatch = new KDirWatch(this); connect(m_dirWatch, &KDirWatch::created, this, &FolderModel::iconNameChanged); connect(m_dirWatch, &KDirWatch::dirty, this, &FolderModel::iconNameChanged); m_dirWatch->addFile(resolvedNewUrl.toLocalFile() + QLatin1String("/.directory")); } if (m_dragInProgress) { m_urlChangedWhileDragging = true; } emit iconNameChanged(); if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { m_screenMapper->removeScreen(m_screen, oldUrl); m_screenMapper->addScreen(m_screen, resolvedUrl()); } } QUrl FolderModel::resolvedUrl() const { return m_dirModel->dirLister()->url(); } QUrl FolderModel::resolve(const QString& url) { QUrl resolvedUrl; if (url.startsWith(QLatin1Char('~'))) { resolvedUrl = QUrl::fromLocalFile(KShell::tildeExpand(url)); } else { resolvedUrl = QUrl::fromUserInput(url); } return resolvedUrl; } QString FolderModel::iconName() const { const KFileItem rootItem(m_dirModel->dirLister()->url()); if (!rootItem.isFinalIconKnown()) { rootItem.determineMimeType(); } return rootItem.iconName(); } FolderModel::Status FolderModel::status() const { return m_status; } void FolderModel::setStatus(Status status) { if (m_status != status) { m_status = status; emit statusChanged(); } } QString FolderModel::errorString() const { return m_errorString; } bool FolderModel::dragging() const { return m_dragInProgress; } bool FolderModel::usedByContainment() const { return m_usedByContainment; } void FolderModel::setUsedByContainment(bool used) { if (m_usedByContainment != used) { m_usedByContainment = used; QAction *action = m_actionCollection.action(QStringLiteral("refresh")); if (action) { action->setText(m_usedByContainment ? i18n("&Refresh Desktop") : i18n("&Refresh View")); action->setIcon(m_usedByContainment ? QIcon::fromTheme(QStringLiteral("user-desktop")) : QIcon::fromTheme(QStringLiteral("view-refresh"))); } m_screenMapper->disconnect(this); connect(m_screenMapper, &ScreenMapper::screensChanged, this, &FolderModel::invalidateFilterIfComplete); connect(m_screenMapper, &ScreenMapper::screenMappingChanged, this, &FolderModel::invalidateFilterIfComplete); emit usedByContainmentChanged(); } } bool FolderModel::locked() const { return m_locked; } void FolderModel::setLocked(bool locked) { if (m_locked != locked) { m_locked = locked; emit lockedChanged(); } } void FolderModel::dirListFailed(const QString& error) { m_errorString = error; emit errorStringChanged(); } int FolderModel::sortMode() const { return m_sortMode; } void FolderModel::setSortMode(int mode) { if (m_sortMode != mode) { m_sortMode = mode; if (mode == -1 /* Unsorted */) { setDynamicSortFilter(false); } else { invalidateIfComplete(); sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder); setDynamicSortFilter(true); } emit sortModeChanged(); } } bool FolderModel::sortDesc() const { return m_sortDesc; } void FolderModel::setSortDesc(bool desc) { if (m_sortDesc != desc) { m_sortDesc = desc; if (m_sortMode != -1 /* Unsorted */) { invalidateIfComplete(); sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder); } emit sortDescChanged(); } } bool FolderModel::sortDirsFirst() const { return m_sortDirsFirst; } void FolderModel::setSortDirsFirst(bool enable) { if (m_sortDirsFirst != enable) { m_sortDirsFirst = enable; if (m_sortMode != -1 /* Unsorted */) { invalidateIfComplete(); sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder); } emit sortDirsFirstChanged(); } } bool FolderModel::parseDesktopFiles() const { return m_parseDesktopFiles; } void FolderModel::setParseDesktopFiles(bool enable) { if (m_parseDesktopFiles != enable) { m_parseDesktopFiles = enable; emit parseDesktopFilesChanged(); } } QObject* FolderModel::viewAdapter() const { return m_viewAdapter; } void FolderModel::setViewAdapter(QObject* adapter) { if (m_viewAdapter != adapter) { KAbstractViewAdapter *abstractViewAdapter = dynamic_cast(adapter); m_viewAdapter = abstractViewAdapter; if (m_viewAdapter && !m_previewGenerator) { m_previewGenerator = new KFilePreviewGenerator(abstractViewAdapter, this); m_previewGenerator->setPreviewShown(m_previews); m_previewGenerator->setEnabledPlugins(m_effectivePreviewPlugins); } emit viewAdapterChanged(); } } bool FolderModel::previews() const { return m_previews; } void FolderModel::setPreviews(bool previews) { if (m_previews != previews) { m_previews = previews; if (m_previewGenerator) { m_previewGenerator->setPreviewShown(m_previews); } emit previewsChanged(); } } QStringList FolderModel::previewPlugins() const { return m_previewPlugins; } void FolderModel::setPreviewPlugins(const QStringList& previewPlugins) { QStringList effectivePlugins = previewPlugins; if (effectivePlugins.isEmpty()) { effectivePlugins = KIO::PreviewJob::defaultPlugins(); } if (m_effectivePreviewPlugins != effectivePlugins) { m_effectivePreviewPlugins = effectivePlugins; if (m_previewGenerator) { m_previewGenerator->setPreviewShown(false); m_previewGenerator->setEnabledPlugins(m_effectivePreviewPlugins); m_previewGenerator->setPreviewShown(true); } } if (m_previewPlugins != previewPlugins) { m_previewPlugins = previewPlugins; emit previewPluginsChanged(); } } int FolderModel::filterMode() const { return m_filterMode; } void FolderModel::setFilterMode(int filterMode) { if (m_filterMode != (FilterMode)filterMode) { m_filterMode = (FilterMode)filterMode; invalidateFilterIfComplete(); emit filterModeChanged(); } } QString FolderModel::filterPattern() const { return m_filterPattern; } void FolderModel::setFilterPattern(const QString &pattern) { if (m_filterPattern == pattern) { return; } m_filterPattern = pattern; m_filterPatternMatchAll = (pattern == QLatin1String("*")); const QStringList patterns = pattern.split(QLatin1Char(' ')); m_regExps.clear(); m_regExps.reserve(patterns.count()); foreach (const QString &pattern, patterns) { QRegExp rx(pattern); rx.setPatternSyntax(QRegExp::Wildcard); rx.setCaseSensitivity(Qt::CaseInsensitive); m_regExps.append(rx); } invalidateFilterIfComplete(); emit filterPatternChanged(); } QStringList FolderModel::filterMimeTypes() const { return m_mimeSet.toList(); } void FolderModel::setFilterMimeTypes(const QStringList &mimeList) { const QSet &set = QSet::fromList(mimeList); if (m_mimeSet != set) { m_mimeSet = set; invalidateFilterIfComplete(); emit filterMimeTypesChanged(); } } void FolderModel::setScreen(int screen) { m_screenUsed = (screen != -1); if (!m_screenUsed || m_screen == screen) return; m_screen = screen; if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { m_screenMapper->addScreen(screen, resolvedUrl()); } emit screenChanged(); } bool FolderModel::eventFilter(QObject *watched, QEvent *event) { Q_UNUSED(watched) // Catching Shift modifier usage on open context menus to swap the // Trash/Delete actions. if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Shift) { m_actionCollection.action(QStringLiteral("trash"))->setVisible(false); m_actionCollection.action(QStringLiteral("del"))->setVisible(true); } } else if (event->type() == QEvent::KeyRelease) { QKeyEvent *keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Shift) { m_actionCollection.action(QStringLiteral("trash"))->setVisible(true); m_actionCollection.action(QStringLiteral("del"))->setVisible(false); } } return false; } KFileItem FolderModel::rootItem() const { return m_dirModel->dirLister()->rootItem(); } void FolderModel::up() { const QUrl &up = KIO::upUrl(resolvedUrl()); if (up.isValid()) { setUrl(up.toString()); } } void FolderModel::cd(int row) { if (row < 0) { return; } const QModelIndex idx = index(row, 0); bool isDir = data(idx, IsDirRole).toBool(); if (isDir) { const KFileItem item = itemForIndex(idx); if (m_parseDesktopFiles && item.isDesktopFile()) { const KDesktopFile file(item.targetUrl().path()); if (file.hasLinkType()) { setUrl(file.readUrl()); } } else { setUrl(item.targetUrl().toString()); } } } void FolderModel::run(int row) { if (row < 0) { return; } KFileItem item = itemForIndex(index(row, 0)); QUrl url(item.targetUrl()); // FIXME TODO: This can go once we depend on a KIO w/ fe1f50caaf2. if (url.scheme().isEmpty()) { url.setScheme(QStringLiteral("file")); } KRun *run = new KRun(url, nullptr); // On desktop:/ we want to be able to run .desktop files right away, // otherwise ask for security reasons. We also don't use the targetUrl() // from above since we don't want the resolved /home/foo/Desktop URL. run->setShowScriptExecutionPrompt(item.url().scheme() != QLatin1String("desktop") || item.url().adjusted(QUrl::RemoveFilename).path() != QLatin1String("/")); } void FolderModel::runSelected() { if (!m_selectionModel->hasSelection()) { return; } if (m_selectionModel->selectedIndexes().count() == 1) { run(m_selectionModel->selectedIndexes().constFirst().row()); return; } KFileItemActions fileItemActions(this); KFileItemList items; foreach (const QModelIndex &index, m_selectionModel->selectedIndexes()) { // Skip over directories. if (!index.data(IsDirRole).toBool()) { items << itemForIndex(index); } } fileItemActions.runPreferredApplications(items, QString()); } void FolderModel::rename(int row, const QString& name) { if (row < 0) { return; } QModelIndex idx = index(row, 0); m_dirModel->setData(mapToSource(idx), name, Qt::EditRole); } int FolderModel::fileExtensionBoundary(int row) { const QModelIndex idx = index(row, 0); const QString &name = data(idx, Qt::DisplayRole).toString(); int boundary = name.length(); if (data(idx, IsDirRole).toBool()) { return boundary; } QMimeDatabase db; const QString &ext = db.suffixForFileName(name); if (ext.isEmpty()) { boundary = name.lastIndexOf(QLatin1Char('.')); if (boundary < 1) { boundary = name.length(); } } else { boundary -= ext.length() + 1; } return boundary; } bool FolderModel::hasSelection() const { return m_selectionModel->hasSelection(); } bool FolderModel::isSelected(int row) { if (row < 0) { return false; } return m_selectionModel->isSelected(index(row, 0)); } void FolderModel::setSelected(int row) { if (row < 0) { return; } m_selectionModel->select(index(row, 0), QItemSelectionModel::Select); } void FolderModel::toggleSelected(int row) { if (row < 0) { return; } m_selectionModel->select(index(row, 0), QItemSelectionModel::Toggle); } void FolderModel::setRangeSelected(int anchor, int to) { if (anchor < 0 || to < 0) { return; } QItemSelection selection(index(anchor, 0), index(to, 0)); m_selectionModel->select(selection, QItemSelectionModel::ClearAndSelect); } void FolderModel::updateSelection(const QVariantList &rows, bool toggle) { QItemSelection newSelection; int iRow = -1; foreach (const QVariant &row, rows) { iRow = row.toInt(); if (iRow < 0) { return; } const QModelIndex &idx = index(iRow, 0); newSelection.select(idx, idx); } if (toggle) { QItemSelection pinnedSelection = m_pinnedSelection; pinnedSelection.merge(newSelection, QItemSelectionModel::Toggle); m_selectionModel->select(pinnedSelection, QItemSelectionModel::ClearAndSelect); } else { m_selectionModel->select(newSelection, QItemSelectionModel::ClearAndSelect); } } void FolderModel::clearSelection() { if (m_selectionModel->hasSelection()) { m_selectionModel->clear(); } } void FolderModel::pinSelection() { m_pinnedSelection = m_selectionModel->selection(); } void FolderModel::unpinSelection() { m_pinnedSelection = QItemSelection(); } void FolderModel::addItemDragImage(int row, int x, int y, int width, int height, const QVariant &image) { if (row < 0) { return; } delete m_dragImages.take(row); DragImage *dragImage = new DragImage(); dragImage->row = row; dragImage->rect = QRect(x, y, width, height); dragImage->image = image.value(); dragImage->blank = false; m_dragImages.insert(row, dragImage); } void FolderModel::clearDragImages() { qDeleteAll(m_dragImages); m_dragImages.clear(); } void FolderModel::setDragHotSpotScrollOffset(int x, int y) { m_dragHotSpotScrollOffset.setX(x); m_dragHotSpotScrollOffset.setY(y); } QPoint FolderModel::dragCursorOffset(int row) { DragImage *image = m_dragImages.value(row); if (!image) { return QPoint(0, 0); } return image->cursorOffset; } void FolderModel::addDragImage(QDrag *drag, int x, int y) { if (!drag || m_dragImages.isEmpty()) { return; } QRegion region; foreach (DragImage *image, m_dragImages) { image->blank = isBlank(image->row); image->rect.translate(-m_dragHotSpotScrollOffset.x(), -m_dragHotSpotScrollOffset.y()); if (!image->blank && !image->image.isNull()) { region = region.united(image->rect); } } QRect rect = region.boundingRect(); QPoint offset = rect.topLeft(); rect.translate(-offset.x(), -offset.y()); QImage dragImage(rect.size(), QImage::Format_RGBA8888); dragImage.fill(Qt::transparent); QPainter painter(&dragImage); QPoint pos; foreach (DragImage *image, m_dragImages) { if (!image->blank && !image->image.isNull()) { pos = image->rect.translated(-offset.x(), -offset.y()).topLeft(); image->cursorOffset.setX(pos.x() - (x - offset.x())); image->cursorOffset.setY(pos.y() - (y - offset.y())); painter.drawImage(pos, image->image); } // FIXME HACK: Operate on copy. image->rect.translate(m_dragHotSpotScrollOffset.x(), m_dragHotSpotScrollOffset.y()); } drag->setPixmap(QPixmap::fromImage(dragImage)); drag->setHotSpot(QPoint(x - offset.x(), y - offset.y())); } void FolderModel::dragSelected(int x, int y) { if (m_dragInProgress) { return; } m_dragInProgress = true; emit draggingChanged(); m_urlChangedWhileDragging = false; // Avoid starting a drag synchronously in a mouse handler or interferes with // child event filtering in parent items (and thus e.g. press-and-hold hand- // ling in a containment). QMetaObject::invokeMethod(this, "dragSelectedInternal", Qt::QueuedConnection, Q_ARG(int, x), Q_ARG(int, y)); } void FolderModel::dragSelectedInternal(int x, int y) { if (!m_viewAdapter || !m_selectionModel->hasSelection()) { m_dragInProgress = false; emit draggingChanged(); return; } ItemViewAdapter *adapter = qobject_cast(m_viewAdapter); QQuickItem *item = qobject_cast(adapter->adapterView()); QDrag *drag = new QDrag(item); addDragImage(drag, x, y); m_dragIndexes = m_selectionModel->selectedIndexes(); std::sort(m_dragIndexes.begin(), m_dragIndexes.end()); // TODO: Optimize to emit contiguous groups. emit dataChanged(m_dragIndexes.first(), m_dragIndexes.last(), QVector() << BlankRole); QModelIndexList sourceDragIndexes; sourceDragIndexes.reserve(m_dragIndexes.count()); foreach (const QModelIndex &index, m_dragIndexes) { sourceDragIndexes.append(mapToSource(index)); } drag->setMimeData(m_dirModel->mimeData(sourceDragIndexes)); // Due to spring-loading (aka auto-expand), the URL might change // while the drag is in-flight - in that case we don't want to // unnecessarily emit dataChanged() for (possibly invalid) indices // after it ends. const QUrl currentUrl(m_dirModel->dirLister()->url()); item->grabMouse(); drag->exec(supportedDragActions()); item->ungrabMouse(); m_dragInProgress = false; emit draggingChanged(); m_urlChangedWhileDragging = false; if (m_dirModel->dirLister()->url() == currentUrl) { const QModelIndex first(m_dragIndexes.first()); const QModelIndex last(m_dragIndexes.last()); m_dragIndexes.clear(); // TODO: Optimize to emit contiguous groups. emit dataChanged(first, last, QVector() << BlankRole); } } static bool isDropBetweenSharedViews(const QList &urls, const QUrl &folderUrl) { for (const auto &url : urls) { if (folderUrl.adjusted(QUrl::StripTrailingSlash) != url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash)) { return false; } } return true; } void FolderModel::drop(QQuickItem *target, QObject* dropEvent, int row) { QMimeData *mimeData = qobject_cast(dropEvent->property("mimeData").value()); if (!mimeData) { return; } QModelIndex idx; KFileItem item; if (row > -1 && row < rowCount()) { idx = index(row, 0); item = itemForIndex(idx); } QUrl dropTargetUrl; // So we get to run mostLocalUrl() over the current URL. if (item.isNull()) { item = rootItem(); } if (item.isNull()) { dropTargetUrl = m_dirModel->dirLister()->url(); } else if (m_parseDesktopFiles && item.isDesktopFile()) { const KDesktopFile file(item.targetUrl().path()); if (file.hasLinkType()) { dropTargetUrl = QUrl(file.readUrl()); } else { dropTargetUrl = item.mostLocalUrl(); } } else { dropTargetUrl = item.mostLocalUrl(); } auto dropTargetFolderUrl = dropTargetUrl; if (dropTargetFolderUrl.fileName() == QLatin1String(".")) { // the target URL for desktop:/ is e.g. 'file://home/user/Desktop/.' dropTargetFolderUrl = dropTargetFolderUrl.adjusted(QUrl::RemoveFilename); } // use dropTargetUrl to resolve desktop:/ to the actual file location which is also used by the mime data /* QMimeData operates on local URLs, but the dir lister and thus screen mapper and positioner may * use a fancy scheme like desktop:/ instead. Ensure we always use the latter to properly map URLs, * i.e. go from file:///home/user/Desktop/file to desktop:/file */ auto mappableUrl = [this, dropTargetFolderUrl](const QUrl &url) -> QUrl { if (dropTargetFolderUrl != m_dirModel->dirLister()->url()) { QString mappedUrl = url.toString(); const auto local = dropTargetFolderUrl.toString(); const auto internal = m_dirModel->dirLister()->url().toString(); if (mappedUrl.startsWith(local)) { mappedUrl.replace(0, local.size(), internal); } return ScreenMapper::stringToUrl(mappedUrl); } return url; }; const int x = dropEvent->property("x").toInt(); const int y = dropEvent->property("y").toInt(); const QPoint dropPos = {x, y}; if (m_dragInProgress && row == -1 && !m_urlChangedWhileDragging) { if (m_locked || mimeData->urls().isEmpty()) { return; } setSortMode(-1); for (const auto &url : mimeData->urls()) { m_dropTargetPositions.insert(url.fileName(), dropPos); m_screenMapper->addMapping(mappableUrl(url), m_screen, ScreenMapper::DelayedSignal); m_screenMapper->removeItemFromDisabledScreen(mappableUrl(url)); } emit move(x, y, mimeData->urls()); return; } if (mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-service")) && mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-path"))) { const QString remoteDBusClient = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-service")); const QString remoteDBusPath = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-path")); QDBusMessage message = QDBusMessage::createMethodCall(remoteDBusClient, remoteDBusPath, QStringLiteral("org.kde.ark.DndExtract"), QStringLiteral("extractSelectedFilesTo")); message.setArguments({dropTargetUrl.toDisplayString(QUrl::PreferLocalFile)}); QDBusConnection::sessionBus().call(message, QDBus::NoBlock); return; } if (idx.isValid() && !(flags(idx) & Qt::ItemIsDropEnabled)) { return; } // Catch drops from a Task Manager and convert to usable URL. if (!mimeData->hasUrls() && mimeData->hasFormat(QStringLiteral("text/x-orgkdeplasmataskmanager_taskurl"))) { QList urls = {QUrl(QString::fromUtf8(mimeData->data(QStringLiteral("text/x-orgkdeplasmataskmanager_taskurl"))))}; mimeData->setUrls(urls); } if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { if (isDropBetweenSharedViews(mimeData->urls(), dropTargetFolderUrl)) { setSortMode(-1); for (const auto &url : mimeData->urls()) { m_dropTargetPositions.insert(url.fileName(), dropPos); m_screenMapper->addMapping(mappableUrl(url), m_screen, ScreenMapper::DelayedSignal); m_screenMapper->removeItemFromDisabledScreen(mappableUrl(url)); } m_dropTargetPositionsCleanup->start(); return; } } Qt::DropAction proposedAction((Qt::DropAction)dropEvent->property("proposedAction").toInt()); Qt::DropActions possibleActions(dropEvent->property("possibleActions").toInt()); Qt::MouseButtons buttons(dropEvent->property("buttons").toInt()); Qt::KeyboardModifiers modifiers(dropEvent->property("modifiers").toInt()); auto pos = target->mapToScene(dropPos).toPoint(); pos = target->window()->mapToGlobal(pos); QDropEvent ev(pos, possibleActions, mimeData, buttons, modifiers); ev.setDropAction(proposedAction); KIO::DropJob *dropJob = KIO::drop(&ev, dropTargetUrl); dropJob->uiDelegate()->setAutoErrorHandlingEnabled(true); // The QMimeData we extract from the DropArea's drop event is deleted as soon as this method // ends but we need to keep a copy for when popupMenuAboutToShow fires. QMimeData *mimeCopy = new QMimeData(); for (const QString &format : mimeData->formats()) { mimeCopy->setData(format, mimeData->data(format)); } connect(dropJob, &KIO::DropJob::popupMenuAboutToShow, this, [this, mimeCopy, x, y, dropJob](const KFileItemListProperties &) { emit popupMenuAboutToShow(dropJob, mimeCopy, x, y); mimeCopy->deleteLater(); }); /* * Position files that come from a drag'n'drop event at the drop event * target position. To do so, we first listen to copy job to figure out * the target URL. Then we store the position of this drop event in the * hash and eventually trigger a move request when we get notified about * the new file event from the source model. */ connect(dropJob, &KIO::DropJob::copyJobStarted, this, [this, dropPos, dropTargetUrl](KIO::CopyJob* copyJob) { auto map = [this, dropPos, dropTargetUrl](const QUrl &targetUrl) { m_dropTargetPositions.insert(targetUrl.fileName(), dropPos); m_dropTargetPositionsCleanup->start(); if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { // assign a screen for the item before the copy is actually done, so // filterAcceptsRow doesn't assign the default screen to it QUrl url = resolvedUrl(); // if the folderview's folder is a standard path, just use the targetUrl for mapping if (targetUrl.toString().startsWith(url.toString())) { m_screenMapper->addMapping(targetUrl, m_screen, ScreenMapper::DelayedSignal); } else if (targetUrl.toString().startsWith(dropTargetUrl.toString())) { // if the folderview's folder is a special path, like desktop:// , we need to convert // the targetUrl file:// path to a desktop:/ path for mapping auto destPath = dropTargetUrl.path(); auto filePath = targetUrl.path(); if (filePath.startsWith(destPath)) { url.setPath(filePath.remove(0, destPath.length())); m_screenMapper->addMapping(url, m_screen, ScreenMapper::DelayedSignal); } } } }; // remember drop target position for target URL and forget about the source URL connect(copyJob, &KIO::CopyJob::copyingDone, this, [this, map](KIO::Job *, const QUrl &, const QUrl &targetUrl, const QDateTime &, bool, bool) { map(targetUrl); }); connect(copyJob, &KIO::CopyJob::copyingLinkDone, this, [this, map](KIO::Job *, const QUrl &, const QString &, const QUrl &targetUrl) { map(targetUrl); }); }); } void FolderModel::dropCwd(QObject* dropEvent) { QMimeData *mimeData = qobject_cast(dropEvent->property("mimeData").value()); if (!mimeData) { return; } if (mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-service")) && mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-path"))) { const QString remoteDBusClient = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-service")); const QString remoteDBusPath = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-path")); QDBusMessage message = QDBusMessage::createMethodCall(remoteDBusClient, remoteDBusPath, QStringLiteral("org.kde.ark.DndExtract"), QStringLiteral("extractSelectedFilesTo")); message.setArguments(QVariantList() << m_dirModel->dirLister()->url().adjusted(QUrl::PreferLocalFile).toString()); QDBusConnection::sessionBus().call(message, QDBus::NoBlock); } else { Qt::DropAction proposedAction((Qt::DropAction)dropEvent->property("proposedAction").toInt()); Qt::DropActions possibleActions(dropEvent->property("possibleActions").toInt()); Qt::MouseButtons buttons(dropEvent->property("buttons").toInt()); Qt::KeyboardModifiers modifiers(dropEvent->property("modifiers").toInt()); QDropEvent ev(QPoint(), possibleActions, mimeData, buttons, modifiers); ev.setDropAction(proposedAction); KIO::DropJob *dropJob = KIO::drop(&ev, m_dirModel->dirLister()->url().adjusted(QUrl::PreferLocalFile)); dropJob->uiDelegate()->setAutoErrorHandlingEnabled(true); } } void FolderModel::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { QModelIndexList indices = selected.indexes(); indices.append(deselected.indexes()); QVector roles; roles.append(SelectedRole); foreach(const QModelIndex &index, indices) { emit dataChanged(index, index, roles); } if (!m_selectionModel->hasSelection()) { clearDragImages(); } else { foreach (const QModelIndex &idx, deselected.indexes()) { delete m_dragImages.take(idx.row()); } } updateActions(); } bool FolderModel::isBlank(int row) const { if (row < 0) { return true; } return data(index(row, 0), BlankRole).toBool(); } QVariant FolderModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == BlankRole) { return m_dragIndexes.contains(index); } else if (role == OverlaysRole) { const KFileItem item = itemForIndex(index); return item.overlays(); } else if (role == SelectedRole) { return m_selectionModel->isSelected(index); } else if (role == IsDirRole) { return isDir(mapToSource(index), m_dirModel); } else if (role == IsLinkRole) { const KFileItem item = itemForIndex(index); return item.isLink(); } else if (role == IsHiddenRole) { const KFileItem item = itemForIndex(index); return item.isHidden(); } else if (role == UrlRole) { return itemForIndex(index).url(); } else if (role == LinkDestinationUrl) { const KFileItem item = itemForIndex(index); if (m_parseDesktopFiles && item.isDesktopFile()) { const KDesktopFile file(item.targetUrl().path()); if (file.hasLinkType()) { return file.readUrl(); } } return item.targetUrl(); } else if (role == SizeRole) { bool isDir = data(index, IsDirRole).toBool(); if (!isDir) { return m_dirModel->data(mapToSource(QSortFilterProxyModel::index(index.row(), 1)), Qt::DisplayRole); } } else if (role == TypeRole) { return m_dirModel->data(mapToSource(QSortFilterProxyModel::index(index.row(), 6)), Qt::DisplayRole); } else if (role == FileNameRole) { return itemForIndex(index).url().fileName(); } return QSortFilterProxyModel::data(index, role); } int FolderModel::indexForUrl(const QUrl& url) const { return mapFromSource(m_dirModel->indexForUrl(url)).row(); } KFileItem FolderModel::itemForIndex(const QModelIndex &index) const { return m_dirModel->itemForIndex(mapToSource(index)); } bool FolderModel::isDir(const QModelIndex &index, const KDirModel *dirModel) const { KFileItem item = dirModel->itemForIndex(index); if (item.isDir()) { return true; } auto it = m_isDirCache.constFind(item.url()); if (it != m_isDirCache.constEnd()) { return *it; } if (m_parseDesktopFiles && item.isDesktopFile()) { // Check if the desktop file is a link to a directory KDesktopFile file(item.targetUrl().path()); if (!file.hasLinkType()) { return false; } const QUrl url(file.readUrl()); // Check if we already have a running StatJob for this URL. if (m_isDirJobs.contains(item.url())) { return false; } // Assume the root folder of a protocol is always a folder. // This avoids spinning up e.g. trash KIO slave just to check whether trash:/ is a folder. if (url.path() == QLatin1String("/")) { m_isDirCache.insert(item.url(), true); return true; } - if (KProtocolInfo::protocolClass(url.scheme()) != QStringLiteral(":local")) { + if (KProtocolInfo::protocolClass(url.scheme()) != QLatin1String(":local")) { return false; } KIO::StatJob *job = KIO::stat(url, KIO::HideProgressInfo); job->setProperty("org.kde.plasma.folder_url", item.url()); job->setSide(KIO::StatJob::SourceSide); job->setDetails(0); connect(job, &KJob::result, this, &FolderModel::statResult); m_isDirJobs.insert(item.url(), job); } return false; } void FolderModel::statResult(KJob *job) { KIO::StatJob *statJob = static_cast(job); const QUrl &url = statJob->property("org.kde.plasma.folder_url").toUrl(); const QModelIndex &idx = index(indexForUrl(url), 0); if (idx.isValid() && statJob->error() == KJob::NoError) { m_isDirCache[url] = statJob->statResult().isDir(); emit dataChanged(idx, idx, QVector() << IsDirRole); } m_isDirJobs.remove(url); } void FolderModel::evictFromIsDirCache(const KFileItemList& items) { foreach (const KFileItem &item, items) { m_screenMapper->removeFromMap(item.url()); m_isDirCache.remove(item.url()); } } bool FolderModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { const KDirModel *dirModel = static_cast(sourceModel()); if (m_sortDirsFirst || left.column() == KDirModel::Size) { bool leftIsDir = isDir(left, dirModel); bool rightIsDir = isDir(right, dirModel); if (leftIsDir && !rightIsDir) { return (sortOrder() == Qt::AscendingOrder); } if (!leftIsDir && rightIsDir) { return (sortOrder() == Qt::DescendingOrder); } } const KFileItem leftItem = dirModel->data(left, KDirModel::FileItemRole).value(); const KFileItem rightItem = dirModel->data(right, KDirModel::FileItemRole).value(); const int column = left.column(); int result = 0; switch (column) { case KDirModel::Size: { if (isDir(left, dirModel) && isDir(right, dirModel)) { const int leftChildCount = dirModel->data(left, KDirModel::ChildCountRole).toInt(); const int rightChildCount = dirModel->data(right, KDirModel::ChildCountRole).toInt(); if (leftChildCount < rightChildCount) result = -1; else if (leftChildCount > rightChildCount) result = +1; } else { const KIO::filesize_t leftSize = leftItem.size(); const KIO::filesize_t rightSize = rightItem.size(); if (leftSize < rightSize) result = -1; else if (leftSize > rightSize) result = +1; } break; } case KDirModel::ModifiedTime: { const long long leftTime = leftItem.entry().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1); const long long rightTime = rightItem.entry().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1); if (leftTime < rightTime) result = -1; else if (leftTime > rightTime) result = +1; break; } case KDirModel::Type: result = QString::compare(dirModel->data(left, Qt::DisplayRole).toString(), dirModel->data(right, Qt::DisplayRole).toString()); break; default: break; } if (result != 0) return result < 0; QCollator collator; result = collator.compare(leftItem.text(), rightItem.text()); if (result != 0) return result < 0; result = collator.compare(leftItem.name(), rightItem.name()); if (result != 0) return result < 0; return QString::compare(leftItem.url().url(), rightItem.url().url(), Qt::CaseSensitive); } Qt::DropActions FolderModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; } Qt::DropActions FolderModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; } inline bool FolderModel::matchMimeType(const KFileItem &item) const { if (m_mimeSet.isEmpty()) { return false; } - if (m_mimeSet.contains(QStringLiteral("all/all")) || m_mimeSet.contains(QStringLiteral("all/allfiles"))) { + if (m_mimeSet.contains(QLatin1String("all/all")) || m_mimeSet.contains(QStringLiteral("all/allfiles"))) { return true; } const QString mimeType = item.determineMimeType().name(); return m_mimeSet.contains(mimeType); } inline bool FolderModel::matchPattern(const KFileItem &item) const { if (m_filterPatternMatchAll) { return true; } const QString name = item.name(); QListIterator i(m_regExps); while (i.hasNext()) { if (i.next().exactMatch(name)) { return true; } } return false; } bool FolderModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { const KDirModel *dirModel = static_cast(sourceModel()); const KFileItem item = dirModel->itemForIndex(dirModel->index(sourceRow, KDirModel::Name, sourceParent)); if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { const QUrl url = item.url(); const int screen = m_screenMapper->screenForItem(url); // don't do anything if the folderview is not associated with a screen if (m_screenUsed && screen == -1) { // The item is not associated with a screen, probably because this is the first // time we see it or the folderview was previously used as a regular applet. // Associated with this folderview if the view is on the first available screen if (m_screen == m_screenMapper->firstAvailableScreen(resolvedUrl())) { m_screenMapper->addMapping(url, m_screen, ScreenMapper::DelayedSignal); } else { return false; } } else if (m_screen != screen) { // the item belongs to a different screen, filter it out return false; } } if (m_filterMode == NoFilter) { return true; } if (m_filterMode == FilterShowMatches) { return (matchPattern(item) && matchMimeType(item)); } else { return !(matchPattern(item) && matchMimeType(item)); } } void FolderModel::createActions() { KIO::FileUndoManager *manager = KIO::FileUndoManager::self(); QAction *cut = KStandardAction::cut(this, &FolderModel::cut, this); QAction *copy = KStandardAction::copy(this, &FolderModel::copy, this); QAction *undo = KStandardAction::undo(manager, &KIO::FileUndoManager::undo, this); undo->setEnabled(manager->undoAvailable()); undo->setShortcutContext(Qt::WidgetShortcut); connect(manager, SIGNAL(undoAvailable(bool)), undo, SLOT(setEnabled(bool))); connect(manager, &KIO::FileUndoManager::undoTextChanged, this, &FolderModel::undoTextChanged); QAction *paste = KStandardAction::paste(this, &FolderModel::paste, this); QAction *pasteTo = KStandardAction::paste(this, &FolderModel::pasteTo, this); QAction *refresh = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18n("&Refresh View"), this); refresh->setShortcut(QKeySequence(QKeySequence::Refresh)); connect(refresh, &QAction::triggered, this, &FolderModel::refresh); QAction *rename = KStandardAction::renameFile(this, &FolderModel::requestRename, this); QAction *trash = KStandardAction::moveToTrash(this, &FolderModel::moveSelectedToTrash, this); QAction *emptyTrash = new QAction(QIcon::fromTheme(QStringLiteral("trash-empty")), i18n("&Empty Trash"), this); connect(emptyTrash, &QAction::triggered, this, &FolderModel::emptyTrashBin); QAction *restoreFromTrash = new QAction(i18nc("Restore from trash", "Restore"), this); connect(restoreFromTrash, &QAction::triggered, this, &FolderModel::restoreSelectedFromTrash); QAction *del = KStandardAction::deleteFile(this, &FolderModel::deleteSelected, this); QAction *actOpen = new QAction(QIcon::fromTheme(QStringLiteral("window-new")), i18n("&Open"), this); connect(actOpen, &QAction::triggered, this, &FolderModel::openSelected); m_actionCollection.addAction(QStringLiteral("open"), actOpen); m_actionCollection.addAction(QStringLiteral("cut"), cut); m_actionCollection.addAction(QStringLiteral("undo"), undo); m_actionCollection.addAction(QStringLiteral("copy"), copy); m_actionCollection.addAction(QStringLiteral("paste"), paste); m_actionCollection.addAction(QStringLiteral("pasteto"), pasteTo); m_actionCollection.addAction(QStringLiteral("refresh"), refresh); m_actionCollection.addAction(QStringLiteral("rename"), rename); m_actionCollection.addAction(QStringLiteral("trash"), trash); m_actionCollection.addAction(QStringLiteral("del"), del); m_actionCollection.addAction(QStringLiteral("restoreFromTrash"), restoreFromTrash); m_actionCollection.addAction(QStringLiteral("emptyTrash"), emptyTrash); m_newMenu = new KNewFileMenu(&m_actionCollection, QStringLiteral("newMenu"), this); m_newMenu->setModal(false); connect(m_newMenu, &KNewFileMenu::directoryCreated, this, &FolderModel::newFileMenuItemCreated); connect(m_newMenu, &KNewFileMenu::fileCreated, this, &FolderModel::newFileMenuItemCreated); m_copyToMenu = new KFileCopyToMenu(nullptr); } QAction* FolderModel::action(const QString &name) const { return m_actionCollection.action(name); } QObject* FolderModel::newMenu() const { return m_newMenu->menu(); } void FolderModel::updateActions() { const QModelIndexList indexes = m_selectionModel->selectedIndexes(); KFileItemList items; QList urls; bool hasRemoteFiles = false; bool isTrashLink = false; const bool isTrash = (resolvedUrl().scheme() == QLatin1String("trash")); if (indexes.isEmpty()) { items << rootItem(); } else { items.reserve(indexes.count()); urls.reserve(indexes.count()); for (const QModelIndex &index : indexes) { KFileItem item = itemForIndex(index); if (!item.isNull()) { hasRemoteFiles |= item.localPath().isEmpty(); items.append(item); urls.append(item.url()); } } } KFileItemListProperties itemProperties(items); // Check if we're showing the menu for the trash link if (items.count() == 1 && items.at(0).isDesktopFile()) { KDesktopFile file(items.at(0).localPath()); if (file.hasLinkType() && file.readUrl() == QLatin1String("trash:/")) { isTrashLink = true; } } if (m_newMenu) { m_newMenu->checkUpToDate(); m_newMenu->setPopupFiles(m_dirModel->dirLister()->url()); // we need to set here as well, when the menu is shown via AppletInterface::eventFilter m_menuPosition = QCursor::pos(); if (QAction *newMenuAction = m_actionCollection.action(QStringLiteral("newMenu"))) { newMenuAction->setEnabled(itemProperties.supportsWriting()); newMenuAction->setVisible(!isTrash); } } if (QAction *emptyTrash = m_actionCollection.action(QStringLiteral("emptyTrash"))) { if (isTrash || isTrashLink) { emptyTrash->setVisible(true); emptyTrash->setEnabled(!isTrashEmpty()); } else { emptyTrash->setVisible(false); } } if (QAction *restoreFromTrash = m_actionCollection.action(QStringLiteral("restoreFromTrash"))) { restoreFromTrash->setVisible(isTrash); } if (QAction *moveToTrash = m_actionCollection.action(QStringLiteral("trash"))) { moveToTrash->setVisible(!hasRemoteFiles && itemProperties.supportsMoving()); } if (QAction *del = m_actionCollection.action(QStringLiteral("del"))) { del->setVisible(itemProperties.supportsDeleting()); } if (QAction *cut = m_actionCollection.action(QStringLiteral("cut"))) { cut->setEnabled(itemProperties.supportsDeleting()); cut->setVisible(!isTrash); } if (QAction *paste = m_actionCollection.action(QStringLiteral("paste"))) { bool enable = false; const QString pasteText = KIO::pasteActionText(QApplication::clipboard()->mimeData(), &enable, rootItem()); if (enable) { paste->setText(pasteText); paste->setEnabled(true); } else { paste->setText(i18n("&Paste")); paste->setEnabled(false); } if (QAction *pasteTo = m_actionCollection.action(QStringLiteral("pasteto"))) { pasteTo->setVisible(itemProperties.isDirectory() && itemProperties.supportsWriting()); pasteTo->setEnabled(paste->isEnabled()); pasteTo->setText(paste->text()); } } if (QAction *rename = m_actionCollection.action(QStringLiteral("rename"))) { rename->setEnabled(itemProperties.supportsMoving()); rename->setVisible(!isTrash); } } void FolderModel::openContextMenu(QQuickItem *visualParent, Qt::KeyboardModifiers modifiers) { if (m_usedByContainment && !KAuthorized::authorize(QStringLiteral("action/kdesktop_rmb"))) { return; } updateActions(); const QModelIndexList indexes = m_selectionModel->selectedIndexes(); QMenu *menu = new QMenu(); if (!m_fileItemActions) { m_fileItemActions = new KFileItemActions(this); m_fileItemActions->setParentWidget(QApplication::desktop()); } if (indexes.isEmpty()) { menu->addAction(m_actionCollection.action(QStringLiteral("newMenu"))); menu->addSeparator(); menu->addAction(m_actionCollection.action(QStringLiteral("paste"))); menu->addAction(m_actionCollection.action(QStringLiteral("undo"))); menu->addAction(m_actionCollection.action(QStringLiteral("refresh"))); menu->addAction(m_actionCollection.action(QStringLiteral("emptyTrash"))); menu->addSeparator(); KFileItemListProperties itemProperties(KFileItemList() << rootItem()); m_fileItemActions->setItemListProperties(itemProperties); menu->addAction(m_fileItemActions->preferredOpenWithAction(QString())); } else { KFileItemList items; QList urls; items.reserve(indexes.count()); urls.reserve(indexes.count()); for (const QModelIndex &index : indexes) { KFileItem item = itemForIndex(index); if (!item.isNull()) { items.append(item); urls.append(item.url()); } } KFileItemListProperties itemProperties(items); // Start adding the actions: // "Open" and "Open with" actions m_fileItemActions->setItemListProperties(itemProperties); m_fileItemActions->addOpenWithActionsTo(menu); menu->addSeparator(); menu->addAction(m_actionCollection.action(QStringLiteral("cut"))); menu->addAction(m_actionCollection.action(QStringLiteral("copy"))); menu->addAction(m_actionCollection.action(QStringLiteral("paste"))); menu->addSeparator(); menu->addAction(m_actionCollection.action(QStringLiteral("rename"))); menu->addAction(m_actionCollection.action(QStringLiteral("restoreFromTrash"))); KConfigGroup cg(KSharedConfig::openConfig(), "KDE"); bool showDeleteCommand = cg.readEntry("ShowDeleteCommand", false); menu->addAction(m_actionCollection.action(QStringLiteral("emptyTrash"))); QAction *trashAction = m_actionCollection.action(QStringLiteral("trash")); menu->addAction(trashAction); trashAction->setVisible(!modifiers.testFlag(Qt::ShiftModifier)); QAction *deleteAction = m_actionCollection.action(QStringLiteral("del")); menu->addAction(deleteAction); deleteAction->setVisible(showDeleteCommand || !trashAction->isVisible()); menu->addSeparator(); // Service actions m_fileItemActions->addServiceActionsTo(menu); menu->addSeparator(); // Plugin actions m_fileItemActions->addPluginActionsTo(menu); // Copy To, Move To KSharedConfig::Ptr dolphin = KSharedConfig::openConfig(QStringLiteral("dolphinrc")); if (KConfigGroup(dolphin, "General").readEntry("ShowCopyMoveMenu", false)) { m_copyToMenu->setUrls(urls); m_copyToMenu->setReadOnly(!itemProperties.supportsMoving()); m_copyToMenu->addActionsTo(menu); menu->addSeparator(); } // Properties if (KPropertiesDialog::canDisplay(items)) { menu->addSeparator(); QAction *act = new QAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18n("&Properties"), menu); act->setShortcuts({Qt::ALT + Qt::Key_Return, Qt::ALT + Qt::Key_Enter}); QObject::connect(act, &QAction::triggered, this, &FolderModel::openPropertiesDialog); menu->addAction(act); } } if (visualParent) { m_menuPosition = visualParent->mapToGlobal(QPointF(0, visualParent->height())).toPoint(); } else { m_menuPosition = QCursor::pos(); } // Used to monitor Shift modifier usage while the menu is open, to // swap the Trash and Delete actions. menu->installEventFilter(this); menu->setAttribute(Qt::WA_TranslucentBackground); menu->winId(); //force surface creation before ensurePolish call in menu::Popup which happens before show menu->popup(m_menuPosition); connect(menu, &QMenu::aboutToHide, [menu]() { menu->deleteLater(); }); } void FolderModel::openPropertiesDialog() { const QModelIndexList indexes = m_selectionModel->selectedIndexes(); if (indexes.isEmpty()) { return; } KFileItemList items; items.reserve(indexes.count()); for (const QModelIndex &index : indexes) { KFileItem item = itemForIndex(index); if (!item.isNull()) { items.append(item); } } if (!KPropertiesDialog::canDisplay(items)) { return; } KPropertiesDialog::showDialog(items, nullptr, false /*non modal*/); } void FolderModel::linkHere(const QUrl &sourceUrl) { KIO::CopyJob *job = KIO::link(sourceUrl, m_dirModel->dirLister()->url()); KIO::FileUndoManager::self()->recordCopyJob(job); } QList FolderModel::selectedUrls() const { const auto indexes = m_selectionModel->selectedIndexes(); QList urls; urls.reserve(indexes.count()); for (const QModelIndex &index : indexes) { urls.append(itemForIndex(index).url()); } return urls; } void FolderModel::copy() { if (!m_selectionModel->hasSelection()) { return; } if (QAction *action = m_actionCollection.action(QStringLiteral("copy"))) { if (!action->isEnabled()) { return; } } QMimeData *mimeData = QSortFilterProxyModel::mimeData(m_selectionModel->selectedIndexes()); QApplication::clipboard()->setMimeData(mimeData); } void FolderModel::cut() { if (!m_selectionModel->hasSelection()) { return; } if (QAction *action = m_actionCollection.action(QStringLiteral("cut"))) { if (!action->isEnabled()) { return; } } QMimeData *mimeData = QSortFilterProxyModel::mimeData(m_selectionModel->selectedIndexes()); KIO::setClipboardDataCut(mimeData, true); QApplication::clipboard()->setMimeData(mimeData); } void FolderModel::paste() { if (QAction *action = m_actionCollection.action(QStringLiteral("paste"))) { if (!action->isEnabled()) { return; } } KIO::paste(QApplication::clipboard()->mimeData(), m_dirModel->dirLister()->url()); } void FolderModel::pasteTo() { const QList urls = selectedUrls(); Q_ASSERT(urls.count() == 1); KIO::paste(QApplication::clipboard()->mimeData(), urls.first()); } void FolderModel::refresh() { m_errorString.clear(); emit errorStringChanged(); m_dirModel->dirLister()->updateDirectory(m_dirModel->dirLister()->url()); } QObject *FolderModel::appletInterface() const { return m_appletInterface; } void FolderModel::setAppletInterface(QObject *appletInterface) { if (m_appletInterface != appletInterface) { Q_ASSERT(!m_appletInterface); m_appletInterface = appletInterface; if (appletInterface) { Plasma::Applet *applet = appletInterface->property("_plasma_applet").value(); if (applet) { Plasma::Containment *containment = applet->containment(); if (containment) { Plasma::Corona *corona = containment->corona(); if (corona) { m_screenMapper->setCorona(corona); } setScreen(containment->screen()); connect(containment, &Plasma::Containment::screenChanged, this, &FolderModel::setScreen); } } } emit appletInterfaceChanged(); } } void FolderModel::moveSelectedToTrash() { if (!m_selectionModel->hasSelection()) { return; } if (QAction *action = m_actionCollection.action(QStringLiteral("trash"))) { if (!action->isEnabled()) { return; } } const QList urls = selectedUrls(); KIO::JobUiDelegate uiDelegate; if (uiDelegate.askDeleteConfirmation(urls, KIO::JobUiDelegate::Trash, KIO::JobUiDelegate::DefaultConfirmation)) { KIO::Job* job = KIO::trash(urls); job->uiDelegate()->setAutoErrorHandlingEnabled(true); KIO::FileUndoManager::self()->recordJob(KIO::FileUndoManager::Trash, urls, QUrl(QStringLiteral("trash:/")), job); } } void FolderModel::deleteSelected() { if (!m_selectionModel->hasSelection()) { return; } if (QAction *action = m_actionCollection.action(QStringLiteral("del"))) { if (!action->isEnabled()) { return; } } const QList urls = selectedUrls(); KIO::JobUiDelegate uiDelegate; if (uiDelegate.askDeleteConfirmation(urls, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::DefaultConfirmation)) { KIO::Job* job = KIO::del(urls); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } } void FolderModel::openSelected() { if (!m_selectionModel->hasSelection()) { return; } const QList urls = selectedUrls(); for (const QUrl &url : urls) { (void) new KRun(url, nullptr); } } void FolderModel::undo() { if (QAction *action = m_actionCollection.action(QStringLiteral("undo"))) { // trigger() doesn't check enabled and would crash if invoked nonetheless. if (action->isEnabled()) { action->trigger(); } } } void FolderModel::emptyTrashBin() { KIO::JobUiDelegate uiDelegate; uiDelegate.setWindow(QApplication::desktop()); if (uiDelegate.askDeleteConfirmation(QList(), KIO::JobUiDelegate::EmptyTrash, KIO::JobUiDelegate::DefaultConfirmation)) { KIO::Job* job = KIO::emptyTrash(); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } } void FolderModel::restoreSelectedFromTrash() { if (!m_selectionModel->hasSelection()) { return; } const auto &urls = selectedUrls(); KIO::RestoreJob *job = KIO::restoreFromTrash(urls); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } bool FolderModel::isTrashEmpty() { KConfig trashConfig(QStringLiteral("trashrc"), KConfig::SimpleConfig); return trashConfig.group("Status").readEntry("Empty", true); } void FolderModel::undoTextChanged(const QString &text) { if (QAction *action = m_actionCollection.action(QStringLiteral("undo"))) { action->setText(text); } } diff --git a/dataengines/kimpanel/kimpaneljob.cpp b/dataengines/kimpanel/kimpaneljob.cpp index af6ae81eb..b31da3270 100644 --- a/dataengines/kimpanel/kimpaneljob.cpp +++ b/dataengines/kimpanel/kimpaneljob.cpp @@ -1,62 +1,62 @@ /*************************************************************************** * Copyright (C) 2011 by CSSlayer * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "kimpaneljob.h" #include "kimpanelagent.h" KimpanelJob::KimpanelJob(PanelAgent* panelAgent, const QString& destination, const QString& operation, const QMap< QString, QVariant >& parameters, QObject* parent): Plasma::ServiceJob(destination, operation, parameters, parent), m_panelAgent(panelAgent) { } void KimpanelJob::start() { const QString operation(operationName()); if (operation == QLatin1String("LookupTablePageUp")) { m_panelAgent->lookupTablePageUp(); } else if (operation == QLatin1String("LookupTablePageDown")) { m_panelAgent->lookupTablePageDown(); } else if (operation == QLatin1String("MovePreeditCaret")) { - if (parameters().contains(QStringLiteral("position"))) { + if (parameters().contains(QLatin1String("position"))) { int position = parameters()[QStringLiteral("position")].toInt(); m_panelAgent->movePreeditCaret(position); } } else if (operation == QLatin1String("SelectCandidate")) { - if (parameters().contains(QStringLiteral("candidate"))) { + if (parameters().contains(QLatin1String("candidate"))) { int candidate = parameters()[QStringLiteral("candidate")].toInt(); m_panelAgent->selectCandidate(candidate); } } else if (operation == QLatin1String("TriggerProperty")) { - if (parameters().contains(QStringLiteral("key"))) { + if (parameters().contains(QLatin1String("key"))) { QString key = parameters()[QStringLiteral("key")].toString(); m_panelAgent->triggerProperty(key); } } else if (operation == QLatin1String("ReloadConfig")) { m_panelAgent->reloadConfig(); } else if (operation == QLatin1String("Configure")) { m_panelAgent->configure(); } else if (operation == QLatin1String("Exit")) { m_panelAgent->exit(); } } diff --git a/kcms/autostart/autostart.cpp b/kcms/autostart/autostart.cpp index dbcfdddf9..33213641f 100644 --- a/kcms/autostart/autostart.cpp +++ b/kcms/autostart/autostart.cpp @@ -1,470 +1,470 @@ /*************************************************************************** * Copyright (C) 2006-2007 by Stephen Leaf * * smileaf@gmail.com * * Copyright (C) 2008 by Montel Laurent * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include "autostart.h" #include "autostartitem.h" #include "addscriptdialog.h" #include "advanceddialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(AutostartFactory, registerPlugin();) Autostart::Autostart( QWidget* parent, const QVariantList& ) : KCModule(parent ) { widget = new Ui_AutostartConfig(); widget->setupUi(this); QStringList lstHeader; lstHeader << i18n( "Name" ) << i18n( "Command" ) << i18n( "Status" ) << i18nc("@title:column The name of the column that decides if the program is run on session startup, on session shutdown, etc", "Run On" ); widget->listCMD->setHeaderLabels(lstHeader); widget->listCMD->setFocus(); setButtons(Help); connect( widget->btnProperties, SIGNAL(clicked()), SLOT(slotEditCMD()) ); connect( widget->listCMD, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), SLOT(slotEditCMD(QTreeWidgetItem*)) ); connect(widget->btnAddScript, &QPushButton::clicked, this, &Autostart::slotAddScript); connect(widget->btnAddProgram, &QPushButton::clicked, this, &Autostart::slotAddProgram); connect(widget->btnRemove, &QPushButton::clicked, this, &Autostart::slotRemoveCMD); connect(widget->btnAdvanced, &QPushButton::clicked, this, &Autostart::slotAdvanced); connect(widget->listCMD, &QTreeWidget::itemClicked, this, &Autostart::slotItemClicked); connect(widget->listCMD, &QTreeWidget::itemSelectionChanged, this, &Autostart::slotSelectionChanged); KAboutData* about = new KAboutData(QStringLiteral("Autostart"), i18n("Session Autostart Manager"), QStringLiteral("1.0"), i18n("Session Autostart Manager Control Panel Module"), KAboutLicense::GPL, i18n("Copyright © 2006–2010 Autostart Manager team")); about->addAuthor(i18n("Stephen Leaf"), QString(), QStringLiteral("smileaf@gmail.com")); about->addAuthor(i18n("Montel Laurent"), i18n( "Maintainer" ), QStringLiteral("montel@kde.org")); setAboutData( about ); } Autostart::~Autostart() { delete widget; } void Autostart::slotItemClicked( QTreeWidgetItem *item, int col) { if ( item && col == COL_STATUS ) { DesktopStartItem *entry = dynamic_cast( item ); if ( entry ) { bool disable = ( item->checkState( col ) == Qt::Unchecked ); KDesktopFile kc(entry->fileName().path()); KConfigGroup grp = kc.desktopGroup(); if ( grp.hasKey( "Hidden" ) && !disable) { grp.deleteEntry( "Hidden" ); } else grp.writeEntry("Hidden", disable); kc.sync(); if ( disable ) item->setText( COL_STATUS, i18nc( "The program won't be run", "Disabled" ) ); else item->setText( COL_STATUS, i18nc( "The program will be run", "Enabled" ) ); } } } void Autostart::addItem( DesktopStartItem* item, const QString& name, const QString& run, const QString& command, bool disabled ) { Q_ASSERT( item ); item->setText( COL_NAME, name ); item->setText( COL_RUN, run ); item->setText( COL_COMMAND, command ); item->setCheckState( COL_STATUS, disabled ? Qt::Unchecked : Qt::Checked ); item->setText( COL_STATUS, disabled ? i18nc( "The program won't be run", "Disabled" ) : i18nc( "The program will be run", "Enabled" )); } void Autostart::addItem(ScriptStartItem* item, const QString& name, const QString& command, ScriptStartItem::ENV type ) { Q_ASSERT( item ); item->setText( COL_NAME, name ); item->setText( COL_COMMAND, command ); item->changeStartup( type ); } void Autostart::load() { // FDO user autostart directories are // .config/autostart which has .desktop files executed by klaunch //Then we have Plasma-specific locations which run scripts // .config/autostart-scripts which has scripts executed by ksmserver // .config/plasma-workspace/shutdown which has scripts executed by startkde // .config/plasma-workspace/env which has scripts executed by startkde //in the case of pre-startup they have to end in .sh //everywhere else it doesn't matter //the comment above describes how autostart *currently* works, it is not definitive documentation on how autostart *should* work m_desktopPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/autostart/"); m_paths << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/autostart-scripts/") << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/plasma-workspace/shutdown/") << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/plasma-workspace/env/"); // share/autostart shouldn't be an option as this should be reserved for global autostart entries m_pathName << i18n("Startup") << i18n("Logout") << i18n("Before session startup") ; widget->listCMD->clear(); m_programItem = new QTreeWidgetItem( widget->listCMD ); m_programItem->setText( 0, i18n( "Desktop File" )); m_programItem->setFlags(m_programItem->flags()^Qt::ItemIsSelectable ); QFont boldFont = m_programItem->font(0); boldFont.setBold( true ); m_programItem->setData ( 0, Qt::FontRole, boldFont ); m_scriptItem = new QTreeWidgetItem( widget->listCMD ); m_scriptItem->setText( 0, i18n( "Script File" )); m_scriptItem->setFlags(m_scriptItem->flags()^Qt::ItemIsSelectable); m_scriptItem->setData ( 0, Qt::FontRole, boldFont); widget->listCMD->expandItem( m_programItem ); widget->listCMD->expandItem( m_scriptItem ); //add programs { QDir d(m_desktopPath); if (!d.exists()) d.mkpath(m_desktopPath); QDir autostartdir( m_desktopPath ); autostartdir.setFilter( QDir::Files ); const QFileInfoList list = autostartdir.entryInfoList(); for (int i = 0; i < list.size(); ++i) { QFileInfo fi = list.at(i); QString filename = fi.fileName(); bool desktopFile = filename.endsWith(QLatin1String(".desktop")); if ( desktopFile ) { KDesktopFile config(fi.absoluteFilePath()); //kDebug() << fi.absoluteFilePath() << "trying" << config.desktopGroup().readEntry("Exec"); QStringList commandLine = KShell::splitArgs(config.desktopGroup().readEntry("Exec")); if (commandLine.isEmpty()) { continue; } const QString exe = commandLine.first(); if (exe.isEmpty() || QStandardPaths::findExecutable(exe).isEmpty()) { continue; } DesktopStartItem *item = new DesktopStartItem( fi.absoluteFilePath(), m_programItem, this ); const KConfigGroup grp = config.desktopGroup(); const bool hidden = grp.readEntry("Hidden", false); const QStringList notShowList = grp.readXdgListEntry("NotShowIn"); const QStringList onlyShowList = grp.readXdgListEntry("OnlyShowIn"); const bool disabled = hidden || - notShowList.contains(QStringLiteral("KDE")) || - (!onlyShowList.isEmpty() && !onlyShowList.contains(QStringLiteral("KDE"))); + notShowList.contains(QLatin1String("KDE")) || + (!onlyShowList.isEmpty() && !onlyShowList.contains(QLatin1String("KDE"))); int indexPath = m_paths.indexOf((item->fileName().adjusted(QUrl::RemoveFilename).toString() ) ); if ( indexPath > 2 ) indexPath = 0; //.kde/share/autostart and .config/autostart load desktop at startup addItem(item, config.readName(), m_pathName.value(indexPath), grp.readEntry("Exec"), disabled ); } } } //add scripts foreach (const QString& path, m_paths) { QDir d(path); if (!d.exists()) d.mkpath(path); QDir autostartdir( path ); autostartdir.setFilter( QDir::Files ); const QFileInfoList list = autostartdir.entryInfoList(); for (int i = 0; i < list.size(); ++i) { QFileInfo fi = list.at(i); ScriptStartItem *item = new ScriptStartItem( fi.absoluteFilePath(), m_scriptItem,this ); int typeOfStartup = m_paths.indexOf((item->fileName().adjusted(QUrl::RemoveScheme | QUrl::RemoveFilename).toString()) ); ScriptStartItem::ENV type = ScriptStartItem::START; switch( typeOfStartup ) { case 0: type =ScriptStartItem::START; break; case 1: type = ScriptStartItem::SHUTDOWN; break; case 2: type = ScriptStartItem::PRE_START; break; default: qDebug()<<" type is not defined :"<listCMD->resizeColumnToContents(COL_NAME); //widget->listCMD->resizeColumnToContents(COL_COMMAND); widget->listCMD->resizeColumnToContents(COL_STATUS); widget->listCMD->resizeColumnToContents(COL_RUN); } void Autostart::slotAddProgram() { KOpenWithDialog owdlg( this ); if (owdlg.exec() != QDialog::Accepted) return; KService::Ptr service = owdlg.service(); Q_ASSERT(service); if (!service) { return; // Don't crash if KOpenWith wasn't able to create service. } // It is important to ensure that we make an exact copy of an existing // desktop file (if selected) to enable users to override global autostarts. // Also see // https://bugs.launchpad.net/ubuntu/+source/kde-workspace/+bug/923360 QString desktopPath; QUrl desktopTemplate; if ( service->desktopEntryName().isEmpty() || service->entryPath().isEmpty()) { // Build custom desktop file (e.g. when the user entered an executable // name in the OpenWithDialog). desktopPath = m_desktopPath + service->name() + QStringLiteral(".desktop"); desktopTemplate = QUrl::fromLocalFile( desktopPath ); KConfig kc(desktopTemplate.path(), KConfig::SimpleConfig); KConfigGroup kcg = kc.group("Desktop Entry"); kcg.writeEntry("Exec",service->exec()); kcg.writeEntry("Icon","system-run"); kcg.writeEntry("Path",""); kcg.writeEntry("Terminal",false); kcg.writeEntry("Type","Application"); kc.sync(); KPropertiesDialog dlg( desktopTemplate, this ); if ( dlg.exec() != QDialog::Accepted ) { return; } } else { // Use existing desktop file and use same file name to enable overrides. desktopPath = m_desktopPath + service->desktopEntryName() + QStringLiteral(".desktop"); desktopTemplate = QUrl::fromLocalFile( QStandardPaths::locate(QStandardPaths::ApplicationsLocation, service->entryPath()) ); KPropertiesDialog dlg( QUrl::fromLocalFile(service->entryPath()), QUrl::fromLocalFile(m_desktopPath), service->desktopEntryName() + QStringLiteral(".desktop"), this ); if ( dlg.exec() != QDialog::Accepted ) return; } KDesktopFile newConf(desktopTemplate.path()); DesktopStartItem * item = new DesktopStartItem( desktopPath, m_programItem,this ); addItem( item, service->name(), m_pathName[0], newConf.desktopGroup().readEntry("Exec") , false); } void Autostart::slotAddScript() { AddScriptDialog * addDialog = new AddScriptDialog(this); int result = addDialog->exec(); if (result == QDialog::Accepted) { if (addDialog->symLink()) KIO::link(addDialog->importUrl(), QUrl::fromLocalFile(m_paths[0])); else KIO::copy(addDialog->importUrl(), QUrl::fromLocalFile(m_paths[0])); ScriptStartItem * item = new ScriptStartItem( m_paths[0] + addDialog->importUrl().fileName(), m_scriptItem,this ); addItem( item, addDialog->importUrl().fileName(), addDialog->importUrl().fileName(),ScriptStartItem::START ); } delete addDialog; } void Autostart::slotRemoveCMD() { QTreeWidgetItem* item = widget->listCMD->currentItem(); if (!item) return; DesktopStartItem *startItem = dynamic_cast( item ); if ( startItem ) { QUrl path(startItem->fileName()); path.setScheme(QStringLiteral("file")); m_programItem->takeChild( m_programItem->indexOfChild( startItem ) ); KIO::del(path); delete item; } else { ScriptStartItem * scriptItem = dynamic_cast( item ); if ( scriptItem ) { QUrl path(scriptItem->fileName()); path.setScheme(QStringLiteral("file")); m_scriptItem->takeChild( m_scriptItem->indexOfChild( scriptItem ) ); KIO::del(path); delete item; } } } void Autostart::slotEditCMD(QTreeWidgetItem* ent) { if (!ent) return; DesktopStartItem *desktopEntry = dynamic_cast( ent ); if ( desktopEntry ) { KFileItem kfi = KFileItem(QUrl(desktopEntry->fileName())); kfi.setDelayedMimeTypes(true); if (! slotEditCMD( kfi )) return; if (desktopEntry) { KService service(desktopEntry->fileName().path()); addItem( desktopEntry, service.name(), m_pathName.value(m_paths.indexOf(desktopEntry->fileName().adjusted(QUrl::RemoveFilename).toString())), service.exec(),false ); } } } bool Autostart::slotEditCMD( const KFileItem &item) { KPropertiesDialog dlg( item, this ); bool c = ( dlg.exec() == QDialog::Accepted ); return c; } void Autostart::slotEditCMD() { if ( widget->listCMD->currentItem() == nullptr ) return; slotEditCMD( (AutoStartItem*)widget->listCMD->currentItem() ); } void Autostart::slotAdvanced() { if ( widget->listCMD->currentItem() == nullptr ) return; DesktopStartItem *entry = static_cast( widget->listCMD->currentItem() ); KDesktopFile kc(entry->fileName().path()); KConfigGroup grp = kc.desktopGroup(); bool status = false; QStringList lstEntry; if (grp.hasKey("OnlyShowIn")) { lstEntry = grp.readXdgListEntry("OnlyShowIn"); - status = lstEntry.contains(QStringLiteral("KDE")); + status = lstEntry.contains(QLatin1String("KDE")); } AdvancedDialog *dlg = new AdvancedDialog( this,status ); if ( dlg->exec() ) { status = dlg->onlyInKde(); - if ( lstEntry.contains( QStringLiteral("KDE") ) && !status ) + if ( lstEntry.contains(QLatin1String("KDE") ) && !status ) { lstEntry.removeAll( QStringLiteral("KDE") ); grp.writeXdgListEntry( "OnlyShowIn", lstEntry ); } - else if ( !lstEntry.contains( QStringLiteral("KDE") ) && status ) + else if ( !lstEntry.contains(QLatin1String("KDE") ) && status ) { lstEntry.append( QStringLiteral("KDE") ); grp.writeXdgListEntry( "OnlyShowIn", lstEntry ); } } delete dlg; } void Autostart::slotChangeStartup( ScriptStartItem* item, int index ) { Q_ASSERT(item); if ( item ) { item->setPath(m_paths.value(index)); widget->listCMD->setCurrentItem( item ); if ( ( index == 2 ) && !item->fileName().path().endsWith( QLatin1String(".sh") )) KMessageBox::information( this, i18n( "Only files with “.sh” extensions are allowed for setting up the environment." ) ); } } void Autostart::slotSelectionChanged() { const bool hasItems = ( dynamic_cast( widget->listCMD->currentItem() )!=nullptr ) ; widget->btnRemove->setEnabled(hasItems); const bool isDesktopItem = (dynamic_cast(widget->listCMD->currentItem() ) != nullptr) ; widget->btnProperties->setEnabled(isDesktopItem); widget->btnAdvanced->setEnabled(isDesktopItem) ; } void Autostart::defaults() { } void Autostart::save() { } #include "autostart.moc" diff --git a/kcms/dateandtime/main.cpp b/kcms/dateandtime/main.cpp index 4180448f2..0f862f218 100644 --- a/kcms/dateandtime/main.cpp +++ b/kcms/dateandtime/main.cpp @@ -1,212 +1,212 @@ /* * main.cpp * * Copyright (C) 1998 Luca Montecchiani * Copyright (C) 2015 David Edmundson * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "main.h" #include #include //Added by qt3to4: #include #include #include #include #include #include #include #include "dtime.h" #include "helper.h" #include #include #include "timedated_interface.h" K_PLUGIN_FACTORY(KlockModuleFactory, registerPlugin();) K_EXPORT_PLUGIN(KlockModuleFactory("kcmkclock")) KclockModule::KclockModule(QWidget *parent, const QVariantList &) : KCModule(parent) { auto reply = QDBusConnection::systemBus().call(QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DBus"), QStringLiteral("/org/freedesktop/DBus"), QStringLiteral("org.freedesktop.DBus"), QStringLiteral("ListActivatableNames"))); - if (!reply.arguments().isEmpty() && reply.arguments().first().value().contains(QStringLiteral("org.freedesktop.timedate1"))) { + if (!reply.arguments().isEmpty() && reply.arguments().first().value().contains(QLatin1String("org.freedesktop.timedate1"))) { m_haveTimedated = true; } KAboutData *about = new KAboutData(QStringLiteral("kcmclock"), i18n("KDE Clock Control Module"), QStringLiteral("1.0"), QString(), KAboutLicense::GPL, i18n("(c) 1996 - 2001 Luca Montecchiani")); about->addAuthor(i18n("Luca Montecchiani"), i18n("Original author"), QStringLiteral("m.luca@usa.net")); about->addAuthor(i18n("Paul Campbell"), i18n("Current Maintainer"), QStringLiteral("paul@taniwha.com")); about->addAuthor(i18n("Benjamin Meyer"), i18n("Added NTP support"), QStringLiteral("ben+kcmclock@meyerhome.net")); setAboutData( about ); setQuickHelp( i18n("

Date & Time

This control module can be used to set the system date and" " time. As these settings do not only affect you as a user, but rather the whole system, you" " can only change these settings when you start the System Settings as root. If you do not have" " the root password, but feel the system time should be corrected, please contact your system" " administrator.")); QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(KDialog::spacingHint()); dtime = new Dtime(this, m_haveTimedated); layout->addWidget(dtime); connect(dtime, SIGNAL(timeChanged(bool)), this, SIGNAL(changed(bool))); setButtons(Help|Apply); if (m_haveTimedated) { setAuthAction(KAuth::Action(QStringLiteral("org.freedesktop.timedate1.set-time"))); } else { //auth action name will be automatically guessed from the KCM name qWarning() << "Timedated not found, using legacy saving mode"; setNeedsAuthorization(true); } } bool KclockModule::kauthSave() { QVariantMap helperargs; helperargs[QStringLiteral("ntp")] = true; helperargs[QStringLiteral("ntpServers")] = dtime->ntpServers(); helperargs[QStringLiteral("ntpEnabled")] = dtime->ntpEnabled(); if (!dtime->ntpEnabled()) { QDateTime newTime = dtime->userTime(); qDebug() << "Set date to " << dtime->userTime(); helperargs[QStringLiteral("date")] = true; helperargs[QStringLiteral("newdate")] = QString::number(newTime.toTime_t()); helperargs[QStringLiteral("olddate")] = QString::number(::time(nullptr)); } QString selectedTimeZone = dtime->selectedTimeZone(); if (!selectedTimeZone.isEmpty()) { helperargs[QStringLiteral("tz")] = true; helperargs[QStringLiteral("tzone")] = selectedTimeZone; } else { helperargs[QStringLiteral("tzreset")] = true; // make the helper reset the timezone } Action action = authAction(); action.setArguments(helperargs); ExecuteJob *job = action.execute(); bool rc = job->exec(); if (!rc) { KMessageBox::error(this, i18n("Unable to authenticate/execute the action: %1, %2", job->error(), job->errorString())); } return rc; } bool KclockModule::timedatedSave() { OrgFreedesktopTimedate1Interface timedateIface(QStringLiteral("org.freedesktop.timedate1"), QStringLiteral("/org/freedesktop/timedate1"), QDBusConnection::systemBus()); bool rc = true; //final arg in each method is "user-interaction" i.e whether it's OK for polkit to ask for auth //we cannot send requests up front then block for all replies as we need NTP to be disabled before we can make a call to SetTime //timedated processes these in parallel and will return an error otherwise auto reply = timedateIface.SetNTP(dtime->ntpEnabled(), true); reply.waitForFinished(); if (reply.isError()) { KMessageBox::error(this, i18n("Unable to change NTP settings")); qWarning() << "Failed to enable NTP" << reply.error().name() << reply.error().message(); rc = false; } if (!dtime->ntpEnabled()) { qint64 timeDiff = dtime->userTime().toMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch(); //*1000 for milliseconds -> microseconds auto reply = timedateIface.SetTime(timeDiff * 1000, true, true); reply.waitForFinished(); if (reply.isError()) { KMessageBox::error(this, i18n("Unable to set current time")); qWarning() << "Failed to set current time" << reply.error().name() << reply.error().message(); rc = false; } } QString selectedTimeZone = dtime->selectedTimeZone(); if (!selectedTimeZone.isEmpty()) { auto reply = timedateIface.SetTimezone(selectedTimeZone, true); reply.waitForFinished(); if (reply.isError()) { KMessageBox::error(this, i18n("Unable to set timezone")); qWarning() << "Failed to set timezone" << reply.error().name() << reply.error().message(); rc = false; } } return rc; } void KclockModule::save() { setDisabled(true); bool success = false; if (m_haveTimedated) { success = timedatedSave(); } else { success = kauthSave(); } if (success) { QDBusMessage msg = QDBusMessage::createSignal(QStringLiteral("/org/kde/kcmshell_clock"), QStringLiteral("org.kde.kcmshell_clock"), QStringLiteral("clockUpdated")); QDBusConnection::sessionBus().send(msg); } // NOTE: super nasty hack #1 // Try to work around time mismatch between KSystemTimeZones' update of local // timezone and reloading of data, so that the new timezone is taken into account. // The Ultimate solution to this would be if KSTZ emitted a signal when a new // local timezone was found. // setDisabled(false) happens in load(), since QTimer::singleShot is non-blocking if (!m_haveTimedated) { QTimer::singleShot(5000, this, SLOT(load())); } else { load(); } } void KclockModule::load() { dtime->load(); setDisabled(false); } #include "main.moc" diff --git a/kcms/desktoptheme/kcm.cpp b/kcms/desktoptheme/kcm.cpp index 79483b192..40647b4d3 100644 --- a/kcms/desktoptheme/kcm.cpp +++ b/kcms/desktoptheme/kcm.cpp @@ -1,368 +1,368 @@ /* This file is part of the KDE Project Copyright (c) 2014 Marco Martin Copyright (c) 2014 Vishesh Handa Copyright (c) 2016 David Rosca Copyright (c) 2018 Kai Uwe Broulik This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcm.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_LOGGING_CATEGORY(KCM_DESKTOP_THEME, "kcm_desktoptheme") K_PLUGIN_FACTORY_WITH_JSON(KCMDesktopThemeFactory, "kcm_desktoptheme.json", registerPlugin();) KCMDesktopTheme::KCMDesktopTheme(QObject *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args) , m_defaultTheme(new Plasma::Theme(this)) , m_haveThemeExplorerInstalled(false) { qmlRegisterType(); KAboutData* about = new KAboutData(QStringLiteral("kcm_desktoptheme"), i18n("Plasma Style"), QStringLiteral("0.1"), QString(), KAboutLicense::LGPL); about->addAuthor(i18n("David Rosca"), QString(), QStringLiteral("nowrep@gmail.com")); setAboutData(about); setButtons(Apply | Default | Help); m_model = new QStandardItemModel(this); QHash roles = m_model->roleNames(); roles[PluginNameRole] = QByteArrayLiteral("pluginName"); roles[ThemeNameRole] = QByteArrayLiteral("themeName"); roles[DescriptionRole] = QByteArrayLiteral("description"); roles[IsLocalRole] = QByteArrayLiteral("isLocal"); roles[PendingDeletionRole] = QByteArrayLiteral("pendingDeletion"); m_model->setItemRoleNames(roles); m_haveThemeExplorerInstalled = !QStandardPaths::findExecutable(QStringLiteral("plasmathemeexplorer")).isEmpty(); } KCMDesktopTheme::~KCMDesktopTheme() { delete m_defaultTheme; } QStandardItemModel *KCMDesktopTheme::desktopThemeModel() const { return m_model; } QString KCMDesktopTheme::selectedPlugin() const { return m_selectedPlugin; } void KCMDesktopTheme::setSelectedPlugin(const QString &plugin) { if (m_selectedPlugin == plugin) { return; } m_selectedPlugin = plugin; emit selectedPluginChanged(m_selectedPlugin); emit selectedPluginIndexChanged(); updateNeedsSave(); } int KCMDesktopTheme::selectedPluginIndex() const { const auto results = m_model->match(m_model->index(0, 0), PluginNameRole, m_selectedPlugin); if (results.count() == 1) { return results.first().row(); } return -1; } bool KCMDesktopTheme::downloadingFile() const { return m_tempCopyJob; } void KCMDesktopTheme::setPendingDeletion(int index, bool pending) { QModelIndex idx = m_model->index(index, 0); m_model->setData(idx, pending, PendingDeletionRole); if (pending && selectedPluginIndex() == index) { // move to the next non-pending theme const auto nonPending = m_model->match(idx, PendingDeletionRole, false); setSelectedPlugin(nonPending.first().data(PluginNameRole).toString()); } updateNeedsSave(); } void KCMDesktopTheme::getNewStuff(QQuickItem *ctx) { if (!m_newStuffDialog) { m_newStuffDialog = new KNS3::DownloadDialog(QStringLiteral("plasma-themes.knsrc")); m_newStuffDialog.data()->setWindowTitle(i18n("Download New Plasma Styles")); m_newStuffDialog->setWindowModality(Qt::WindowModal); m_newStuffDialog->winId(); // so it creates the windowHandle(); connect(m_newStuffDialog.data(), &KNS3::DownloadDialog::accepted, this, &KCMDesktopTheme::load); } if (ctx && ctx->window()) { m_newStuffDialog->windowHandle()->setTransientParent(ctx->window()); } m_newStuffDialog.data()->show(); } void KCMDesktopTheme::installThemeFromFile(const QUrl &url) { if (url.isLocalFile()) { installTheme(url.toLocalFile()); return; } if (m_tempCopyJob) { return; } m_tempInstallFile.reset(new QTemporaryFile()); if (!m_tempInstallFile->open()) { emit showErrorMessage(i18n("Unable to create a temporary file.")); m_tempInstallFile.reset(); return; } m_tempCopyJob = KIO::file_copy(url, QUrl::fromLocalFile(m_tempInstallFile->fileName()), -1, KIO::Overwrite); m_tempCopyJob->uiDelegate()->setAutoErrorHandlingEnabled(true); emit downloadingFileChanged(); connect(m_tempCopyJob, &KIO::FileCopyJob::result, this, [this, url](KJob *job) { if (job->error() != KJob::NoError) { emit showErrorMessage(i18n("Unable to download the theme: %1", job->errorText())); return; } installTheme(m_tempInstallFile->fileName()); m_tempInstallFile.reset(); }); connect(m_tempCopyJob, &QObject::destroyed, this, &KCMDesktopTheme::downloadingFileChanged); } void KCMDesktopTheme::installTheme(const QString &path) { qCDebug(KCM_DESKTOP_THEME) << "Installing ... " << path; const QString program = QStringLiteral("kpackagetool5"); const QStringList arguments = { QStringLiteral("--type"), QStringLiteral("Plasma/Theme"), QStringLiteral("--install"), path}; - qCDebug(KCM_DESKTOP_THEME) << program << arguments.join(QStringLiteral(" ")); + qCDebug(KCM_DESKTOP_THEME) << program << arguments.join(QLatin1String(" ")); QProcess *myProcess = new QProcess(this); connect(myProcess, static_cast(&QProcess::finished), this, [this, myProcess](int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitStatus); if (exitCode == 0) { emit showSuccessMessage(i18n("Theme installed successfully.")); load(); } else { Q_EMIT showErrorMessage(i18n("Theme installation failed.")); } }); connect(myProcess, static_cast(&QProcess::error), this, [this](QProcess::ProcessError e) { qCWarning(KCM_DESKTOP_THEME) << "Theme installation failed: " << e; Q_EMIT showErrorMessage(i18n("Theme installation failed.")); }); myProcess->start(program, arguments); } void KCMDesktopTheme::applyPlasmaTheme(QQuickItem *item, const QString &themeName) { if (!item) { return; } Plasma::Theme *theme = m_themes[themeName]; if (!theme) { theme = new Plasma::Theme(themeName, this); m_themes[themeName] = theme; } Q_FOREACH (Plasma::Svg *svg, item->findChildren()) { svg->setTheme(theme); svg->setUsingRenderingCache(false); } } void KCMDesktopTheme::load() { m_pendingRemoval.clear(); // Get all desktop themes QStringList themes; const QStringList &packs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("plasma/desktoptheme"), QStandardPaths::LocateDirectory); Q_FOREACH (const QString &ppath, packs) { const QDir cd(ppath); const QStringList &entries = cd.entryList(QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot); Q_FOREACH (const QString &pack, entries) { const QString _metadata = ppath + QLatin1Char('/') + pack + QStringLiteral("/metadata.desktop"); if (QFile::exists(_metadata)) { themes << _metadata; } } } m_model->clear(); Q_FOREACH (const QString &theme, themes) { int themeSepIndex = theme.lastIndexOf(QLatin1Char('/'), -1); const QString themeRoot = theme.left(themeSepIndex); int themeNameSepIndex = themeRoot.lastIndexOf(QLatin1Char('/'), -1); const QString packageName = themeRoot.right(themeRoot.length() - themeNameSepIndex - 1); KDesktopFile df(theme); if (df.noDisplay()) { continue; } QString name = df.readName(); if (name.isEmpty()) { name = packageName; } const bool isLocal = QFileInfo(theme).isWritable(); if (m_model->findItems(packageName).isEmpty()) { QStandardItem *item = new QStandardItem; item->setText(packageName); item->setData(packageName, PluginNameRole); item->setData(name, ThemeNameRole); item->setData(df.readComment(), DescriptionRole); item->setData(isLocal, IsLocalRole); item->setData(false, PendingDeletionRole); m_model->appendRow(item); } } m_model->setSortRole(ThemeNameRole); // FIXME the model should really be just using Qt::DisplayRole m_model->sort(0 /*column*/); KConfigGroup cg(KSharedConfig::openConfig(QStringLiteral("plasmarc")), "Theme"); setSelectedPlugin(cg.readEntry("name", m_defaultTheme->themeName())); emit selectedPluginIndexChanged(); updateNeedsSave(); } void KCMDesktopTheme::save() { if (m_defaultTheme->themeName() != m_selectedPlugin) { m_defaultTheme->setThemeName(m_selectedPlugin); } processPendingDeletions(); updateNeedsSave(); } void KCMDesktopTheme::defaults() { setSelectedPlugin(QStringLiteral("default")); // can this be done more elegantly? const auto pendingDeletions = m_model->match(m_model->index(0, 0), PendingDeletionRole, true); for (const QModelIndex &idx : pendingDeletions) { m_model->setData(idx, false, PendingDeletionRole); } } bool KCMDesktopTheme::canEditThemes() const { return m_haveThemeExplorerInstalled; } void KCMDesktopTheme::editTheme(const QString &theme) { QProcess::startDetached(QStringLiteral("plasmathemeexplorer -t ") % theme); } void KCMDesktopTheme::updateNeedsSave() { setNeedsSave(!m_model->match(m_model->index(0, 0), PendingDeletionRole, true).isEmpty() || m_selectedPlugin != m_defaultTheme->themeName()); } void KCMDesktopTheme::processPendingDeletions() { const QString program = QStringLiteral("plasmapkg2"); const auto pendingDeletions = m_model->match(m_model->index(0, 0), PendingDeletionRole, true, -1 /*all*/); QVector persistentPendingDeletions; // turn into persistent model index so we can delete as we go std::transform(pendingDeletions.begin(), pendingDeletions.end(), std::back_inserter(persistentPendingDeletions), [](const QModelIndex &idx) { return QPersistentModelIndex(idx); }); for (const QPersistentModelIndex &idx : persistentPendingDeletions) { const QString pluginName = idx.data(PluginNameRole).toString(); const QString displayName = idx.data(Qt::DisplayRole).toString(); Q_ASSERT(pluginName != m_selectedPlugin); const QStringList arguments = {QStringLiteral("-t"), QStringLiteral("theme"), QStringLiteral("-r"), pluginName}; QProcess *process = new QProcess(this); connect(process, static_cast(&QProcess::finished), this, [this, process, idx, pluginName, displayName](int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitStatus); if (exitCode == 0) { m_model->removeRow(idx.row()); } else { emit showErrorMessage(i18n("Removing theme failed: %1", QString::fromLocal8Bit(process->readAllStandardOutput().trimmed()))); m_model->setData(idx, false, PendingDeletionRole); } process->deleteLater(); }); process->start(program, arguments); process->waitForFinished(); // needed so it deletes fine when "OK" is clicked and the dialog destroyed } } #include "kcm.moc" diff --git a/kcms/formats/kcmformats.cpp b/kcms/formats/kcmformats.cpp index 90730f148..78b91fecc 100644 --- a/kcms/formats/kcmformats.cpp +++ b/kcms/formats/kcmformats.cpp @@ -1,360 +1,360 @@ /* * kcmformats.cpp * Copyright 2014 Sebastian Kügler * * 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, write to the Free Software */ // own #include "kcmformats.h" #include "ui_kcmformatswidget.h" #include "writeexports.h" // Qt #include #include #include #include #include #include #include #include // Frameworks #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KCMFormatsFactory, "formats.json", registerPlugin();) KCMFormats::KCMFormats(QWidget *parent, const QVariantList &args) : KCModule(parent, args) { setQuickHelp(i18n("

Formats

" "You can configure the formats used for time, dates, money and other numbers here.")); m_ui = new Ui::KCMFormatsWidget; m_ui->setupUi(this); m_combos << m_ui->comboGlobal << m_ui->comboNumbers << m_ui->comboTime << m_ui->comboCurrency << m_ui->comboMeasurement << m_ui->comboCollate; } KCMFormats::~KCMFormats() { delete m_ui; } bool countryLessThan(const QLocale & c1, const QLocale & c2) { // Ensure that the "Default (C)" locale always appears at the top if (c1.name()==QLatin1String("C") && c2.name()!=QLatin1String("C")) return true; if (c2.name()==QLatin1String("C")) return false; const QString ncn1 = !c1.nativeCountryName().isEmpty() ? c1.nativeCountryName() : QLocale::countryToString(c1.country()); const QString ncn2 = !c2.nativeCountryName().isEmpty() ? c2.nativeCountryName() : QLocale::countryToString(c2.country()); return QString::localeAwareCompare(ncn1, ncn2) < 0; } void KCMFormats::load() { QList allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); std::sort(allLocales.begin(), allLocales.end(), countryLessThan); foreach(QComboBox * combo, m_combos) { initCombo(combo, allLocales); } readConfig(); foreach(QComboBox * combo, m_combos) { connectCombo(combo); } connect(m_ui->checkDetailed, &QAbstractButton::toggled, [ = ]() { updateExample(); updateEnabled(); emit changed(true); }); updateEnabled(); updateExample(); emit changed(false); } void KCMFormats::initCombo(QComboBox *combo, const QList & allLocales) { combo->clear(); const QString clabel = i18n("No change"); combo->addItem(clabel, QString()); foreach(const QLocale & l, allLocales) { addLocaleToCombo(combo, l); } } void KCMFormats::connectCombo(QComboBox *combo) { connect(combo, &QComboBox::currentTextChanged, [ = ]() { emit changed(true); updateExample(); }); } void KCMFormats::addLocaleToCombo(QComboBox *combo, const QLocale &locale) { const QString clabel = !locale.nativeCountryName().isEmpty() ? locale.nativeCountryName() : QLocale::countryToString(locale.country()); // This needs to use name() rather than bcp47name() or later on the export will generate a non-sense locale (e.g. "it" instead of // "it_IT") // TODO: Properly handle scripts (@foo) QString cvalue = locale.name(); - if (!cvalue.contains(QLatin1Char('.')) && cvalue != QStringLiteral("C")) { + if (!cvalue.contains(QLatin1Char('.')) && cvalue != QLatin1Char('C')) { // explicitly add the encoding, // otherwise Qt doesn't accept dead keys and garbles the output as well cvalue.append(QLatin1Char('.') + QTextCodec::codecForLocale()->name()); } QString flagcode; const QStringList split = locale.name().split(QLatin1Char('_')); if (split.count() > 1) { flagcode = split[1].toLower(); } QIcon flagIcon = loadFlagIcon(flagcode); const QString nativeLangName = locale.nativeLanguageName(); if (!nativeLangName.isEmpty()) { combo->addItem(flagIcon, i18n("%1 - %2 (%3)", clabel, nativeLangName, locale.name()), cvalue); } else { combo->addItem(flagIcon, i18n("%1 (%2)", clabel, locale.name()), cvalue); } } void setCombo(QComboBox *combo, const QString &key) { const int ix = combo->findData(key); if (ix > -1) { combo->setCurrentIndex(ix); } } QIcon KCMFormats::loadFlagIcon(const QString &flagCode) { QIcon icon = m_cachedFlags.value(flagCode); if (!icon.isNull()) { return icon; } QString flag(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/locale/countries/%1/flag.png").arg(flagCode))); if (!flag.isEmpty()) { icon = QIcon(flag); } else { if (m_cachedUnknown.isNull()) { m_cachedUnknown = QIcon::fromTheme("unknown"); } icon = m_cachedUnknown; } m_cachedFlags.insert(flagCode, icon); return icon; } void KCMFormats::readConfig() { m_config = KConfigGroup(KSharedConfig::openConfig(configFile), "Formats"); bool useDetailed = m_config.readEntry("useDetailed", false); m_ui->checkDetailed->setChecked(useDetailed); setCombo(m_ui->comboGlobal, m_config.readEntry(lcLang, qgetenv(lcLang.toLatin1()))); setCombo(m_ui->comboNumbers, m_config.readEntry(lcNumeric, qgetenv(lcNumeric.toLatin1()))); setCombo(m_ui->comboTime, m_config.readEntry(lcTime, qgetenv(lcTime.toLatin1()))); setCombo(m_ui->comboCollate, m_config.readEntry(lcCollate, qgetenv(lcCollate.toLatin1()))); setCombo(m_ui->comboCurrency, m_config.readEntry(lcMonetary, qgetenv(lcMonetary.toLatin1()))); setCombo(m_ui->comboMeasurement, m_config.readEntry(lcMeasurement, qgetenv(lcMeasurement.toLatin1()))); updateEnabled(); } void KCMFormats::writeConfig() { m_config = KConfigGroup(KSharedConfig::openConfig(configFile), "Formats"); // global ends up empty here when OK button is clicked from kcmshell5, // apparently the data in the combo is gone by the time save() is called. // This might be a problem in KCModule, but does not directly affect us // since within systemsettings, it works fine. // See https://bugs.kde.org/show_bug.cgi?id=334624 if (m_ui->comboGlobal->count() == 0) { qWarning() << "Couldn't read data from UI, writing configuration failed."; return; } const QString global = m_ui->comboGlobal->currentData().toString(); if (!m_ui->checkDetailed->isChecked()) { // Global setting, clean up config m_config.deleteEntry("useDetailed"); if (global.isEmpty()) { m_config.deleteEntry(lcLang); } else { m_config.writeEntry(lcLang, global); } m_config.deleteEntry(lcNumeric); m_config.deleteEntry(lcTime); m_config.deleteEntry(lcMonetary); m_config.deleteEntry(lcMeasurement); m_config.deleteEntry(lcCollate); m_config.deleteEntry(lcCtype); } else { // Save detailed settings m_config.writeEntry("useDetailed", true); if (global.isEmpty()) { m_config.deleteEntry(lcLang); } else { m_config.writeEntry(lcLang, global); } const QString numeric = m_ui->comboNumbers->currentData().toString(); if (numeric.isEmpty()) { m_config.deleteEntry(lcNumeric); } else { m_config.writeEntry(lcNumeric, numeric); } const QString time = m_ui->comboTime->currentData().toString(); if (time.isEmpty()) { m_config.deleteEntry(lcTime); } else { m_config.writeEntry(lcTime, time); } const QString monetary = m_ui->comboCurrency->currentData().toString(); if (monetary.isEmpty()) { m_config.deleteEntry(lcMonetary); } else { m_config.writeEntry(lcMonetary, monetary); } const QString measurement = m_ui->comboMeasurement->currentData().toString(); if (measurement.isEmpty()) { m_config.deleteEntry(lcMeasurement); } else { m_config.writeEntry(lcMeasurement, measurement); } const QString collate = m_ui->comboCollate->currentData().toString(); if (collate.isEmpty()) { m_config.deleteEntry(lcCollate); } else { m_config.writeEntry(lcCollate, collate); } } m_config.sync(); } void KCMFormats::save() { writeConfig(); writeExports(); KMessageBox::information(this, i18n("Your changes will take effect the next time you log in."), i18n("Format Settings Changed"), QStringLiteral("FormatSettingsChanged")); } void KCMFormats::defaults() { m_ui->checkDetailed->setChecked(false); // restore user defaults from env vars setCombo(m_ui->comboGlobal, qgetenv(lcLang.toLatin1())); setCombo(m_ui->comboNumbers, qgetenv(lcNumeric.toLatin1())); setCombo(m_ui->comboTime, qgetenv(lcTime.toLatin1())); setCombo(m_ui->comboCollate, qgetenv(lcCollate.toLatin1())); setCombo(m_ui->comboCurrency, qgetenv(lcMonetary.toLatin1())); setCombo(m_ui->comboMeasurement, qgetenv(lcMeasurement.toLatin1())); updateEnabled(); } void KCMFormats::updateEnabled() { const bool enabled = m_ui->checkDetailed->isChecked(); m_ui->labelNumbers->setEnabled(enabled); m_ui->labelTime->setEnabled(enabled); m_ui->labelCurrency->setEnabled(enabled); m_ui->labelMeasurement->setEnabled(enabled); m_ui->labelCollate->setEnabled(enabled); m_ui->comboNumbers->setEnabled(enabled); m_ui->comboTime->setEnabled(enabled); m_ui->comboCurrency->setEnabled(enabled); m_ui->comboMeasurement->setEnabled(enabled); m_ui->comboCollate->setEnabled(enabled); } void KCMFormats::updateExample() { const bool useDetailed = m_ui->checkDetailed->isChecked(); QLocale nloc; QLocale tloc; QLocale cloc; QLocale mloc; QString str; QString glob = m_ui->comboGlobal->currentData().toString(); if (useDetailed) { str = m_ui->comboNumbers->currentData().toString(); nloc = str.isEmpty() ? QLocale(glob) : QLocale(str); str = m_ui->comboTime->currentData().toString(); tloc = str.isEmpty() ? QLocale(glob) : QLocale(str); str = m_ui->comboCurrency->currentData().toString(); cloc = str.isEmpty() ? QLocale(glob) : QLocale(str); str = m_ui->comboMeasurement->currentData().toString(); mloc = str.isEmpty() ? QLocale(glob) : QLocale(str); } else { nloc = QLocale(glob); tloc = QLocale(glob); cloc = QLocale(glob); mloc = QLocale(glob); } const QString numberExample = nloc.toString(1000.01); const QString timeExample = i18n("%1 (long format)", tloc.toString(QDateTime::currentDateTime())) + QStringLiteral("\n") + i18n("%1 (short format)", tloc.toString(QDateTime::currentDateTime(), QLocale::ShortFormat)); const QString currencyExample = cloc.toCurrencyString(24.00); QString measurementSetting; if (mloc.measurementSystem() == QLocale::ImperialUKSystem) { measurementSetting = i18nc("Measurement combobox", "Imperial UK"); } else if (mloc.measurementSystem() == QLocale::ImperialUSSystem || mloc.measurementSystem() == QLocale::ImperialSystem) { measurementSetting = i18nc("Measurement combobox", "Imperial US"); } else { measurementSetting = i18nc("Measurement combobox", "Metric"); } m_ui->exampleNumbers->setText(numberExample); m_ui->exampleTime->setText(timeExample); m_ui->exampleCurrency->setText(currencyExample); m_ui->exampleMeasurement->setText(measurementSetting); } #include "kcmformats.moc" diff --git a/kcms/hardware/joystick/joywidget.cpp b/kcms/hardware/joystick/joywidget.cpp index 3cb59653e..a5af1bd4d 100644 --- a/kcms/hardware/joystick/joywidget.cpp +++ b/kcms/hardware/joystick/joywidget.cpp @@ -1,417 +1,417 @@ /*************************************************************************** * Copyright (C) 2003,2012 by Martin Koller * * kollix@aon.at * * This file is part of the KDE Control Center Module for Joysticks * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "joywidget.h" #include "joydevice.h" #include "poswidget.h" #include "caldialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //-------------------------------------------------------------- static QString PRESSED = I18N_NOOP("PRESSED"); //-------------------------------------------------------------- class TableWidget : public QTableWidget { public: TableWidget(int row, int col) : QTableWidget(row, col) {} QSize sizeHint() const override { return QSize(150, 100); // return a smaller size than the Qt default(256, 192) } }; //-------------------------------------------------------------- JoyWidget::JoyWidget(QWidget *parent) : QWidget(parent), idle(nullptr), joydev(nullptr) { QVBoxLayout *mainVbox = new QVBoxLayout(this); mainVbox->setSpacing(KDialog::spacingHint()); mainVbox->setContentsMargins(0, 0, 0, 0); // create area to show an icon + message if no joystick was detected { messageBox = new KMessageWidget(this); messageBox->setMessageType(KMessageWidget::Error); messageBox->setCloseButtonVisible(false); messageBox->hide(); mainVbox->addWidget(messageBox); } QHBoxLayout *devHbox = new QHBoxLayout; devHbox->setSpacing(KDialog::spacingHint()); devHbox->addWidget(new QLabel(i18n("Device:"))); devHbox->addWidget(device = new KComboBox(true)); device->setInsertPolicy(QComboBox::NoInsert); KUrlCompletion *kc = new KUrlCompletion(KUrlCompletion::FileCompletion); device->setCompletionObject(kc); device->setAutoDeleteCompletionObject(true); connect(device, SIGNAL(activated(QString)), this, SLOT(deviceChanged(QString))); connect(device, SIGNAL(returnPressed(QString)), this, SLOT(deviceChanged(QString))); devHbox->setStretchFactor(device, 3); QHBoxLayout *hbox = new QHBoxLayout; hbox->setSpacing(KDialog::spacingHint()); mainVbox->addLayout(devHbox); mainVbox->addLayout(hbox); QVBoxLayout *vboxLeft = new QVBoxLayout; vboxLeft->setSpacing(KDialog::spacingHint()); vboxLeft->addWidget(new QLabel(i18nc("Cue for deflection of the stick", "Position:"))); vboxLeft->addWidget(xyPos = new PosWidget); vboxLeft->addWidget(trace = new QCheckBox(i18n("Show trace"))); connect(trace, &QAbstractButton::toggled, this, &JoyWidget::traceChanged); QVBoxLayout *vboxMid = new QVBoxLayout; vboxMid->setSpacing(KDialog::spacingHint()); QVBoxLayout *vboxRight = new QVBoxLayout; vboxRight->setSpacing(KDialog::spacingHint()); // calculate the column width we need QFontMetrics fm(font()); int colWidth = qMax(fm.width(PRESSED), fm.width(QStringLiteral("-32767"))) + 10; // -32767 largest string vboxMid->addWidget(new QLabel(i18n("Buttons:"))); buttonTbl = new TableWidget(0, 1); buttonTbl->setSelectionMode(QAbstractItemView::NoSelection); buttonTbl->setEditTriggers(QAbstractItemView::NoEditTriggers); buttonTbl->setHorizontalHeaderLabels(QStringList(i18n("State"))); buttonTbl->setSortingEnabled(false); buttonTbl->horizontalHeader()->setSectionsClickable(false); buttonTbl->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); buttonTbl->horizontalHeader()->resizeSection(0, colWidth); buttonTbl->verticalHeader()->setSectionsClickable(false); vboxMid->addWidget(buttonTbl); vboxRight->addWidget(new QLabel(i18n("Axes:"))); axesTbl = new TableWidget(0, 1); axesTbl->setSelectionMode(QAbstractItemView::NoSelection); axesTbl->setEditTriggers(QAbstractItemView::NoEditTriggers); axesTbl->setHorizontalHeaderLabels(QStringList(i18n("Value"))); axesTbl->setSortingEnabled(false); axesTbl->horizontalHeader()->setSectionsClickable(false); axesTbl->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); axesTbl->horizontalHeader()->resizeSection(0, colWidth); axesTbl->verticalHeader()->setSectionsClickable(false); vboxRight->addWidget(axesTbl); hbox->addLayout(vboxLeft); hbox->addLayout(vboxMid); hbox->addLayout(vboxRight); // calibrate button calibrate = new QPushButton(i18n("Calibrate")); connect(calibrate, &QAbstractButton::clicked, this, &JoyWidget::calibrateDevice); calibrate->setEnabled(false); vboxLeft->addStretch(); vboxLeft->addWidget(calibrate); // set up a timer for idle processing of joystick events idle = new QTimer(this); connect(idle, &QTimer::timeout, this, &JoyWidget::checkDevice); // check which devicefiles we have init(); } //-------------------------------------------------------------- JoyWidget::~JoyWidget() { delete joydev; } //-------------------------------------------------------------- void JoyWidget::init() { // check which devicefiles we have int i; bool first = true; char dev[30]; device->clear(); buttonTbl->setRowCount(0); axesTbl->setRowCount(0); for (i = 0; i < 5; i++) // check the first 5 devices { sprintf(dev, "/dev/js%d", i); // first look in /dev JoyDevice *joy = new JoyDevice(dev); if ( joy->open() != JoyDevice::SUCCESS ) { delete joy; sprintf(dev, "/dev/input/js%d", i); // then look in /dev/input joy = new JoyDevice(dev); if ( joy->open() != JoyDevice::SUCCESS ) { delete joy; continue; // try next number } } // we found one device->addItem(QStringLiteral("%1 (%2)").arg(joy->text()).arg(joy->device())); // display values for first device if ( first ) { showDeviceProps(joy); // this sets the joy object into this->joydev first = false; } else delete joy; } /* KDE 4: Remove this check(and i18n) when all KCM wrappers properly test modules */ if ( device->count() == 0 ) { messageBox->show(); messageBox->setText(QStringLiteral("%1").arg( i18n("No joystick device automatically found on this computer.
" "Checks were done in /dev/js[0-4] and /dev/input/js[0-4]
" "If you know that there is one attached, please enter the correct device file."))); } } //-------------------------------------------------------------- void JoyWidget::traceChanged(bool state) { xyPos->showTrace(state); } //-------------------------------------------------------------- void JoyWidget::restoreCurrDev() { if ( !joydev ) // no device open { device->setEditText(QLatin1String("")); calibrate->setEnabled(false); } else { // try to find the current open device in the combobox list int index = device->findText(joydev->device(), Qt::MatchContains); if ( index == -1 ) // the current open device is one the user entered (not in the list) device->setEditText(joydev->device()); else device->setEditText(device->itemText(index)); } } //-------------------------------------------------------------- void JoyWidget::deviceChanged(const QString &dev) { // find "/dev" in given string int start, stop; QString devName; - if ( (start = dev.indexOf(QStringLiteral("/dev"))) == -1 ) + if ( (start = dev.indexOf(QLatin1String("/dev"))) == -1 ) { KMessageBox::sorry(this, i18n("The given device name is invalid (does not contain /dev).\n" "Please select a device from the list or\n" "enter a device file, like /dev/js0."), i18n("Unknown Device")); restoreCurrDev(); return; } - if ( (stop = dev.indexOf(QStringLiteral(")"), start)) != -1 ) // seems to be text selected from our list + if ( (stop = dev.indexOf(QLatin1String(")"), start)) != -1 ) // seems to be text selected from our list devName = dev.mid(start, stop - start); else devName = dev.mid(start); if ( joydev && (devName == joydev->device()) ) return; // user selected the current device; ignore it JoyDevice *joy = new JoyDevice(devName); JoyDevice::ErrorCode ret = joy->open(); if ( ret != JoyDevice::SUCCESS ) { KMessageBox::error(this, joy->errText(ret), i18n("Device Error")); delete joy; restoreCurrDev(); return; } showDeviceProps(joy); } //-------------------------------------------------------------- void JoyWidget::showDeviceProps(JoyDevice *joy) { joydev = joy; buttonTbl->setRowCount(joydev->numButtons()); axesTbl->setRowCount(joydev->numAxes()); if ( joydev->numAxes() >= 2 ) { axesTbl->setVerticalHeaderItem(0, new QTableWidgetItem(i18n("1(x)"))); axesTbl->setVerticalHeaderItem(1, new QTableWidgetItem(i18n("2(y)"))); } calibrate->setEnabled(true); idle->start(0); // make both tables use the same space for header; this looks nicer // TODO: Don't know how to do this in Qt4; the following does no longer work // Probably by setting a sizeHint for every single header item ? /* buttonTbl->verticalHeader()->setFixedWidth(qMax(buttonTbl->verticalHeader()->width(), axesTbl->verticalHeader()->width())); axesTbl->verticalHeader()->setFixedWidth(buttonTbl->verticalHeader()->width()); */ } //-------------------------------------------------------------- void JoyWidget::checkDevice() { if ( !joydev ) return; // no open device yet JoyDevice::EventType type; int number, value; if ( !joydev->getEvent(type, number, value) ) return; if ( type == JoyDevice::BUTTON ) { if ( ! buttonTbl->item(number, 0) ) buttonTbl->setItem(number, 0, new QTableWidgetItem()); if ( value == 0 ) // button release buttonTbl->item(number, 0)->setText(QStringLiteral("-")); else buttonTbl->item(number, 0)->setText(PRESSED); } if ( type == JoyDevice::AXIS ) { if ( number == 0 ) // x-axis xyPos->changeX(value); if ( number == 1 ) // y-axis xyPos->changeY(value); if ( ! axesTbl->item(number, 0) ) axesTbl->setItem(number, 0, new QTableWidgetItem()); axesTbl->item(number, 0)->setText(QStringLiteral("%1").arg(int(value))); } } //-------------------------------------------------------------- void JoyWidget::calibrateDevice() { if ( !joydev ) return; // just to be save JoyDevice::ErrorCode ret = joydev->initCalibration(); if ( ret != JoyDevice::SUCCESS ) { KMessageBox::error(this, joydev->errText(ret), i18n("Communication Error")); return; } if ( KMessageBox::messageBox(this, KMessageBox::Information, i18n("Calibration is about to check the precision.

" "Please move all axes to their center position and then " "do not touch the joystick anymore.

" "Click OK to start the calibration.
"), i18n("Calibration"), KStandardGuiItem::ok(), KStandardGuiItem::cancel()) != KMessageBox::Ok ) return; idle->stop(); // stop the joystick event getting; this must be done inside the calibrate dialog CalDialog dlg(this, joydev); dlg.calibrate(); // user canceled somewhere during calibration, therefore the device is in a bad state if ( dlg.result() == QDialog::Rejected ) joydev->restoreCorr(); idle->start(0); // continue with event getting } //-------------------------------------------------------------- void JoyWidget::resetCalibration() { if ( !joydev ) return; // just to be save JoyDevice::ErrorCode ret = joydev->restoreCorr(); if ( ret != JoyDevice::SUCCESS ) { KMessageBox::error(this, joydev->errText(ret), i18n("Communication Error")); } else { KMessageBox::information(this, i18n("Restored all calibration values for joystick device %1.", joydev->device()), i18n("Calibration Success")); } } //-------------------------------------------------------------- diff --git a/kcms/keyboard/preview/geometry_parser.cpp b/kcms/keyboard/preview/geometry_parser.cpp index 36246ec02..068a7b7d6 100644 --- a/kcms/keyboard/preview/geometry_parser.cpp +++ b/kcms/keyboard/preview/geometry_parser.cpp @@ -1,593 +1,593 @@ /* * Copyright (C) 2013 Shivam Makkar (amourphious1992@gmail.com) * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "geometry_parser.h" #include "geometry_components.h" #include "xkb_rules.h" #include #include #include #include #include #include #include namespace grammar { keywords::keywords() { add ("shape", 1) ("height", 2) ("width", 3) ("description", 4) ("keys", 5) ("row", 6) ("section", 7) ("key", 8) ("//", 9) ("/*", 10) ; } template GeometryParser::GeometryParser(): GeometryParser::base_type(start) { using qi::lexeme; using qi::char_; using qi::lit; using qi::_1; using qi::_val; using qi::int_; using qi::double_; using qi::eol; name = '"' >> +(char_ - '"') >> '"'; ignore = (lit("outline") || lit("overlay") || lit("text")) >> *(char_ - lit("};")) >> lit("};") || lit("solid") >> *(char_ - lit("};")) >> lit("};") || lit("indicator") >> *(char_ - ';' - '{') >> ';' || '{' >> *(char_ - lit("};")) >> lit("};") || lit("indicator") >> '.' >> lit("shape") >> '=' >> name >> ';'; comments = lexeme[ lit("//") >> *(char_ - eol || keyword - eol) >> eol || lit("/*") >> *(char_ - lit("*/") || keyword - lit("*/")) >> lit("*/") ]; cordinates = ('[' >> double_[phx::ref(shapeLenX) = _1] >> ',' >> double_[phx::ref(shapeLenY) = _1] >> ']') || '[' >> double_ >> "," >> double_ >> ']' ; cordinatea = '[' >> double_[phx::ref(approxLenX) = _1] >> "," >> double_[phx::ref(approxLenY) = _1] >> ']'; set = '{' >> cordinates >> *(',' >> cordinates) >> '}'; setap = '{' >> cordinatea >> *(',' >> cordinatea) >> '}'; seta = '{' >> cordinates[phx::bind(&GeometryParser::setCord, this)] >> *(',' >> cordinates[phx::bind(&GeometryParser::setCord, this)]) >> '}' ; description = lit("description") >> '=' >> name[phx::bind(&GeometryParser::getDescription, this, _1)] >> ';'; cornerRadius = (lit("cornerRadius") || lit("corner")) >> '=' >> double_; shapeDef = lit("shape") >> name[phx::bind(&GeometryParser::getShapeName, this, _1)] >> '{' >> *(lit("approx") >> '=' >> setap[phx::bind(&GeometryParser::setApprox, this)] >> ',' || cornerRadius >> ',' || comments) >> seta >> *((',' >> (set || lit("approx") >> '=' >> setap[phx::bind(&GeometryParser::setApprox, this)] || cornerRadius) || comments)) >> lit("};") ; keyName = '<' >> +(char_ - '>') >> '>'; keyShape = *(lit("key.")) >> lit("shape") >> '=' >> name[phx::bind(&GeometryParser::setKeyShape, this, _1)] || name[phx::bind(&GeometryParser::setKeyShape, this, _1)]; keyColor = lit("color") >> '=' >> name; keygap = lit("gap") >> '=' >> double_[phx::ref(KeyOffset) = _1] || double_[phx::ref(KeyOffset) = _1]; keyDesc = keyName[phx::bind(&GeometryParser::setKeyNameandShape, this, _1)] || '{' >> (keyName[phx::bind(&GeometryParser::setKeyNameandShape, this, _1)] || keyShape || keygap[phx::bind(&GeometryParser::setKeyOffset, this)] || keyColor) >> *((',' >> (keyName || keyShape || keygap[phx::bind(&GeometryParser::setKeyOffset, this)] || keyColor)) || comments) >> '}'; keys = lit("keys") >> '{' >> keyDesc[phx::bind(&GeometryParser::setKeyCordi, this)] >> *((*lit(',') >> keyDesc[phx::bind(&GeometryParser::setKeyCordi, this)] >> *lit(',')) || comments) >> lit("};"); geomShape = ((lit("key.shape") >> '=' >> name[phx::bind(&GeometryParser::setGeomShape, this, _1)]) || (lit("key.color") >> '=' >> name)) >> ';'; geomLeft = lit("section.left") >> '=' >> double_[phx::ref(geom.sectionLeft) = _1] >> ';'; geomTop = lit("section.top") >> '=' >> double_[phx::ref(geom.sectionTop) = _1] >> ';'; geomRowTop = lit("row.top") >> '=' >> double_[phx::ref(geom.rowTop) = _1] >> ';'; geomRowLeft = lit("row.left") >> '=' >> double_[phx::ref(geom.rowLeft) = _1] >> ';'; geomGap = lit("key.gap") >> '=' >> double_[phx::ref(geom.keyGap) = _1] >> ';'; geomVertical = *lit("row.") >> lit("vertical") >> '=' >> (lit("True") || lit("true")) >> ';'; geomAtt = geomLeft || geomTop || geomRowTop || geomRowLeft || geomGap; top = lit("top") >> '=' >> double_ >> ';'; left = lit("left") >> '=' >> double_ >> ';'; row = lit("row")[phx::bind(&GeometryParser::rowinit, this)] >> '{' >> *(top[phx::bind(&GeometryParser::setRowTop, this, _1)] || left[phx::bind(&GeometryParser::setRowLeft, this, _1)] || localShape[phx::bind(&GeometryParser::setRowShape, this, _1)] || localColor || comments || geomVertical[phx::bind(&GeometryParser::setVerticalRow, this)] || keys ) >> lit("};") || ignore || geomVertical[phx::bind(&GeometryParser::setVerticalSection, this)]; angle = lit("angle") >> '=' >> double_ >> ';'; localShape = lit("key.shape") >> '=' >> name[_val = _1] >> ';'; localColor = lit("key.color") >> '=' >> name >> ';'; localDimension = (lit("height") || lit("width")) >> '=' >> double_ >> ';'; priority = lit("priority") >> '=' >> double_ >> ';'; section = lit("section")[phx::bind(&GeometryParser::sectioninit, this)] >> name[phx::bind(&GeometryParser::sectionName, this, _1)] >> '{' >> *(top[phx::bind(&GeometryParser::setSectionTop, this, _1)] || left[phx::bind(&GeometryParser::setSectionLeft, this, _1)] || angle[phx::bind(&GeometryParser::setSectionAngle, this, _1)] || row[phx::bind(&GeometryParser::addRow, this)] || localShape[phx::bind(&GeometryParser::setSectionShape, this, _1)] || geomAtt || localColor || localDimension || priority || comments) >> lit("};") || geomVertical[phx::bind(&GeometryParser::setVerticalGeometry, this)]; shapeC = lit("shape") >> '.' >> cornerRadius >> ';'; shape = shapeDef || shapeC; input = '{' >> +(width || height || comments || ignore || description || (char_ - keyword - '}' || shape[phx::bind(&Geometry::addShape, &geom)] || section[phx::bind(&Geometry::addSection, &geom)] || geomAtt || geomShape )) >> '}'; width = lit("width") >> '=' >> double_[phx::bind(&Geometry::setWidth, &geom, _1)] >> ";"; height = lit("height") >> '=' >> double_[phx::bind(&Geometry::setHeight, &geom, _1)] >> ";"; start %= *(lit("default")) >> lit("xkb_geometry") >> name[phx::bind(&GeometryParser::getName, this, _1)] >> input >> ';' >> *(comments || char_ - lit("xkb_geometry")); } template void GeometryParser::setCord() { geom.setShapeCord(shapeLenX, shapeLenY); } template void GeometryParser::setSectionShape(std::string n) { geom.sectionList[geom.getSectionCount()].setShapeName(QString::fromUtf8(n.data(), n.size())); } template void GeometryParser::getName(std::string n) { geom.setName(QString::fromUtf8(n.data(), n.size())); } template void GeometryParser::getDescription(std::string n) { geom.setDescription(QString::fromUtf8(n.data(), n.size())); } template void GeometryParser::getShapeName(std::string n) { geom.setShapeName(QString::fromUtf8(n.data(), n.size())); } template void GeometryParser::setGeomShape(std::string n) { geom.setKeyShape(QString::fromUtf8(n.data(), n.size())); } template void GeometryParser::setRowShape(std::string n) { int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); geom.sectionList[secn].rowList[rown].setShapeName(QString::fromUtf8(n.data(), n.size())); } template void GeometryParser::setApprox() { geom.setShapeApprox(approxLenX, approxLenY); } template void GeometryParser::addRow() { geom.sectionList[geom.getSectionCount()].addRow(); } template void GeometryParser::sectionName(std::string n) { geom.sectionList[geom.getSectionCount()].setName(QString::fromUtf8(n.data(), n.size())); } template void GeometryParser::rowinit() { int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); double tempTop = geom.sectionList[secn].getTop(); QString tempShape = geom.sectionList[secn].getShapeName(); geom.sectionList[secn].rowList[rown].setTop(tempTop); geom.sectionList[secn].rowList[rown].setLeft(geom.sectionList[secn].getLeft()); geom.sectionList[secn].rowList[rown].setShapeName(tempShape); keyCordiX = geom.sectionList[secn].rowList[rown].getLeft(); keyCordiY = geom.sectionList[secn].rowList[rown].getTop(); tempTop = geom.sectionList[secn].getVertical(); geom.sectionList[secn].rowList[rown].setVertical(tempTop); } template void GeometryParser::sectioninit() { int secn = geom.getSectionCount(); geom.sectionList[secn].setTop(geom.sectionTop); geom.sectionList[secn].setLeft(geom.sectionLeft); keyCordiX = geom.sectionList[secn].getLeft(); keyCordiY = geom.sectionList[secn].getTop(); geom.sectionList[secn].setShapeName(geom.getKeyShape()); geom.sectionList[secn].setVertical(geom.getVertical()); } template void GeometryParser::setRowTop(double a) { int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); double tempTop = geom.sectionList[secn].getTop(); geom.sectionList[secn].rowList[rown].setTop(a + tempTop); keyCordiY = geom.sectionList[secn].rowList[rown].getTop(); } template void GeometryParser::setRowLeft(double a) { int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); double tempLeft = geom.sectionList[secn].getLeft(); geom.sectionList[secn].rowList[rown].setLeft(a + tempLeft); keyCordiX = geom.sectionList[secn].rowList[rown].getLeft(); } template void GeometryParser::setSectionTop(double a) { //qCDebug(KEYBOARD_PREVIEW) << "\nsectionCount" << geom.sectionCount; int secn = geom.getSectionCount(); geom.sectionList[secn].setTop(a + geom.sectionTop); keyCordiY = geom.sectionList[secn].getTop(); } template void GeometryParser::setSectionLeft(double a) { //qCDebug(KEYBOARD_PREVIEW) << "\nsectionCount" << geom.sectionCount; int secn = geom.getSectionCount(); geom.sectionList[secn].setLeft(a + geom.sectionLeft); keyCordiX = geom.sectionList[secn].getLeft(); } template void GeometryParser::setSectionAngle(double a) { //qCDebug(KEYBOARD_PREVIEW) << "\nsectionCount" << geom.sectionCount; int secn = geom.getSectionCount(); geom.sectionList[secn].setAngle(a); } template void GeometryParser::setVerticalRow() { int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); geom.sectionList[secn].rowList[rown].setVertical(1); } template void GeometryParser::setVerticalSection() { int secn = geom.getSectionCount(); geom.sectionList[secn].setVertical(1); } template void GeometryParser::setVerticalGeometry() { geom.setVertical(1); } template void GeometryParser::setKeyName(std::string n) { int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); int keyn = geom.sectionList[secn].rowList[rown].getKeyCount(); //qCDebug(KEYBOARD_PREVIEW) << "\nsC: " << secn << "\trC: " << rown << "\tkn: " << keyn; geom.sectionList[secn].rowList[rown].keyList[keyn].setKeyName(QString::fromUtf8(n.data(), n.size())); } template void GeometryParser::setKeyShape(std::string n) { int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); int keyn = geom.sectionList[secn].rowList[rown].getKeyCount(); //qCDebug(KEYBOARD_PREVIEW) << "\nsC: " << secn << "\trC: " << rown << "\tkn: " << keyn; geom.sectionList[secn].rowList[rown].keyList[keyn].setShapeName(QString::fromUtf8(n.data(), n.size())); } template void GeometryParser::setKeyNameandShape(std::string n) { int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); setKeyName(n); setKeyShape(geom.sectionList[secn].rowList[rown].getShapeName().toUtf8().constData()); } template void GeometryParser::setKeyOffset() { //qCDebug(KEYBOARD_PREVIEW) << "\nhere\n"; int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); int keyn = geom.sectionList[secn].rowList[rown].getKeyCount(); //qCDebug(KEYBOARD_PREVIEW) << "\nsC: " << secn << "\trC: " << rown << "\tkn: " << keyn; geom.sectionList[secn].rowList[rown].keyList[keyn].setOffset(KeyOffset); } template void GeometryParser::setKeyCordi() { int secn = geom.getSectionCount(); int rown = geom.sectionList[secn].getRowCount(); int keyn = geom.sectionList[secn].rowList[rown].getKeyCount(); int vertical = geom.sectionList[secn].rowList[rown].getVertical(); Key key = geom.sectionList[secn].rowList[rown].keyList[keyn]; if (vertical == 0) { keyCordiX += key.getOffset(); } else { keyCordiY += key.getOffset(); } geom.sectionList[secn].rowList[rown].keyList[keyn].setKeyPosition(keyCordiX, keyCordiY); QString shapeStr = key.getShapeName(); if (shapeStr.isEmpty()) { shapeStr = geom.getKeyShape(); } GShape shapeObj = geom.findShape(shapeStr); int a = shapeObj.size(vertical); if (vertical == 0) { keyCordiX += a + geom.keyGap; } else { keyCordiY += a + geom.keyGap; } geom.sectionList[secn].rowList[rown].addKey(); } Geometry parseGeometry(const QString &model) { using boost::spirit::iso8859_1::space; typedef std::string::const_iterator iterator_type; typedef grammar::GeometryParser GeometryParser; GeometryParser geometryParser; Rules::GeometryId geoId = Rules::getGeometryId(model); QString geometryFile = geoId.fileName; QString geometryName = geoId.geoName; qCDebug(KEYBOARD_PREVIEW) << "looking for model" << model << "geometryName" << geometryName << "in" << geometryFile; QString input = getGeometry(geometryFile, geometryName); if (! input.isEmpty()) { geometryParser.geom = Geometry(); input = includeGeometry(input); std::string parserInput = input.toUtf8().constData(); std::string::const_iterator iter = parserInput.begin(); std::string::const_iterator end = parserInput.end(); bool success = phrase_parse(iter, end, geometryParser, space); if (success && iter == end) { // qCDebug(KEYBOARD_PREVIEW) << "Geometry parsing succeeded for" << input.left(20); geometryParser.geom.setParsing(true); return geometryParser.geom; } else { qCritical() << "Geometry parsing failed for\n\t" << input.left(30); geometryParser.geom.setParsing(false); } } if (geometryParser.geom.getParsing()) { return geometryParser.geom; } qCritical() << "Failed to get geometry" << geometryParser.geom.getName() << "falling back to pc104"; return parseGeometry(QStringLiteral("pc104")); } QString includeGeometry(QString geometry) { QStringList lines = geometry.split(QStringLiteral("\n")); int includeLine = -1; QString includeLineStr; QString startLine = lines[0]; for (int i = 0; i < lines.size(); i++) { includeLineStr = lines[i]; - lines[i] = lines[i].remove(QStringLiteral(" ")); - lines[i] = lines[i].remove(QStringLiteral("\r")); + lines[i].remove(QStringLiteral(" ")); + lines[i].remove(QStringLiteral("\r")); if (lines[i].startsWith(QLatin1String("include"))) { includeLine = i; break; } } if (includeLine == -1) { return geometry; } - geometry = geometry.remove(includeLineStr); - lines[includeLine] = lines[includeLine].remove(QStringLiteral("include")); - lines[includeLine] = lines[includeLine].remove(QStringLiteral("\"")); - lines[includeLine] = lines[includeLine].remove(QStringLiteral(")")); - if (lines[includeLine].contains(QStringLiteral("("))) { + geometry.remove(includeLineStr); + lines[includeLine].remove(QStringLiteral("include")); + lines[includeLine].remove(QStringLiteral("\"")); + lines[includeLine].remove(QStringLiteral(")")); + if (lines[includeLine].contains(QLatin1String("("))) { QString includeFile = lines[includeLine].split(QStringLiteral("("))[0]; QString includeGeom = lines[includeLine].split(QStringLiteral("("))[1]; qCDebug(KEYBOARD_PREVIEW) << "looking to include " << "geometryName" << includeGeom << "in" << includeFile; QString includeStr = getGeometry(includeFile, includeGeom); includeStr = getGeometryStrContent(includeStr); - geometry = geometry.remove(startLine); - geometry = geometry.prepend(includeStr); - geometry = geometry.prepend(startLine); + geometry.remove(startLine); + geometry.prepend(includeStr); + geometry.prepend(startLine); includeGeometry(geometry); } return geometry; } QString getGeometryStrContent(QString geometryStr) { - int k = geometryStr.indexOf(QStringLiteral("{")); + int k = geometryStr.indexOf(QLatin1String("{")); int k2 = geometryStr.lastIndexOf(QLatin1String("};")); geometryStr = geometryStr.mid(k + 1, k2 - k - 2); return geometryStr; } QString getGeometry(QString geometryFile, QString geometryName) { QString xkbParentDir = findGeometryBaseDir(); geometryFile.prepend(xkbParentDir); QFile gfile(geometryFile); if (!gfile.open(QIODevice::ReadOnly | QIODevice::Text)) { qCritical() << "Unable to open the file" << geometryFile; return QString(); } QString gcontent = gfile.readAll(); gfile.close(); QStringList gcontentList = gcontent.split(QStringLiteral("xkb_geometry ")); int current = 0; for (int i = 1; i < gcontentList.size(); i++) { if (gcontentList[i].startsWith("\"" + geometryName + "\"")) { current = i; break; } } if (current != 0) { return gcontentList[current].prepend("xkb_geometry "); } else { return QString(); } } QString findGeometryBaseDir() { QString xkbDir = Rules::findXkbDir(); return QStringLiteral("%1/geometry/").arg(xkbDir); } } diff --git a/kcms/keyboard/preview/keyaliases.cpp b/kcms/keyboard/preview/keyaliases.cpp index 4fb79193b..c17d091be 100644 --- a/kcms/keyboard/preview/keyaliases.cpp +++ b/kcms/keyboard/preview/keyaliases.cpp @@ -1,128 +1,128 @@ /* * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "keyaliases.h" #include "xkb_rules.h" #include #include #include #include #include #include #include #include #include #include Aliases::Aliases() { QString filename = findaliasdir(); QFile file(filename); file.open(QIODevice::ReadOnly | QIODevice::Text); QString content = file.readAll(); file.close(); QListals; als = content.split(QStringLiteral("xkb_keycodes")); for (int i = 1; i < als.size(); i++) { QString temp = als.at(i); - temp = temp.remove(QStringLiteral(" ")); - temp = temp.remove(QStringLiteral("\n")); - temp = temp.remove(QStringLiteral("\"")); - temp = temp.remove(QStringLiteral(">")); - temp = temp.remove(QStringLiteral("<")); - temp = temp.remove(QStringLiteral(";")); - temp = temp.remove(QStringLiteral("}")); - temp = temp.remove(QStringLiteral("{")); + temp.remove(QStringLiteral(" ")); + temp.remove(QStringLiteral("\n")); + temp.remove(QStringLiteral("\"")); + temp.remove(QStringLiteral(">")); + temp.remove(QStringLiteral("<")); + temp.remove(QStringLiteral(";")); + temp.remove(QStringLiteral("}")); + temp.remove(QStringLiteral("{")); QListalskeys; alskeys = temp.split(QStringLiteral("alias")); if (temp.startsWith(QLatin1String("qwerty"))) { for (int k = 1; k < alskeys.size(); k++) { QString tmp = alskeys.at(k); - int inofeq = tmp.indexOf(QStringLiteral("=")); + int inofeq = tmp.indexOf(QLatin1String("=")); QString lat = tmp.left(inofeq); QString key = tmp.mid(inofeq + 1); qwerty[lat] = key; } } if (temp.startsWith(QLatin1String("azerty"))) { for (int k = 1; k < alskeys.size(); k++) { QString tmp = alskeys.at(k); - int inofeq = tmp.indexOf(QStringLiteral("=")); + int inofeq = tmp.indexOf(QLatin1String("=")); QString lat = tmp.left(inofeq); QString key = tmp.mid(inofeq + 1); azerty[lat] = key; } } if (temp.startsWith(QLatin1String("qwertz"))) { for (int k = 1; k < alskeys.size(); k++) { QString tmp = alskeys.at(k); - int inofeq = tmp.indexOf(QStringLiteral("=")); + int inofeq = tmp.indexOf(QLatin1String("=")); QString lat = tmp.left(inofeq); QString key = tmp.mid(inofeq + 1); qwertz[lat] = key; } } } } QString Aliases::getAlias(const QString &cname, const QString &name) { QMessageBox q; QString a = name; if (cname == QLatin1String("ma") || cname == QLatin1String("be") || cname == QLatin1String("fr")) { a = azerty.value(name); } else { a = qwerty.value(name); } return a; } QString Aliases::findaliasdir() { QString xkbDir = Rules::findXkbDir(); return QStringLiteral("%1/keycodes/aliases").arg(xkbDir); } diff --git a/kcms/keyboard/preview/keysymbols.cpp b/kcms/keyboard/preview/keysymbols.cpp index c0bb8685d..06985416f 100644 --- a/kcms/keyboard/preview/keysymbols.cpp +++ b/kcms/keyboard/preview/keysymbols.cpp @@ -1,59 +1,59 @@ /* * Copyright (C) 2012 Shivam Makkar (amourphious1992@gmail.com) * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "keysymbols.h" #include static const int MAX_GROUPS_SUPPORTED = 4; KeySymbols::KeySymbols() { } void KeySymbols::setKey(const QString &a) { int i = a.indexOf("<"); i++; keyname = a.mid(i, 4); keyname.remove(" "); i = a.indexOf("["); i++; QString str = a.mid(i); i = str.indexOf("]"); QString st = str.left(i); - st = st.remove(" "); + st.remove(" "); //QStringList klst; symbols = st.split(","); if (symbols.size() > MAX_GROUPS_SUPPORTED) { symbols = symbols.mid(0, MAX_GROUPS_SUPPORTED); } for (int k = 0; k < symbols.size(); k++) { QString du = symbols.at(k); du.remove(" "); du.remove("\t"); du.remove("\n"); symbols[k] = du; } } diff --git a/kcms/keyboard/preview/symbol_parser.cpp b/kcms/keyboard/preview/symbol_parser.cpp index 71aa552e5..b608fbdb1 100644 --- a/kcms/keyboard/preview/symbol_parser.cpp +++ b/kcms/keyboard/preview/symbol_parser.cpp @@ -1,288 +1,288 @@ /* * Copyright (C) 2013 Shivam Makkar (amourphious1992@gmail.com) * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "symbol_parser.h" #include "xkb_rules.h" #include #include #include #include #include namespace grammar { symbol_keywords::symbol_keywords() { add("key", 2)("include", 1)("//", 3)("*/", 4); } levels::levels() { add("ONE", 1)("TWO", 2)("THREE", 3)("FOUR", 4)("SIX", 6)("EIGHT", 8); } template SymbolParser::SymbolParser() : SymbolParser::base_type(start) { using qi::lexeme; using qi::char_; using qi::lit; using qi::_1; using qi::_val; using qi::int_; using qi::double_; using qi::eol; newKey = 0; name %= '"' >> +(char_ - '"') >> '"'; group = lit("Group") >> int_; comments = lexeme[lit("//") >> *(char_ - eol || symbolKeyword - eol) >> eol || lit("/*") >> *(char_ - lit("*/") || symbolKeyword - lit("*/")) >> lit("*/")]; include = lit("include") >> name[phx::bind(&SymbolParser::getInclude, this, _1)]; type = lit("type") >> '[' >> group >> lit(']') >> lit('=') >> lit("\"") >> *(char_ - lvl) >> *lvl[phx::bind(&SymbolParser::setLevel, this, _1)] >> *(char_ - lvl - '"') >> lit("\""); symbol = +(char_ - ',' - ']'); symbols = *(lit("symbols") >> '[' >> group >> lit(']') >> lit('=')) >> '[' >> symbol[phx::bind(&SymbolParser::getSymbol, this, _1)] >> *(',' >> symbol[phx::bind(&SymbolParser::getSymbol, this, _1)]) >> ']'; keyName = '<' >> *(char_ - '>') >> '>'; key = (lit("key") >> keyName[phx::bind(&SymbolParser::addKeyName, this, _1)] >> '{' >> *(type >> ',') >> symbols >> *(',' >> type) >> lit("};")) || lit("key") >> lit(".") >> type >> lit(";"); ee = *(char_ - symbolKeyword - '{') >> '{' >> *(char_ - '}' - ';') >> lit("};"); start = *(char_ - lit("xkb_symbols") || comments) >> lit("xkb_symbols") >> name[phx::bind(&SymbolParser::setName, this, _1)] >> '{' >> *(key[phx::bind(&SymbolParser::addKey, this)] || include || ee || char_ - '}' - symbolKeyword || comments) >> lit("};") >> *(comments || char_); } template void SymbolParser::getSymbol(std::string n) { int index = layout.keyList[keyIndex].getSymbolCount(); layout.keyList[keyIndex].addSymbol(QString::fromUtf8(n.data(), n.size()), index); //qCDebug(KEYBOARD_PREVIEW) << "adding symbol: " << QString::fromUtf8(n.data(), n.size()); //qCDebug(KEYBOARD_PREVIEW) << "added symbol: " << layout.keyList[keyIndex].getSymbol(index) << " in " << keyIndex << " at " << index; } template void SymbolParser::addKeyName(std::string n) { QString kname = QString::fromUtf8(n.data(), n.size()); if (kname.startsWith(QLatin1String("Lat"))) { kname = alias.getAlias(layout.country, kname); } keyIndex = layout.findKey(kname); //qCDebug(KEYBOARD_PREVIEW) << layout.getKeyCount(); if (keyIndex == -1) { layout.keyList[layout.getKeyCount()].keyName = kname; keyIndex = layout.getKeyCount(); newKey = 1; } // qCDebug(KEYBOARD_PREVIEW) << "key at" << keyIndex; } template void SymbolParser::addKey() { if (newKey == 1) { layout.addKey(); newKey = 0; //qCDebug(KEYBOARD_PREVIEW) << "new key"; } } template void SymbolParser::getInclude(std::string n) { layout.addInclude(QString::fromUtf8(n.data(), n.size())); } template void SymbolParser::setName(std::string n) { layout.setName(QString::fromUtf8(n.data(), n.size())); //qCDebug(KEYBOARD_PREVIEW) << layout.getLayoutName(); } template void SymbolParser::setLevel(int lvl) { if (lvl > layout.getLevel()) { layout.setLevel(lvl); qCDebug(KEYBOARD_PREVIEW) << lvl; } } QString findSymbolBaseDir() { QString xkbDir = Rules::findXkbDir(); return QStringLiteral("%1/symbols/").arg(xkbDir); } QString findLayout(const QString &layout, const QString &layoutVariant) { QString symbolBaseDir = findSymbolBaseDir(); QString symbolFile = symbolBaseDir.append(layout); QFile sfile(symbolFile); if (!sfile.open(QIODevice::ReadOnly | QIODevice::Text)) { //qCDebug(KEYBOARD_PREVIEW) << "unable to open the file"; return QStringLiteral("I/O ERROR"); } QString scontent = sfile.readAll(); sfile.close(); QStringList scontentList = scontent.split(QStringLiteral("xkb_symbols")); QString variant; QString input; if (layoutVariant.isEmpty()) { input = scontentList.at(1); input.prepend("xkb_symbols"); } else { int current = 1; while (layoutVariant != variant && current < scontentList.size()) { input = scontentList.at(current); QString symbolCont = scontentList.at(current); - int index = symbolCont.indexOf(QStringLiteral("\"")); + int index = symbolCont.indexOf(QLatin1String("\"")); symbolCont = symbolCont.mid(index); - index = symbolCont.indexOf(QStringLiteral("{")); + index = symbolCont.indexOf(QLatin1String("{")); symbolCont = symbolCont.left(index); - symbolCont = symbolCont.remove(QStringLiteral(" ")); + symbolCont.remove(QStringLiteral(" ")); variant = symbolCont.remove(QStringLiteral("\"")); input.prepend("xkb_symbols"); current++; } } return input; } KbLayout parseSymbols(const QString &layout, const QString &layoutVariant) { using boost::spirit::iso8859_1::space; typedef std::string::const_iterator iterator_type; typedef grammar::SymbolParser SymbolParser; SymbolParser symbolParser; symbolParser.layout.country = layout; QString input = findLayout(layout, layoutVariant); if (input == QLatin1String("I/O ERROR")) { symbolParser.layout.setParsedSymbol(false); return symbolParser.layout; } std::string parserInput = input.toUtf8().constData(); std::string::const_iterator iter = parserInput.begin(); std::string::const_iterator end = parserInput.end(); bool success = phrase_parse(iter, end, symbolParser, space); if (success && iter == end) { qCDebug(KEYBOARD_PREVIEW) << "Symbols Parsing succeeded"; symbolParser.layout.setParsedSymbol(true); } else { qWarning() << "Symbols Parsing failed\n" << input; symbolParser.layout.setParsedSymbol(false); } for (int currentInclude = 0; currentInclude < symbolParser.layout.getIncludeCount(); currentInclude++) { QString include = symbolParser.layout.getInclude(currentInclude); QStringList includeFile = include.split(QStringLiteral("(")); if (includeFile.size() == 2) { QString file = includeFile.at(0); QString layout = includeFile.at(1); layout.remove(QStringLiteral(")")); input = findLayout(file, layout); } else { QString a; a.clear(); input = findLayout(includeFile.at(0), a); } parserInput = input.toUtf8().constData(); std::string::const_iterator iter = parserInput.begin(); std::string::const_iterator end = parserInput.end(); success = phrase_parse(iter, end, symbolParser, space); if (success && iter == end) { qCDebug(KEYBOARD_PREVIEW) << "Symbols Parsing succeeded"; symbolParser.layout.setParsedSymbol(true); } else { qCDebug(KEYBOARD_PREVIEW) << "Symbols Parsing failed\n"; qCDebug(KEYBOARD_PREVIEW) << input; symbolParser.layout.setParsedSymbol(false); } } //s.layout.display(); if (symbolParser.layout.getParsedSymbol()) { return symbolParser.layout; } else { return parseSymbols(QStringLiteral("us"), QStringLiteral("basic")); } } } diff --git a/kcms/keyboard/xkb_helper.cpp b/kcms/keyboard/xkb_helper.cpp index 949e37e69..969614536 100644 --- a/kcms/keyboard/xkb_helper.cpp +++ b/kcms/keyboard/xkb_helper.cpp @@ -1,184 +1,184 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "xkb_helper.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include "keyboard_config.h" static const char SETXKBMAP_EXEC[] = "setxkbmap"; static const char XMODMAP_EXEC[] = "xmodmap"; static bool setxkbmapNotFound = false; static QString setxkbmapExe; static bool xmodmapNotFound = false; static QString xmodmapExe; static const QString COMMAND_OPTIONS_SEPARATOR(QStringLiteral(",")); static QString getSetxkbmapExe() { if( setxkbmapNotFound ) return QLatin1String(""); if( setxkbmapExe.isEmpty() ) { setxkbmapExe = QStandardPaths::findExecutable(SETXKBMAP_EXEC); if( setxkbmapExe.isEmpty() ) { setxkbmapNotFound = true; qCCritical(KCM_KEYBOARD) << "Can't find" << SETXKBMAP_EXEC << "- keyboard layouts won't be configured"; return QLatin1String(""); } } return setxkbmapExe; } static void executeXmodmap(const QString& configFileName) { if( xmodmapNotFound ) return; if( QFile(configFileName).exists() ) { if( xmodmapExe.isEmpty() ) { xmodmapExe = QStandardPaths::findExecutable(XMODMAP_EXEC); if( xmodmapExe.isEmpty() ) { xmodmapNotFound = true; qCCritical(KCM_KEYBOARD) << "Can't find" << XMODMAP_EXEC << "- xmodmap files won't be run"; return; } } KProcess xmodmapProcess; xmodmapProcess << xmodmapExe; xmodmapProcess << configFileName; - qCDebug(KCM_KEYBOARD) << "Executing" << xmodmapProcess.program().join(QStringLiteral(" ")); + qCDebug(KCM_KEYBOARD) << "Executing" << xmodmapProcess.program().join(QLatin1String(" ")); if( xmodmapProcess.execute() != 0 ) { qCCritical(KCM_KEYBOARD) << "Failed to execute " << xmodmapProcess.program(); } } } static void restoreXmodmap() { // TODO: is just home .Xmodmap enough or should system be involved too? // QString configFileName = QDir("/etc/X11/xinit").filePath(".Xmodmap"); // executeXmodmap(configFileName); QString configFileName = QDir::home().filePath(QStringLiteral(".Xmodmap")); executeXmodmap(configFileName); } //TODO: make private bool XkbHelper::runConfigLayoutCommand(const QStringList& setxkbmapCommandArguments) { QTime timer; timer.start(); KProcess setxkbmapProcess; setxkbmapProcess << getSetxkbmapExe() << setxkbmapCommandArguments; int res = setxkbmapProcess.execute(); if( res == 0 ) { // restore Xmodmap mapping reset by setxkbmap - qCDebug(KCM_KEYBOARD) << "Executed successfully in " << timer.elapsed() << "ms" << setxkbmapProcess.program().join(QStringLiteral(" ")); + qCDebug(KCM_KEYBOARD) << "Executed successfully in " << timer.elapsed() << "ms" << setxkbmapProcess.program().join(QLatin1String(" ")); restoreXmodmap(); qCDebug(KCM_KEYBOARD) << "\t and with xmodmap" << timer.elapsed() << "ms"; return true; } else { - qCCritical(KCM_KEYBOARD) << "Failed to run" << setxkbmapProcess.program().join(QStringLiteral(" ")) << "return code:" << res; + qCCritical(KCM_KEYBOARD) << "Failed to run" << setxkbmapProcess.program().join(QLatin1String(" ")) << "return code:" << res; } return false; } bool XkbHelper::initializeKeyboardLayouts(const QList& layoutUnits) { QStringList layouts; QStringList variants; foreach (const LayoutUnit& layoutUnit, layoutUnits) { layouts.append(layoutUnit.layout()); variants.append(layoutUnit.variant()); } QStringList setxkbmapCommandArguments; setxkbmapCommandArguments.append(QStringLiteral("-layout")); setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); if( ! variants.join(QLatin1String("")).isEmpty() ) { setxkbmapCommandArguments.append(QStringLiteral("-variant")); setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); } return runConfigLayoutCommand(setxkbmapCommandArguments); } bool XkbHelper::initializeKeyboardLayouts(KeyboardConfig& config) { QStringList setxkbmapCommandArguments; if( ! config.keyboardModel.isEmpty() ) { XkbConfig xkbConfig; X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::MODEL_ONLY); if( xkbConfig.keyboardModel != config.keyboardModel ) { setxkbmapCommandArguments.append(QStringLiteral("-model")); setxkbmapCommandArguments.append(config.keyboardModel); } } if( config.configureLayouts ) { QStringList layouts; QStringList variants; QList defaultLayouts = config.getDefaultLayouts(); foreach (const LayoutUnit& layoutUnit, defaultLayouts) { layouts.append(layoutUnit.layout()); variants.append(layoutUnit.variant()); } setxkbmapCommandArguments.append(QStringLiteral("-layout")); setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); if( ! variants.join(QLatin1String("")).isEmpty() ) { setxkbmapCommandArguments.append(QStringLiteral("-variant")); setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); } } if( config.resetOldXkbOptions ) { setxkbmapCommandArguments.append(QStringLiteral("-option")); } if( ! config.xkbOptions.isEmpty() ) { setxkbmapCommandArguments.append(QStringLiteral("-option")); setxkbmapCommandArguments.append(config.xkbOptions.join(COMMAND_OPTIONS_SEPARATOR)); } if( ! setxkbmapCommandArguments.isEmpty() ) { return runConfigLayoutCommand(setxkbmapCommandArguments); if( config.configureLayouts ) { X11Helper::setDefaultLayout(); } } return false; } diff --git a/kcms/keyboard/xkb_rules.cpp b/kcms/keyboard/xkb_rules.cpp index 3cc081935..64b4777e0 100644 --- a/kcms/keyboard/xkb_rules.cpp +++ b/kcms/keyboard/xkb_rules.cpp @@ -1,495 +1,495 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "xkb_rules.h" #include "config-workspace.h" #include "debug.h" #include #include #include #include // for Qt::escape #include #include //#include //#include #include "x11_helper.h" // for findXkbRuleFile #include #include #include #include #include #include #include class RulesHandler : public QXmlDefaultHandler { public: RulesHandler(Rules* rules_, bool fromExtras_): rules(rules_), fromExtras(fromExtras_){} bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &attributes) override; bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName) override; bool characters(const QString &str) override; // bool fatalError(const QXmlParseException &exception); // QString errorString() const; private: // QString getString(const QString& text); QStringList path; Rules* rules; const bool fromExtras; }; static QString translate_xml_item(const QString& itemText) { if (itemText.isEmpty()) { // i18n warns on empty input strings return itemText; } //messages are already extracted from the source XML files by xkb //the characters '<' and '>' (but not '"') are HTML-escaped in the xkeyboard-config translation files, so we need to convert them before/after looking up the translation //note that we cannot use QString::toHtmlEscaped() here because that would convert '"' as well QString msgid(itemText); return i18nd("xkeyboard-config", msgid.replace(QLatin1Literal("<"), QLatin1Literal("<")).replace(QLatin1Literal(">"), QLatin1Literal(">")).toUtf8()).replace(QLatin1Literal("<"), QLatin1Literal("<")).replace(QLatin1Literal(">"), QLatin1Literal(">")); } static QString translate_description(ConfigItem* item) { return item->description.isEmpty() ? item->name : translate_xml_item(item->description); } static bool notEmpty(const ConfigItem* item) { return ! item->name.isEmpty(); } template void removeEmptyItems(QList& list) { #ifdef __GNUC__ #if __GNUC__ == 4 && (__GNUC_MINOR__ == 8 && __GNUC_PATCHLEVEL__ < 3) || (__GNUC_MINOR__ == 7 && __GNUC_PATCHLEVEL__ < 4) #warning Compiling with a workaround for GCC < 4.8.3 || GCC < 4.7.4 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58800 Q_FOREACH(T* x, list) { ConfigItem *y = static_cast(x); if (y->name.isEmpty()) { list.removeAll(x); } } #else QtConcurrent::blockingFilter(list, notEmpty); #endif #endif } static void postProcess(Rules* rules) { //TODO remove elements with empty names to safeguard us removeEmptyItems(rules->layoutInfos); removeEmptyItems(rules->modelInfos); removeEmptyItems(rules->optionGroupInfos); // setlocale(LC_ALL, ""); // bindtextdomain("xkeyboard-config", LOCALE_DIR); foreach(ModelInfo* modelInfo, rules->modelInfos) { modelInfo->vendor = translate_xml_item(modelInfo->vendor); modelInfo->description = translate_description(modelInfo); } foreach(LayoutInfo* layoutInfo, rules->layoutInfos) { layoutInfo->description = translate_description(layoutInfo); removeEmptyItems(layoutInfo->variantInfos); foreach(VariantInfo* variantInfo, layoutInfo->variantInfos) { variantInfo->description = translate_description(variantInfo); } } foreach(OptionGroupInfo* optionGroupInfo, rules->optionGroupInfos) { optionGroupInfo->description = translate_description(optionGroupInfo); removeEmptyItems(optionGroupInfo->optionInfos); foreach(OptionInfo* optionInfo, optionGroupInfo->optionInfos) { optionInfo->description = translate_description(optionInfo); } } } Rules::Rules(): version(QStringLiteral("1.0")) { } QString Rules::getRulesName() { if (!QX11Info::isPlatformX11()) { return QString(); } XkbRF_VarDefsRec vd; char *tmp = nullptr; if (XkbRF_GetNamesProp(QX11Info::display(), &tmp, &vd) && tmp != nullptr ) { // qCDebug(KCM_KEYBOARD) << "namesprop" << tmp ; const QString name(tmp); XFree(tmp); return name; } return {}; } QString Rules::findXkbDir() { return QStringLiteral(XKBDIR); } static QString findXkbRulesFile() { QString rulesFile; QString rulesName = Rules::getRulesName(); const QString xkbDir = Rules::findXkbDir(); if ( ! rulesName.isNull() ) { rulesFile = QStringLiteral("%1/rules/%2.xml").arg(xkbDir, rulesName); } else { // default to evdev rulesFile = QStringLiteral("%1/rules/evdev.xml").arg(xkbDir); } return rulesFile; } static void mergeRules(Rules* rules, Rules* extraRules) { rules->modelInfos.append( extraRules->modelInfos ); rules->optionGroupInfos.append( extraRules->optionGroupInfos ); // need to iterate and merge? QList layoutsToAdd; foreach(LayoutInfo* extraLayoutInfo, extraRules->layoutInfos) { LayoutInfo* layoutInfo = findByName(rules->layoutInfos, extraLayoutInfo->name); if( layoutInfo != nullptr ) { layoutInfo->variantInfos.append( extraLayoutInfo->variantInfos ); layoutInfo->languages.append( extraLayoutInfo->languages ); } else { layoutsToAdd.append(extraLayoutInfo); } } rules->layoutInfos.append(layoutsToAdd); qCDebug(KCM_KEYBOARD) << "Merged from extra rules:" << extraRules->layoutInfos.size() << "layouts," << extraRules->modelInfos.size() << "models," << extraRules->optionGroupInfos.size() << "option groups"; // base rules now own the objects - remove them from extra rules so that it does not try to delete them extraRules->layoutInfos.clear(); extraRules->modelInfos.clear(); extraRules->optionGroupInfos.clear(); } const char Rules::XKB_OPTION_GROUP_SEPARATOR = ':'; Rules* Rules::readRules(ExtrasFlag extrasFlag) { Rules* rules = new Rules(); QString rulesFile = findXkbRulesFile(); if( ! readRules(rules, rulesFile, false) ) { delete rules; return nullptr; } if( extrasFlag == Rules::READ_EXTRAS ) { QRegExp regex(QStringLiteral("\\.xml$")); Rules* rulesExtra = new Rules(); QString extraRulesFile = rulesFile.replace(regex, QStringLiteral(".extras.xml")); if( readRules(rulesExtra, extraRulesFile, true) ) { // not fatal if it fails mergeRules(rules, rulesExtra); } delete rulesExtra; } return rules; } Rules* Rules::readRules(Rules* rules, const QString& filename, bool fromExtras) { QFile file(filename); if( !file.open(QFile::ReadOnly | QFile::Text) ) { qCCritical(KCM_KEYBOARD) << "Cannot open the rules file" << file.fileName(); return nullptr; } RulesHandler rulesHandler(rules, fromExtras); QXmlSimpleReader reader; reader.setContentHandler(&rulesHandler); reader.setErrorHandler(&rulesHandler); QXmlInputSource xmlInputSource(&file); qCDebug(KCM_KEYBOARD) << "Parsing xkb rules from" << file.fileName(); if( ! reader.parse(xmlInputSource) ) { qCCritical(KCM_KEYBOARD) << "Failed to parse the rules file" << file.fileName(); return nullptr; } postProcess(rules); return rules; } bool RulesHandler::startElement(const QString &/*namespaceURI*/, const QString &/*localName*/, const QString &qName, const QXmlAttributes &attributes) { path << QString(qName); - QString strPath = path.join(QStringLiteral("/")); + QString strPath = path.join(QLatin1String("/")); if( strPath.endsWith(QLatin1String("layoutList/layout/configItem")) ) { rules->layoutInfos << new LayoutInfo(fromExtras); } else if( strPath.endsWith(QLatin1String("layoutList/layout/variantList/variant")) ) { rules->layoutInfos.last()->variantInfos << new VariantInfo(fromExtras); } else if( strPath.endsWith(QLatin1String("modelList/model")) ) { rules->modelInfos << new ModelInfo(); } else if( strPath.endsWith(QLatin1String("optionList/group")) ) { rules->optionGroupInfos << new OptionGroupInfo(); rules->optionGroupInfos.last()->exclusive = (attributes.value(QStringLiteral("allowMultipleSelection")) != QLatin1String("true")); } else if( strPath.endsWith(QLatin1String("optionList/group/option")) ) { rules->optionGroupInfos.last()->optionInfos << new OptionInfo(); } else if( strPath == ("xkbConfigRegistry") && ! attributes.value(QStringLiteral("version")).isEmpty() ) { rules->version = attributes.value(QStringLiteral("version")); qCDebug(KCM_KEYBOARD) << "xkbConfigRegistry version" << rules->version; } return true; } bool RulesHandler::endElement(const QString &/*namespaceURI*/, const QString &/*localName*/, const QString &/*qName*/) { path.removeLast(); return true; } bool RulesHandler::characters(const QString &str) { if( !str.trimmed().isEmpty() ) { - QString strPath = path.join(QStringLiteral("/")); + QString strPath = path.join(QLatin1String("/")); if( strPath.endsWith(QLatin1String("layoutList/layout/configItem/name")) ) { if( rules->layoutInfos.last() != nullptr ) { rules->layoutInfos.last()->name = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "name:" << str; } // skipping invalid entry } else if( strPath.endsWith(QLatin1String("layoutList/layout/configItem/description")) ) { rules->layoutInfos.last()->description = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "descr:" << str; } else if( strPath.endsWith(QLatin1String("layoutList/layout/configItem/languageList/iso639Id")) ) { rules->layoutInfos.last()->languages << str.trimmed(); // qCDebug(KCM_KEYBOARD) << "\tlang:" << str; } else if( strPath.endsWith(QLatin1String("layoutList/layout/variantList/variant/configItem/name")) ) { rules->layoutInfos.last()->variantInfos.last()->name = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "\tvariant name:" << str; } else if( strPath.endsWith(QLatin1String("layoutList/layout/variantList/variant/configItem/description")) ) { rules->layoutInfos.last()->variantInfos.last()->description = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "\tvariant descr:" << str; } else if( strPath.endsWith(QLatin1String("layoutList/layout/variantList/variant/configItem/languageList/iso639Id")) ) { rules->layoutInfos.last()->variantInfos.last()->languages << str.trimmed(); // qCDebug(KCM_KEYBOARD) << "\tvlang:" << str; } else if( strPath.endsWith(QLatin1String("modelList/model/configItem/name")) ) { rules->modelInfos.last()->name = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "name:" << str; } else if( strPath.endsWith(QLatin1String("modelList/model/configItem/description")) ) { rules->modelInfos.last()->description = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "\tdescr:" << str; } else if( strPath.endsWith(QLatin1String("modelList/model/configItem/vendor")) ) { rules->modelInfos.last()->vendor = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "\tvendor:" << str; } else if( strPath.endsWith(QLatin1String("optionList/group/configItem/name")) ) { rules->optionGroupInfos.last()->name = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "name:" << str; } else if( strPath.endsWith(QLatin1String("optionList/group/configItem/description")) ) { rules->optionGroupInfos.last()->description = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "\tdescr:" << str; } else if( strPath.endsWith(QLatin1String("optionList/group/option/configItem/name")) ) { rules->optionGroupInfos.last()->optionInfos.last()->name = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "name:" << str; } else if( strPath.endsWith(QLatin1String("optionList/group/option/configItem/description")) ) { rules->optionGroupInfos.last()->optionInfos.last()->description = str.trimmed(); // qCDebug(KCM_KEYBOARD) << "\tdescr:" << str; } } return true; } bool LayoutInfo::isLanguageSupportedByLayout(const QString& lang) const { if( languages.contains(lang) || isLanguageSupportedByVariants(lang) ) return true; // // return yes if no languages found in layout or its variants // if( languages.empty() ) { // foreach(const VariantInfo* info, variantInfos) { // if( ! info->languages.empty() ) // return false; // } // return true; // } return false; } bool LayoutInfo::isLanguageSupportedByVariants(const QString& lang) const { foreach(const VariantInfo* info, variantInfos) { if( info->languages.contains(lang) ) return true; } return false; } bool LayoutInfo::isLanguageSupportedByDefaultVariant(const QString& lang) const { if( languages.contains(lang) ) return true; if( languages.empty() && isLanguageSupportedByVariants(lang) ) return true; return false; } bool LayoutInfo::isLanguageSupportedByVariant(const VariantInfo* variantInfo, const QString& lang) const { if( variantInfo->languages.contains(lang) ) return true; // if variant has no languages try to "inherit" them from layout if( variantInfo->languages.empty() && languages.contains(lang) ) return true; return false; } #ifdef NEW_GEOMETRY Rules::GeometryId Rules::getGeometryId(const QString& model) { QString xkbDir = Rules::findXkbDir(); QString rulesName = Rules::getRulesName(); QString ruleFileName = QStringLiteral("%1/rules/%2").arg(xkbDir, rulesName); QFile ruleFile(ruleFileName); GeometryId defaultGeoId(QStringLiteral("pc"), QStringLiteral("pc104")); if ( ! ruleFile.open(QIODevice::ReadOnly | QIODevice::Text) ){ qCCritical(KCM_KEYBOARD) << "Unable to open file" << ruleFileName; return defaultGeoId; } QString modelGeoId = model; bool inTable = false; QTextStream in(&ruleFile); while (!in.atEnd()) { QString line = in.readLine().trimmed(); if( line.isEmpty() || QRegExp(QStringLiteral("^\\s*//")).indexIn(line) != -1 ) continue; QRegExp modelGroupRegex(QStringLiteral("!\\s*(\\$[a-zA-Z0-9_]+)\\s*=(.*)")); if( modelGroupRegex.indexIn(line) != -1 ) { QStringList parts = modelGroupRegex.capturedTexts(); QString groupName = parts[1]; QStringList models = parts[2].split(QRegExp(QStringLiteral("\\s+")), QString::SkipEmptyParts); // qCDebug(KCM_KEYBOARD) << "modelGroup definition" << groupName << ":" << models; if( models.contains(model) ) { modelGeoId = groupName; } continue; } if( inTable ) { QRegExp modelTableEntry (QStringLiteral("\\s*(\\$?[a-zA-Z0-9_]+|\\*)\\s*=\\s*([a-zA-Z0-9_]+)\\(([a-zA-Z0-9_%]+)\\)")); if( modelTableEntry.indexIn(line) == -1 ) { if( QRegExp(QStringLiteral("^!\\s*")).indexIn(line) != -1 ) break; qCWarning(KCM_KEYBOARD) << "could not parse geometry line" << line; continue; } QStringList parts = modelTableEntry.capturedTexts(); QString modelName = parts[1]; QString fileName = parts[2]; QString geoName = parts[3]; if( geoName == QLatin1String("%m") ) { geoName = model; } if( modelName == QLatin1String("*") ) { defaultGeoId = GeometryId(fileName, geoName); } // qCDebug(KCM_KEYBOARD) << "geo entry" << modelName << fileName << geoName; if( modelName == model ) { return GeometryId(fileName, geoName); } continue; } QRegExp modelTableHeader (QStringLiteral("!\\s+model\\s*=\\s*geometry")); if( modelTableHeader.indexIn(line) != -1 ) { inTable = true; continue; } } return defaultGeoId; } #endif diff --git a/kcms/kfontinst/kcmfontinst/JobRunner.cpp b/kcms/kfontinst/kcmfontinst/JobRunner.cpp index 5c1aacc0b..9c3e875ec 100644 --- a/kcms/kfontinst/kcmfontinst/JobRunner.cpp +++ b/kcms/kfontinst/kcmfontinst/JobRunner.cpp @@ -1,809 +1,809 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2007 Craig Drummond * * ---- * * 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "JobRunner.h" #include "KfiConstants.h" #include "Misc.h" #include "Fc.h" #include "ActionLabel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config-fontinst.h" #define CFG_GROUP "Runner Dialog" #define CFG_DONT_SHOW_FINISHED_MSG "DontShowFinishedMsg" namespace KFI { Q_GLOBAL_STATIC(FontInstInterface, theInterface) FontInstInterface * CJobRunner::dbus() { return theInterface; } QString CJobRunner::folderName(bool sys) { if(!theInterface) return QString(); QDBusPendingReply reply=theInterface->folderName(sys); reply.waitForFinished(); return reply.isError() ? QString() : reply.argumentAt<0>(); } void CJobRunner::startDbusService() { if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(OrgKdeFontinstInterface::staticInterfaceName())) { const QString fontinst = QStringLiteral(KFONTINST_LIB_EXEC_DIR"/fontinst"); qDebug() << "Service " << OrgKdeFontinstInterface::staticInterfaceName() << " not registered, starting" << fontinst; QProcess::startDetached(fontinst, QStringList()); } } static const int constDownloadFailed=-1; static const int constInterfaceCheck=5*1000; static void decode(const QUrl &url, Misc::TFont &font, bool &system) { font=FC::decode(url); QUrlQuery query(url); - system = (query.hasQueryItem("sys") && query.queryItemValue("sys") == QStringLiteral("true")); + system = (query.hasQueryItem("sys") && query.queryItemValue("sys") == QLatin1String("true")); } QUrl CJobRunner::encode(const QString &family, quint32 style, bool system) { QUrl url(FC::encode(family, style)); url.addQueryItem("sys", system ? "true" : "false"); return url; } enum EPages { PAGE_PROGRESS, PAGE_SKIP, PAGE_ERROR, PAGE_CANCEL, PAGE_COMPLETE }; enum Response { RESP_CONTINUE, RESP_AUTO, RESP_CANCEL }; static void addIcon(QGridLayout *layout, QFrame *page, const char *iconName, int iconSize) { QLabel *icon=new QLabel(page); icon->setPixmap(QIcon::fromTheme(iconName).pixmap(iconSize)); icon->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); layout->addWidget(icon, 0, 0); } CJobRunner::CJobRunner(QWidget *parent, int xid) : QDialog(parent), itsIt(itsUrls.end()), itsEnd(itsIt), itsAutoSkip(false), itsCancelClicked(false), itsModified(false), itsTempDir(nullptr) { setModal(true); if(nullptr==parent && 0!=xid) XSetTransientForHint(QX11Info::display(), winId(), xid); itsButtonBox = new QDialogButtonBox; connect(itsButtonBox, &QDialogButtonBox::clicked, this, &CJobRunner::slotButtonClicked); itsSkipButton = new QPushButton(i18n("Skip")); itsButtonBox->addButton(itsSkipButton, QDialogButtonBox::ActionRole); itsSkipButton->hide(); itsAutoSkipButton = new QPushButton(i18n("AutoSkip")); itsButtonBox->addButton(itsAutoSkipButton, QDialogButtonBox::ActionRole); itsAutoSkipButton->hide(); itsStack = new QStackedWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(itsStack); mainLayout->addWidget(itsButtonBox); QStyleOption option; option.initFrom(this); int iconSize=style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, this); QFrame *page = new QFrame(itsStack); QGridLayout *layout=new QGridLayout(page); itsStatusLabel=new QLabel(page); itsProgress=new QProgressBar(page); // itsStatusLabel->setWordWrap(true); layout->addWidget(itsActionLabel = new CActionLabel(this), 0, 0, 2, 1); layout->addWidget(itsStatusLabel, 0, 1); layout->addWidget(itsProgress, 1, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 2, 0); itsStack->insertWidget(PAGE_PROGRESS, page); page=new QFrame(itsStack); layout=new QGridLayout(page); itsSkipLabel=new QLabel(page); itsSkipLabel->setWordWrap(true); addIcon(layout, page, "dialog-error", iconSize); layout->addWidget(itsSkipLabel, 0, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0); itsStack->insertWidget(PAGE_SKIP, page); page=new QFrame(itsStack); layout=new QGridLayout(page); itsErrorLabel=new QLabel(page); itsErrorLabel->setWordWrap(true); addIcon(layout, page, "dialog-error", iconSize); layout->addWidget(itsErrorLabel, 0, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0); itsStack->insertWidget(PAGE_ERROR, page); page=new QFrame(itsStack); layout=new QGridLayout(page); QLabel *cancelLabel=new QLabel(i18n("

Cancel?

Are you sure you wish to cancel?

"), page); cancelLabel->setWordWrap(true); addIcon(layout, page, "dialog-warning", iconSize); layout->addWidget(cancelLabel, 0, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0); itsStack->insertWidget(PAGE_CANCEL, page); if(KSharedConfig::openConfig(KFI_UI_CFG_FILE)->group(CFG_GROUP).readEntry(CFG_DONT_SHOW_FINISHED_MSG, false)) itsDontShowFinishedMsg= nullptr; else { page=new QFrame(itsStack); layout=new QGridLayout(page); QLabel *finishedLabel=new QLabel(i18n("

Finished

" "

Please note that any open applications will need to be " "restarted in order for any changes to be noticed.

"), page); finishedLabel->setWordWrap(true); addIcon(layout, page, "dialog-information", iconSize); layout->addWidget(finishedLabel, 0, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0); itsDontShowFinishedMsg = new QCheckBox(i18n("Do not show this message again"), page); itsDontShowFinishedMsg->setChecked(false); layout->addItem(new QSpacerItem(0, layout->spacing(), QSizePolicy::Fixed, QSizePolicy::Fixed), 2, 0); layout->addWidget(itsDontShowFinishedMsg, 3, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 4, 0); itsStack->insertWidget(PAGE_COMPLETE, page); } QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this); connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), SLOT(dbusServiceOwnerChanged(QString,QString,QString))); connect(dbus(), SIGNAL(status(int,int)), SLOT(dbusStatus(int,int))); setMinimumSize(420, 160); } CJobRunner::~CJobRunner() { delete itsTempDir; } void CJobRunner::getAssociatedUrls(const QUrl &url, QList &list, bool afmAndPfm, QWidget *widget) { QString ext(url.path()); int dotPos(ext.lastIndexOf('.')); bool check(false); if(-1==dotPos) // Hmm, no extension - check anyway... check=true; else // Cool, got an extension - see if it is a Type1 font... { ext=ext.mid(dotPos+1); check=0==ext.compare("pfa", Qt::CaseInsensitive) || 0==ext.compare("pfb", Qt::CaseInsensitive); } if(check) { const char *afm[]={"afm", "AFM", "Afm", nullptr}, *pfm[]={"pfm", "PFM", "Pfm", nullptr}; bool gotAfm(false), localFile(url.isLocalFile()); int e; for(e=0; afm[e]; ++e) { QUrl statUrl(url); statUrl.setPath(Misc::changeExt(url.path(), afm[e])); bool urlExists = false; if (localFile) { urlExists = Misc::fExists(statUrl.toLocalFile()); } else { auto job = KIO::stat(statUrl); KJobWidgets::setWindow(job, widget); job->exec(); urlExists = !job->error(); } if (urlExists) { list.append(statUrl); gotAfm=true; break; } } if(afmAndPfm || !gotAfm) for(e=0; pfm[e]; ++e) { QUrl statUrl(url); statUrl.setPath(Misc::changeExt(url.path(), pfm[e])); bool urlExists = false; if (localFile) { urlExists = Misc::fExists(statUrl.toLocalFile()); } else { auto job = KIO::stat(statUrl); KJobWidgets::setWindow(job, widget); job->exec(); urlExists = !job->error(); } if (urlExists) { list.append(statUrl); break; } } } } static void addEnableActions(CJobRunner::ItemList &urls) { CJobRunner::ItemList modified; CJobRunner::ItemList::ConstIterator it(urls.constBegin()), end(urls.constEnd()); for(; it!=end; ++it) { if((*it).isDisabled) { CJobRunner::Item item(*it); item.fileName=QLatin1String("--"); modified.append(item); } modified.append(*it); } urls=modified; } int CJobRunner::exec(ECommand cmd, const ItemList &urls, bool destIsSystem) { itsAutoSkip=itsCancelClicked=itsModified=false; switch(cmd) { case CMD_INSTALL: setWindowTitle(i18n("Installing")); break; case CMD_DELETE: setWindowTitle(i18n("Uninstalling")); break; case CMD_ENABLE: setWindowTitle(i18n("Enabling")); break; case CMD_MOVE: setWindowTitle(i18n("Moving")); break; case CMD_UPDATE: setWindowTitle(i18n("Updating")); itsModified=true; break; case CMD_REMOVE_FILE: setWindowTitle(i18n("Removing")); break; default: case CMD_DISABLE: setWindowTitle(i18n("Disabling")); } itsDestIsSystem=destIsSystem; itsUrls=urls; if(CMD_INSTALL==cmd) std::sort(itsUrls.begin(), itsUrls.end()); // Sort list of fonts so that we have type1 fonts followed by their metrics... else if(CMD_MOVE==cmd) addEnableActions(itsUrls); itsIt=itsUrls.constBegin(); itsEnd=itsUrls.constEnd(); itsPrev=itsEnd; itsProgress->setValue(0); itsProgress->setRange(0, itsUrls.count()+1); itsProgress->show(); itsCmd=cmd; itsCurrentFile=QString(); itsStatusLabel->setText(QString()); setPage(PAGE_PROGRESS); QTimer::singleShot(0, this, SLOT(doNext())); QTimer::singleShot(constInterfaceCheck, this, SLOT(checkInterface())); itsActionLabel->startAnimation(); int rv=QDialog::exec(); if(itsTempDir) { delete itsTempDir; itsTempDir= nullptr; } return rv; } void CJobRunner::doNext() { if(itsIt==itsEnd/* || CMD_UPDATE==itsCmd*/) { if(itsModified) { // Force reconfig if command was already set to update... dbus()->reconfigure(getpid(), CMD_UPDATE==itsCmd); itsCmd=CMD_UPDATE; itsStatusLabel->setText(i18n("Updating font configuration. Please wait...")); itsProgress->setValue(itsProgress->maximum()); emit configuring(); } else { itsActionLabel->stopAnimation(); if(PAGE_ERROR!=itsStack->currentIndex()) reject(); } } else { Misc::TFont font; bool system; switch(itsCmd) { case CMD_INSTALL: { itsCurrentFile=fileName((*itsIt)); if(itsCurrentFile.isEmpty()) // Failed to download... dbusStatus(getpid(), constDownloadFailed); else { // Create AFM if this is a PFM, and the previous was not the AFM for this font... bool createAfm=Item::TYPE1_PFM==(*itsIt).type && (itsPrev==itsEnd || (*itsIt).fileName!=(*itsPrev).fileName || Item::TYPE1_AFM!=(*itsPrev).type); dbus()->install(itsCurrentFile, createAfm, itsDestIsSystem, getpid(), false); } break; } case CMD_DELETE: decode(*itsIt, font, system); dbus()->uninstall(font.family, font.styleInfo, system, getpid(), false); break; case CMD_ENABLE: decode(*itsIt, font, system); dbus()->enable(font.family, font.styleInfo, system, getpid(), false); break; case CMD_DISABLE: decode(*itsIt, font, system); dbus()->disable(font.family, font.styleInfo, system, getpid(), false); break; case CMD_MOVE: decode(*itsIt, font, system); // To 'Move' a disabled font, we first need to enable it. To accomplish this, JobRunner creates a 'fake' entry // with the filename "--" if((*itsIt).fileName==QLatin1String("--")) { setWindowTitle(i18n("Enabling")); dbus()->enable(font.family, font.styleInfo, system, getpid(), false); } else { if(itsPrev!=itsEnd && (*itsPrev).fileName==QLatin1String("--")) setWindowTitle(i18n("Moving")); dbus()->move(font.family, font.styleInfo, itsDestIsSystem, getpid(), false); } break; case CMD_REMOVE_FILE: decode(*itsIt, font, system); dbus()->removeFile(font.family, font.styleInfo, (*itsIt).fileName, system, getpid(), false); break; default: break; } itsStatusLabel->setText(CMD_INSTALL==itsCmd ? (*itsIt).url() : FC::createName(FC::decode(*itsIt))); itsProgress->setValue(itsProgress->value()+1); // Keep copy of this iterator - so that can check whether AFM should be created. itsPrev=itsIt; } } void CJobRunner::checkInterface() { if(itsIt==itsUrls.constBegin() && !FontInst::isStarted(dbus())) { setPage(PAGE_ERROR, i18n("Unable to start backend.")); itsActionLabel->stopAnimation(); itsIt=itsEnd; } } void CJobRunner::dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to) { if(to.isEmpty() && !from.isEmpty() && name==QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()) && itsIt!=itsEnd) { setPage(PAGE_ERROR, i18n("Backend died, but has been restarted. Please try again.")); itsActionLabel->stopAnimation(); itsIt=itsEnd; } } void CJobRunner::dbusStatus(int pid, int status) { if(pid!=getpid()) return; if(CMD_UPDATE==itsCmd) { setPage(PAGE_COMPLETE); return; } itsLastDBusStatus=status; if(itsCancelClicked) { itsActionLabel->stopAnimation(); setPage(PAGE_CANCEL); return; /* if(RESP_CANCEL==itsResponse) itsIt=itsEnd; itsCancelClicked=false; setPage(PAGE_PROGRESS); itsActionLabel->startAnimation(); */ } // itsIt will equal itsEnd if user decided to cancel the current op if(itsIt==itsEnd) { doNext(); } else if (0==status) { itsModified=true; ++itsIt; doNext(); } else { bool cont(itsAutoSkip && itsUrls.count()>1); QString currentName((*itsIt).fileName); if(!cont) { itsActionLabel->stopAnimation(); if(FontInst::STATUS_SERVICE_DIED==status) { setPage(PAGE_ERROR, errorString(status)); itsIt=itsEnd; } else { ItemList::ConstIterator lastPartOfCurrent(itsIt), next(itsIt==itsEnd ? itsEnd : itsIt+1); // If we're installing a Type1 font, and its already installed - then we need to skip past AFM/PFM if(next!=itsEnd && Item::TYPE1_FONT==(*itsIt).type && (*next).fileName==currentName && (Item::TYPE1_AFM==(*next).type || Item::TYPE1_PFM==(*next).type)) { next++; if(next!=itsEnd && (*next).fileName==currentName && (Item::TYPE1_AFM==(*next).type || Item::TYPE1_PFM==(*next).type)) next++; } if(1==itsUrls.count() || next==itsEnd) setPage(PAGE_ERROR, errorString(status)); else { setPage(PAGE_SKIP, errorString(status)); return; } } } contineuToNext(cont); } } void CJobRunner::contineuToNext(bool cont) { itsActionLabel->startAnimation(); if(cont) { if(CMD_INSTALL==itsCmd && Item::TYPE1_FONT==(*itsIt).type) // Did we error on a pfa/pfb? if so, exclude the afm/pfm... { QString currentName((*itsIt).fileName); ++itsIt; // Skip afm/pfm if(itsIt!=itsEnd && (*itsIt).fileName==currentName && (Item::TYPE1_AFM==(*itsIt).type || Item::TYPE1_PFM==(*itsIt).type)) ++itsIt; // Skip pfm/afm if(itsIt!=itsEnd && (*itsIt).fileName==currentName && (Item::TYPE1_AFM==(*itsIt).type || Item::TYPE1_PFM==(*itsIt).type)) ++itsIt; } else ++itsIt; } else { itsUrls.empty(); itsIt=itsEnd=itsUrls.constEnd(); } doNext(); } void CJobRunner::slotButtonClicked(QAbstractButton *button) { switch(itsStack->currentIndex()) { case PAGE_PROGRESS: if(itsIt!=itsEnd) itsCancelClicked=true; break; case PAGE_SKIP: setPage(PAGE_PROGRESS); if (button == itsSkipButton) { contineuToNext(true); } else if (button == itsAutoSkipButton) { itsAutoSkip=true; contineuToNext(true); } else { contineuToNext(false); } break; case PAGE_CANCEL: if(button == itsButtonBox->button(QDialogButtonBox::Yes)) itsIt=itsEnd; itsCancelClicked=false; setPage(PAGE_PROGRESS); itsActionLabel->startAnimation(); // Now continue... dbusStatus(getpid(), itsLastDBusStatus); break; case PAGE_COMPLETE: if(itsDontShowFinishedMsg) { KConfigGroup grp(KSharedConfig::openConfig(KFI_UI_CFG_FILE)->group(CFG_GROUP)); grp.writeEntry(CFG_DONT_SHOW_FINISHED_MSG, itsDontShowFinishedMsg->isChecked()); } case PAGE_ERROR: QDialog::accept(); break; } } void CJobRunner::closeEvent(QCloseEvent *e) { if(PAGE_COMPLETE!=itsStack->currentIndex()) { e->ignore(); slotButtonClicked(PAGE_CANCEL==itsStack->currentIndex() ? itsButtonBox->button(QDialogButtonBox::No) : itsButtonBox->button(QDialogButtonBox::Cancel)); } } void CJobRunner::setPage(int page, const QString &msg) { itsStack->setCurrentIndex(page); switch(page) { case PAGE_PROGRESS: itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel); itsSkipButton->hide(); itsAutoSkipButton->hide(); break; case PAGE_SKIP: itsSkipLabel->setText(i18n("

Error

")+QLatin1String("

")+msg+QLatin1String("

")); itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel); itsSkipButton->show(); itsAutoSkipButton->show(); break; case PAGE_ERROR: itsErrorLabel->setText(i18n("

Error

")+QLatin1String("

")+msg+QLatin1String("

")); itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel); itsSkipButton->hide(); itsAutoSkipButton->hide(); break; case PAGE_CANCEL: itsButtonBox->setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::No); itsSkipButton->hide(); itsAutoSkipButton->hide(); break; case PAGE_COMPLETE: if(!itsDontShowFinishedMsg || itsDontShowFinishedMsg->isChecked()) { QDialog::accept(); } else { itsButtonBox->setStandardButtons(QDialogButtonBox::Close); itsSkipButton->hide(); itsAutoSkipButton->hide(); } break; } } QString CJobRunner::fileName(const QUrl &url) { if(url.isLocalFile()) return url.toLocalFile(); else { auto job = KIO::mostLocalUrl(url); job->exec(); QUrl local = job->mostLocalUrl(); if(local.isLocalFile()) return local.toLocalFile(); // Yipee! no need to download!! else { // Need to do actual download... if(!itsTempDir) { itsTempDir=new QTemporaryDir(QDir::tempPath() + "/fontinst"); itsTempDir->setAutoRemove(true); } QString tempName(itsTempDir->filePath(Misc::getFile(url.path()))); auto job = KIO::file_copy(url, QUrl::fromLocalFile(tempName), -1, KIO::Overwrite); if (job->exec()) return tempName; else return QString(); } } } QString CJobRunner::errorString(int value) const { Misc::TFont font(FC::decode(*itsIt)); QString urlStr; if(CMD_REMOVE_FILE==itsCmd) urlStr=(*itsIt).fileName; else if(font.family.isEmpty()) urlStr=(*itsIt).url(); else urlStr=FC::createName(font.family, font.styleInfo); switch(value) { case constDownloadFailed: return i18n("Failed to download %1", urlStr); case FontInst::STATUS_SERVICE_DIED: return i18n("System backend died. Please try again.
%1", urlStr); case FontInst::STATUS_BITMAPS_DISABLED: return i18n("%1 is a bitmap font, and these have been disabled on your system.", urlStr); case FontInst::STATUS_ALREADY_INSTALLED: return i18n("%1 contains the font %2, which is already installed on your system.", urlStr, FC::getName(itsCurrentFile)); case FontInst::STATUS_NOT_FONT_FILE: return i18n("%1 is not a font.", urlStr); case FontInst::STATUS_PARTIAL_DELETE: return i18n("Could not remove all files associated with %1", urlStr); case FontInst::STATUS_NO_SYS_CONNECTION: return i18n("Failed to start the system daemon.
%1", urlStr); case KIO::ERR_FILE_ALREADY_EXIST: { QString name(Misc::modifyName(Misc::getFile((*itsIt).fileName))), destFolder(Misc::getDestFolder(folderName(itsDestIsSystem), name)); return i18n("%1 already exists.", destFolder+name); } case KIO::ERR_DOES_NOT_EXIST: return i18n("%1 does not exist.", urlStr); case KIO::ERR_WRITE_ACCESS_DENIED: return i18n("Permission denied.
%1", urlStr); case KIO::ERR_UNSUPPORTED_ACTION: return i18n("Unsupported action.
%1", urlStr); case KIO::ERR_COULD_NOT_AUTHENTICATE: return i18n("Authentication failed.
%1", urlStr); default: return i18n("Unexpected error while processing: %1", urlStr); } } CJobRunner::Item::Item(const QUrl &u, const QString &n, bool dis) : QUrl(u), name(n), fileName(Misc::getFile(u.path())), isDisabled(dis) { type=Misc::checkExt(fileName, "pfa") || Misc::checkExt(fileName, "pfb") ? TYPE1_FONT : Misc::checkExt(fileName, "afm") ? TYPE1_AFM : Misc::checkExt(fileName, "pfm") ? TYPE1_PFM : OTHER_FONT; if(OTHER_FONT!=type) { int pos(fileName.lastIndexOf('.')); if(-1!=pos) fileName=fileName.left(pos); } } CJobRunner::Item::Item(const QString &file, const QString &family, quint32 style, bool system) : QUrl(CJobRunner::encode(family, style, system)), fileName(file), type(OTHER_FONT) { } bool CJobRunner::Item::operator<(const Item &o) const { int nameComp(fileName.compare(o.fileName)); return nameComp<0 || (0==nameComp && type * * ---- * * 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "Misc.h" #include "config-paths.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KFI { namespace Misc { QString prettyUrl(const QUrl &url) { QString u(url.url()); u.replace("%20", " "); return u; } QString dirSyntax(const QString &d) { if(!d.isEmpty()) { QString ds(d); ds.replace("//", "/"); int slashPos(ds.lastIndexOf('/')); if(slashPos!=(((int)ds.length())-1)) ds.append('/'); return ds; } return d; } QString fileSyntax(const QString &d) { if(!d.isEmpty()) { QString ds(d); ds.replace("//", "/"); int slashPos(ds.lastIndexOf('/')); if(slashPos==(((int)ds.length())-1)) ds.remove(slashPos, 1); return ds; } return d; } QString getDir(const QString &f) { QString d(f); int slashPos(d.lastIndexOf('/')); if(slashPos!=-1) d.remove(slashPos+1, d.length()); return dirSyntax(d); } QString getFile(const QString &f) { QString d(f); int slashPos=d.lastIndexOf('/'); if(slashPos!=-1) d.remove(0, slashPos+1); return d; } bool createDir(const QString &dir) { if (!QDir().mkpath(dir)) return false; // // Clear any umask before setting dir perms mode_t oldMask(umask(0000)); const QByteArray d = QFile::encodeName(dir); ::chmod(d.constData(), DIR_PERMS); // Reset umask ::umask(oldMask); return true; } void setFilePerms(const QByteArray &f) { // // Clear any umask before setting file perms mode_t oldMask(umask(0000)); ::chmod(f.constData(), FILE_PERMS); // Reset umask ::umask(oldMask); } bool doCmd(const QString &cmd, const QString &p1, const QString &p2, const QString &p3) { QStringList args; if(!p1.isEmpty()) args << p1; if(!p2.isEmpty()) args << p2; if(!p3.isEmpty()) args << p3; return 0==QProcess::execute(cmd, args); } QString changeExt(const QString &f, const QString &newExt) { QString newStr(f); int dotPos(newStr.lastIndexOf('.')); if(-1==dotPos) newStr+=QChar('.')+newExt; else { newStr.remove(dotPos+1, newStr.length()); newStr+=newExt; } return newStr; } // // Get a list of files associated with a file, e.g.: // // File: /home/a/courier.pfa // // Associated: /home/a/courier.afm /home/a/courier.pfm // void getAssociatedFiles(const QString &path, QStringList &files, bool afmAndPfm) { QString ext(path); int dotPos(ext.lastIndexOf('.')); bool check(false); if(-1==dotPos) // Hmm, no extension - check anyway... check=true; else // Cool, got an extension - see if it is a Type1 font... { ext=ext.mid(dotPos+1); check=0==ext.compare("pfa", Qt::CaseInsensitive) || 0==ext.compare("pfb", Qt::CaseInsensitive); } if(check) { const char *afm[]={"afm", "AFM", "Afm", nullptr}, *pfm[]={"pfm", "PFM", "Pfm", nullptr}; bool gotAfm(false); int e; for(e=0; afm[e]; ++e) { QString statFile(changeExt(path, afm[e])); if(fExists(statFile)) { files.append(statFile); gotAfm=true; break; } } if(afmAndPfm || !gotAfm) for(e=0; pfm[e]; ++e) { QString statFile(changeExt(path, pfm[e])); if(fExists(statFile)) { files.append(statFile); break; } } } } time_t getTimeStamp(const QString &item) { QT_STATBUF info; return !item.isEmpty() && 0==QT_LSTAT(QFile::encodeName(item), &info) ? info.st_mtime : 0; } bool check(const QString &path, bool file, bool checkW) { QT_STATBUF info; QByteArray pathC(QFile::encodeName(path)); return 0==QT_LSTAT(pathC, &info) && (file ? (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode)) : S_ISDIR(info.st_mode)) && (!checkW || 0==::access(pathC, W_OK)); } QString getFolder(const QString &defaultDir, const QString &root, QStringList &dirs) { if(dirs.contains(defaultDir)) return defaultDir; else { QStringList::const_iterator it, end=dirs.constEnd(); bool found=false; for(it=dirs.constBegin(); it!=end && !found; ++it) if(0==(*it).indexOf(root)) return *it; } return defaultDir; } bool checkExt(const QString &fname, const QString &ext) { QString extension('.'+ext); return fname.length()>extension.length() ? 0==fname.mid(fname.length()-extension.length()).compare(extension, Qt::CaseInsensitive) : false; } bool isBitmap(const QString &str) { return checkExt(str, "pcf") || checkExt(str, "bdf") || checkExt(str, "pcf.gz") || checkExt(str, "bdf.gz"); } bool isMetrics(const QString &str) { return checkExt(str, "afm") || checkExt(str, "pfm"); } int getIntQueryVal(const QUrl &url, const char *key, int defVal) { QUrlQuery query(url); QString item(query.queryItemValue(key)); int val(defVal); if(!item.isNull()) val=item.toInt(); return val; } bool printable(const QString &mime) { return "font/otf"==mime || "font/ttf"==mime || "application/x-font-type1"==mime || "application/x-font-ttf"==mime || "application/x-font-otf"==mime || "application/x-font-type1"==mime; } uint qHash(const KFI::Misc::TFont &key) { //return qHash(QString(key.family+'%'+QString().setNum(key.styleInfo, 16))); const QChar *p = key.family.unicode(); int n = key.family.size(); uint h = 0, g; h = (h << 4) + key.styleInfo; if ((g = (h & 0xf0000000)) != 0) h ^= g >> 23; h &= ~g; while (n--) { h = (h << 4) + (*p++).unicode(); if ((g = (h & 0xf0000000)) != 0) h ^= g >> 23; h &= ~g; } return h; } // Taken from qdom.cpp QString encodeText(const QString &str, QTextStream &s) { const QTextCodec *const codec = s.codec(); Q_ASSERT(codec); QString retval(str); int len = retval.length(), i = 0; while (i < len) { const QChar ati(retval.at(i)); if (ati == QLatin1Char('<')) { retval.replace(i, 1, QLatin1String("<")); len += 3; i += 4; } else if (ati == QLatin1Char('"')) { retval.replace(i, 1, QLatin1String(""")); len += 5; i += 6; } else if (ati == QLatin1Char('&')) { retval.replace(i, 1, QLatin1String("&")); len += 4; i += 5; } else if (ati == QLatin1Char('>') && i >= 2 && retval[i - 1] == QLatin1Char(']') && retval[i - 2] == QLatin1Char(']')) { retval.replace(i, 1, QLatin1String(">")); len += 3; i += 4; } else { if(codec->canEncode(ati)) ++i; else { // We have to use a character reference to get it through. const ushort codepoint(ati.unicode()); const QString replacement(QLatin1String("&#x") + QString::number(codepoint, 16) + QLatin1Char(';')); retval.replace(i, 1, replacement); i += replacement.length(); len += replacement.length() - 1; } } } return retval; } QString contractHome(QString path) { if (!path.isEmpty() && '/'==path[0]) { QString home(QDir::homePath()); if(path.startsWith(home)) { int len = home.length(); if(len>1 && (path.length() == len || path[len] == '/')) return path.replace(0, len, QString::fromLatin1("~")); } } return path; } QString expandHome(QString path) { if(!path.isEmpty() && '~'==path[0]) return 1==path.length() ? QDir::homePath() : path.replace(0, 1, QDir::homePath()); return path; } QMap getFontFileMap(const QSet &files) { QMap map; QSet::ConstIterator it=files.constBegin(), end=files.constEnd(); QMap > fontsFiles; for(;it!=end; ++it) fontsFiles[unhide(getFile(*it))].insert(getDir(*it)); QMap >::ConstIterator fIt(fontsFiles.constBegin()), fEnd(fontsFiles.constEnd()); for(; fIt!=fEnd; ++fIt) if(fIt.value().count()>1) { QVector orig(fIt.value().count()), modified(fIt.value().count()); QSet::ConstIterator oIt(fIt.value().constBegin()), oEnd(fIt.value().constEnd()); bool good=true; int count=fIt.value().count(); for(int i=0; i apps; if(!apps.contains(name)) { QStringList installPaths; if (qstrcmp(path, "libexec") == 0) installPaths.append(KFONTINST_LIBEXEC_DIR); apps[name] = QStandardPaths::findExecutable(name, installPaths); } return apps[name]; } } // Misc:: } // KFI:: diff --git a/kcms/krdb/krdb.cpp b/kcms/krdb/krdb.cpp index e158c336c..313c1bf43 100644 --- a/kcms/krdb/krdb.cpp +++ b/kcms/krdb/krdb.cpp @@ -1,990 +1,990 @@ /**************************************************************************** ** ** ** KRDB - puts current KDE color scheme into preprocessor statements ** cats specially written application default files and uses xrdb -merge to ** write to RESOURCE_MANAGER. Thus it gives a simple way to make non-KDE ** applications fit in with the desktop ** ** Copyright (C) 1998 by Mark Donohoe ** Copyright (C) 1999 by Dirk A. Mueller (reworked for KDE 2.0) ** Copyright (C) 2001 by Matthias Ettrich (add support for GTK applications ) ** Copyright (C) 2001 by Waldo Bastian ** Copyright (C) 2002 by Karol Szwed ** This application is freely distributable under the GNU Public License. ** *****************************************************************************/ #include #include #include #include #include #include #undef Unsorted #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "krdb.h" #if HAVE_X11 #include #include #endif inline const char * gtkEnvVar(int version) { return 2==version ? "GTK2_RC_FILES" : "GTK_RC_FILES"; } inline const char * sysGtkrc(int version) { if(2==version) { if(access("/etc/opt/gnome/gtk-2.0", F_OK) == 0) return "/etc/opt/gnome/gtk-2.0/gtkrc"; else return "/etc/gtk-2.0/gtkrc"; } else { if(access("/etc/opt/gnome/gtk", F_OK) == 0) return "/etc/opt/gnome/gtk/gtkrc"; else return "/etc/gtk/gtkrc"; } } inline const char * userGtkrc(int version) { return 2==version ? "/.gtkrc-2.0" : "/.gtkrc"; } // ----------------------------------------------------------------------------- static QString writableGtkrc(int version) { QString gtkrc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QDir dir; dir.mkpath(gtkrc); gtkrc += 2==version?"/gtkrc-2.0":"/gtkrc"; return gtkrc; } // ----------------------------------------------------------------------------- static void applyGtkStyles(bool active, int version) { QString gtkkde = writableGtkrc(version); QByteArray gtkrc = getenv(gtkEnvVar(version)); QStringList list = QFile::decodeName(gtkrc).split( QLatin1Char(':')); QString userHomeGtkrc = QDir::homePath()+userGtkrc(version); if (!list.contains(userHomeGtkrc)) list.prepend(userHomeGtkrc); QLatin1String systemGtkrc = QLatin1String(sysGtkrc(version)); if (!list.contains(systemGtkrc)) list.prepend(systemGtkrc); list.removeAll(QLatin1String("")); list.removeAll(gtkkde); list.append(gtkkde); // Pass env. var to kdeinit. QString name = gtkEnvVar(version); - QString value = list.join(QStringLiteral(":")); + QString value = list.join(QLatin1String(":")); org::kde::KLauncher klauncher(QStringLiteral("org.kde.klauncher5"), QStringLiteral("/KLauncher"), QDBusConnection::sessionBus()); klauncher.setLaunchEnv(name, value); } // ----------------------------------------------------------------------------- static void applyQtColors( KSharedConfigPtr kglobalcfg, QSettings& settings, QPalette& newPal ) { QStringList actcg, inactcg, discg; /* export kde color settings */ int i; for (i = 0; i < QPalette::NColorRoles; i++) actcg << newPal.color(QPalette::Active, (QPalette::ColorRole) i).name(); for (i = 0; i < QPalette::NColorRoles; i++) inactcg << newPal.color(QPalette::Inactive, (QPalette::ColorRole) i).name(); for (i = 0; i < QPalette::NColorRoles; i++) discg << newPal.color(QPalette::Disabled, (QPalette::ColorRole) i).name(); settings.setValue(QStringLiteral("/qt/Palette/active"), actcg); settings.setValue(QStringLiteral("/qt/Palette/inactive"), inactcg); settings.setValue(QStringLiteral("/qt/Palette/disabled"), discg); // export kwin's colors to qtrc for kstyle to use KConfigGroup wmCfgGroup(kglobalcfg, "WM"); // active colors QColor clr = newPal.color( QPalette::Active, QPalette::Window ); clr = wmCfgGroup.readEntry("activeBackground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/activeBackground"), clr.name()); if (QPixmap::defaultDepth() > 8) clr = clr.darker(110); clr = wmCfgGroup.readEntry("activeBlend", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/activeBlend"), clr.name()); clr = newPal.color( QPalette::Active, QPalette::HighlightedText ); clr = wmCfgGroup.readEntry("activeForeground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/activeForeground"), clr.name()); clr = newPal.color( QPalette::Active,QPalette::Window ); clr = wmCfgGroup.readEntry("frame", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/frame"), clr.name()); clr = wmCfgGroup.readEntry("activeTitleBtnBg", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/activeTitleBtnBg"), clr.name()); // inactive colors clr = newPal.color(QPalette::Inactive, QPalette::Window); clr = wmCfgGroup.readEntry("inactiveBackground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveBackground"), clr.name()); if (QPixmap::defaultDepth() > 8) clr = clr.darker(110); clr = wmCfgGroup.readEntry("inactiveBlend", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveBlend"), clr.name()); clr = newPal.color(QPalette::Inactive, QPalette::Window).darker(); clr = wmCfgGroup.readEntry("inactiveForeground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveForeground"), clr.name()); clr = newPal.color(QPalette::Inactive, QPalette::Window); clr = wmCfgGroup.readEntry("inactiveFrame", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveFrame"), clr.name()); clr = wmCfgGroup.readEntry("inactiveTitleBtnBg", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveTitleBtnBg"), clr.name()); KConfigGroup kdeCfgGroup(kglobalcfg, "KDE"); settings.setValue(QStringLiteral("/qt/KDE/contrast"), kdeCfgGroup.readEntry("contrast", 7)); } // ----------------------------------------------------------------------------- static void applyQtSettings( KSharedConfigPtr kglobalcfg, QSettings& settings ) { /* export font settings */ // NOTE keep this in sync with kfontsettingsdata in plasma-integration (cf. also Bug 378262) QFont defaultFont(QStringLiteral("Noto Sans"), 10, -1); defaultFont.setStyleHint(QFont::SansSerif); const KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("General")); const QString fontInfo = configGroup.readEntry(QStringLiteral("font"), QString()); if (!fontInfo.isEmpty()) { defaultFont.fromString(fontInfo); } settings.setValue(QStringLiteral("/qt/font"), defaultFont.toString()); /* export effects settings */ KConfigGroup kdeCfgGroup(kglobalcfg, "General"); bool effectsEnabled = kdeCfgGroup.readEntry("EffectsEnabled", false); bool fadeMenus = kdeCfgGroup.readEntry("EffectFadeMenu", false); bool fadeTooltips = kdeCfgGroup.readEntry("EffectFadeTooltip", false); bool animateCombobox = kdeCfgGroup.readEntry("EffectAnimateCombo", false); QStringList guieffects; if (effectsEnabled) { guieffects << QStringLiteral("general"); if (fadeMenus) guieffects << QStringLiteral("fademenu"); if (animateCombobox) guieffects << QStringLiteral("animatecombo"); if (fadeTooltips) guieffects << QStringLiteral("fadetooltip"); } else guieffects << QStringLiteral("none"); settings.setValue(QStringLiteral("/qt/GUIEffects"), guieffects); } // ----------------------------------------------------------------------------- static void addColorDef(QString& s, const char* n, const QColor& col) { QString tmp; tmp.sprintf("#define %s #%02x%02x%02x\n", n, col.red(), col.green(), col.blue()); s += tmp; } // ----------------------------------------------------------------------------- static void copyFile(QFile& tmp, QString const& filename, bool ) { QFile f( filename ); if ( f.open(QIODevice::ReadOnly) ) { QByteArray buf( 8192, ' ' ); while ( !f.atEnd() ) { int read = f.read( buf.data(), buf.size() ); if ( read > 0 ) tmp.write( buf.data(), read ); } } } // ----------------------------------------------------------------------------- static QString item( int i ) { return QString::number( i / 255.0, 'f', 3 ); } static QString color( const QColor& col ) { return QStringLiteral( "{ %1, %2, %3 }" ).arg( item( col.red() ) ).arg( item( col.green() ) ).arg( item( col.blue() ) ); } static void createGtkrc( bool exportColors, const QPalette& cg, bool exportGtkTheme, const QString& gtkTheme, int version ) { // lukas: why does it create in ~/.kde/share/config ??? // pfeiffer: so that we don't overwrite the user's gtkrc. // it is found via the GTK_RC_FILES environment variable. QSaveFile saveFile( writableGtkrc(version) ); if ( !saveFile.open(QIODevice::WriteOnly) ) return; QTextStream t ( &saveFile ); t.setCodec( QTextCodec::codecForLocale () ); t << i18n( "# created by KDE Plasma, %1\n" "#\n" "# If you do not want Plasma to override your GTK settings, select\n" "# Colors in the System Settings and disable the checkbox\n" "# \"Apply colors to non-Qt applications\"\n" "#\n" "#\n", QDateTime::currentDateTime().toString()); if ( 2==version ) { // we should maybe check for MacOS settings here t << endl; t << "gtk-alternative-button-order = 1" << endl; t << endl; } if (exportGtkTheme) { QString gtkStyle; if (gtkTheme.toLower() == QLatin1String("oxygen")) gtkStyle = QStringLiteral("oxygen-gtk"); else gtkStyle = gtkTheme; bool exist_gtkrc = false; QByteArray gtkrc = getenv(gtkEnvVar(version)); QStringList listGtkrc = QFile::decodeName(gtkrc).split(QLatin1Char(':')); if (listGtkrc.contains(saveFile.fileName())) listGtkrc.removeAll(saveFile.fileName()); listGtkrc.append(QDir::homePath() + userGtkrc(version)); listGtkrc.append(QDir::homePath() + "/.gtkrc-2.0-kde"); listGtkrc.append(QDir::homePath() + "/.gtkrc-2.0-kde4"); listGtkrc.removeAll(QLatin1String("")); listGtkrc.removeDuplicates(); for (int i = 0; i < listGtkrc.size(); ++i) { if ((exist_gtkrc = QFile::exists(listGtkrc.at(i)))) break; } if (!exist_gtkrc) { QString gtk2ThemeFilename; gtk2ThemeFilename = QStringLiteral("%1/.themes/%2/gtk-2.0/gtkrc").arg(QDir::homePath()).arg(gtkStyle); if (!QFile::exists(gtk2ThemeFilename)) { QStringList gtk2ThemePath; gtk2ThemeFilename.clear(); QByteArray xdgDataDirs = getenv("XDG_DATA_DIRS"); gtk2ThemePath.append(QDir::homePath() + "/.local"); gtk2ThemePath.append(QFile::decodeName(xdgDataDirs).split(QLatin1Char(':'))); gtk2ThemePath.removeDuplicates(); for (int i = 0; i < gtk2ThemePath.size(); ++i) { gtk2ThemeFilename = QStringLiteral("%1/themes/%2/gtk-2.0/gtkrc").arg(gtk2ThemePath.at(i)).arg(gtkStyle); if (QFile::exists(gtk2ThemeFilename)) break; else gtk2ThemeFilename.clear(); } } if (!gtk2ThemeFilename.isEmpty()) { t << "include \"" << gtk2ThemeFilename << "\"" << endl; t << endl; t << "gtk-theme-name=\"" << gtkStyle << "\"" << endl; t << endl; if (gtkStyle == QLatin1String("oxygen-gtk")) exportColors = false; } } } if (exportColors) { t << "style \"default\"" << endl; t << "{" << endl; t << " bg[NORMAL] = " << color( cg.color( QPalette::Active, QPalette::Window ) ) << endl; t << " bg[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl; t << " bg[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Window ) ) << endl; t << " bg[ACTIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl; t << " bg[PRELIGHT] = " << color( cg.color( QPalette::Active, QPalette::Window ) ) << endl; t << endl; t << " base[NORMAL] = " << color( cg.color( QPalette::Active, QPalette::Base ) ) << endl; t << " base[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl; t << " base[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Window ) ) << endl; t << " base[ACTIVE] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl; t << " base[PRELIGHT] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl; t << endl; t << " text[NORMAL] = " << color( cg.color(QPalette::Active, QPalette::Text) ) << endl; t << " text[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl; t << " text[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl; t << " text[ACTIVE] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl; t << " text[PRELIGHT] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl; t << endl; t << " fg[NORMAL] = " << color ( cg.color( QPalette::Active, QPalette::WindowText ) ) << endl; t << " fg[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl; t << " fg[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl; t << " fg[ACTIVE] = " << color( cg.color( QPalette::Active, QPalette::WindowText ) ) << endl; t << " fg[PRELIGHT] = " << color( cg.color( QPalette::Active, QPalette::WindowText ) ) << endl; t << "}" << endl; t << endl; t << "class \"*\" style \"default\"" << endl; t << endl; // tooltips don't have the standard background color t << "style \"ToolTip\"" << endl; t << "{" << endl; t << " bg[NORMAL] = " << color( cg.color( QPalette::ToolTipBase ) ) << endl; t << " base[NORMAL] = " << color( cg.color( QPalette::ToolTipBase ) ) << endl; t << " text[NORMAL] = " << color( cg.color( QPalette::ToolTipText ) ) << endl; t << " fg[NORMAL] = " << color( cg.color( QPalette::ToolTipText ) ) << endl; t << "}" << endl; t << endl; t << "widget \"gtk-tooltip\" style \"ToolTip\"" << endl; t << "widget \"gtk-tooltips\" style \"ToolTip\"" << endl; t << "widget \"gtk-tooltip*\" style \"ToolTip\"" << endl; t << endl; // highlight the current (mouse-hovered) menu-item // not every button, checkbox, etc. t << "style \"MenuItem\"" << endl; t << "{" << endl; t << " bg[PRELIGHT] = " << color( cg.color(QPalette::Highlight) ) << endl; t << " fg[PRELIGHT] = " << color( cg.color(QPalette::HighlightedText) ) << endl; t << "}" << endl; t << endl; t << "class \"*MenuItem\" style \"MenuItem\"" << endl; t << endl; } saveFile.commit(); } // --------------------------------------------------------------------- QString gtkColorsHelper(const QString &name, const QString &color) { return QStringLiteral("@define-color %1 %2;\n").arg(name, color); } void checkGtkCss() { QFile gtkCss(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/gtk-3.0/gtk.css"); if (gtkCss.open(QIODevice::ReadWrite)) { QTextStream gtkStream(>kCss); bool hasImport = false; while (!gtkStream.atEnd()) { QString line = gtkStream.readLine(); if (line.contains("@import 'colors.css';")) { hasImport = true; } } if (!hasImport) { gtkStream << "@import 'colors.css';"; } } } void exportGtkColors(QList activeColorSchemes, QList inactiveColorSchemes, QList disabledColorSchemes, KConfigGroup groupWMTheme, QTextStream& colorsStream) { /* Normal (Non Backdrop, Non Insensitive) */ // General Colors colorsStream << gtkColorsHelper("theme_fg_color", activeColorSchemes[1].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_bg_color", activeColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_text_color", activeColorSchemes[0].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_base_color", activeColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_view_hover_decoration_color", activeColorSchemes[0].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_hovering_selected_bg_color", activeColorSchemes[3].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_selected_bg_color", activeColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_selected_fg_color", activeColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_view_active_decoration_color", activeColorSchemes[0].decoration(KColorScheme::HoverColor).color().name()); // Button Colors colorsStream << gtkColorsHelper("theme_button_background_normal", activeColorSchemes[2].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_hover", activeColorSchemes[2].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_focus", activeColorSchemes[2].decoration(KColorScheme::FocusColor).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_normal", activeColorSchemes[2].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_active", activeColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Misc Colors QColor windowForegroundColor = activeColorSchemes[1].foreground(KColorScheme::NormalText).color(); QColor windowBackgroundColor = activeColorSchemes[1].background(KColorScheme::NormalBackground).color(); QColor bordersColor = KColorUtils::mix(windowBackgroundColor,windowForegroundColor, 0.25); colorsStream << gtkColorsHelper("borders", bordersColor.name()); colorsStream << gtkColorsHelper("warning_color", activeColorSchemes[0].foreground(KColorScheme::NeutralText).color().name()); colorsStream << gtkColorsHelper("success_color", activeColorSchemes[0].foreground(KColorScheme::PositiveText).color().name()); colorsStream << gtkColorsHelper("error_color", activeColorSchemes[0].foreground(KColorScheme::NegativeText).color().name()); /* Backdrop (Inactive) */ // General colorsStream << gtkColorsHelper("theme_unfocused_fg_color",inactiveColorSchemes[1].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_text_color", inactiveColorSchemes[0].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_bg_color", inactiveColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_base_color", inactiveColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_selected_bg_color_alt", inactiveColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_selected_bg_color", inactiveColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_selected_fg_color", inactiveColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Button colorsStream << gtkColorsHelper("theme_button_background_backdrop", inactiveColorSchemes[2].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_hover_backdrop", inactiveColorSchemes[2].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_focus_backdrop", inactiveColorSchemes[2].decoration(KColorScheme::FocusColor).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_backdrop", inactiveColorSchemes[2].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_active_backdrop", inactiveColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Misc Colors QColor inactiveWindowForegroundColor = inactiveColorSchemes[1].foreground(KColorScheme::NormalText).color(); QColor inactiveWindowBackgroundColor = inactiveColorSchemes[1].background(KColorScheme::NormalBackground).color(); QColor inactiveBordersColor = KColorUtils::mix(inactiveWindowBackgroundColor,inactiveWindowForegroundColor, 0.25); colorsStream << gtkColorsHelper("unfocused_borders", inactiveBordersColor.name()); colorsStream << gtkColorsHelper("warning_color_backdrop", inactiveColorSchemes[0].foreground(KColorScheme::NeutralText).color().name()); colorsStream << gtkColorsHelper("success_color_backdrop", inactiveColorSchemes[0].foreground(KColorScheme::PositiveText).color().name()); colorsStream << gtkColorsHelper("error_color_backdrop", inactiveColorSchemes[0].foreground(KColorScheme::NegativeText).color().name()); /* Insensitive (Disabled) */ // General colorsStream << gtkColorsHelper("insensitive_fg_color",disabledColorSchemes[1].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("insensitive_base_fg_color", disabledColorSchemes[0].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("insensitive_bg_color", disabledColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_base_color", disabledColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_selected_bg_color", disabledColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_selected_fg_color", disabledColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Button colorsStream << gtkColorsHelper("theme_button_background_insensitive", disabledColorSchemes[2].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_hover_insensitive", disabledColorSchemes[2].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_focus_insensitive", disabledColorSchemes[2].decoration(KColorScheme::FocusColor).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_insensitive", disabledColorSchemes[2].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_active_insensitive", disabledColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Misc Colors QColor disabledWindowForegroundColor = disabledColorSchemes[1].foreground(KColorScheme::NormalText).color(); QColor disabledWindowBackgroundColor = disabledColorSchemes[1].background(KColorScheme::NormalBackground).color(); QColor disabledBordersColor = KColorUtils::mix(disabledWindowBackgroundColor,disabledWindowForegroundColor, 0.25); colorsStream << gtkColorsHelper("insensitive_borders", disabledBordersColor.name()); colorsStream << gtkColorsHelper("warning_color_insensitive", disabledColorSchemes[0].foreground(KColorScheme::NeutralText).color().name()); colorsStream << gtkColorsHelper("success_color_insensitive", disabledColorSchemes[0].foreground(KColorScheme::PositiveText).color().name()); colorsStream << gtkColorsHelper("error_color_insensitive", disabledColorSchemes[0].foreground(KColorScheme::NegativeText).color().name()); /* Insensitive Backdrop (Inactive Disabled) These pretty much have the same appearance as regular inactive colors, but they're seperate in case we decide to make them different in the future. */ // General colorsStream << gtkColorsHelper("insensitive_unfocused_fg_color",disabledColorSchemes[1].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_view_text_color", disabledColorSchemes[0].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("insensitive_unfocused_bg_color", disabledColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_view_bg_color", disabledColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_unfocused_selected_bg_color", disabledColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_unfocused_selected_fg_color", disabledColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Button colorsStream << gtkColorsHelper("theme_button_background_backdrop_insensitive", disabledColorSchemes[2].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_hover_backdrop_insensitive", disabledColorSchemes[2].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_focus_backdrop_insensitive", disabledColorSchemes[2].decoration(KColorScheme::FocusColor).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_backdrop_insensitive", disabledColorSchemes[2].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_active_backdrop_insensitive", disabledColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Misc Colors QColor unfocusedDisabledWindowForegroundColor = disabledColorSchemes[1].foreground(KColorScheme::NormalText).color(); QColor unfocusedDisabledWindowBackgroundColor = disabledColorSchemes[1].background(KColorScheme::NormalBackground).color(); QColor unfocusedDisabledBordersColor = KColorUtils::mix(unfocusedDisabledWindowBackgroundColor,unfocusedDisabledWindowForegroundColor, 0.25); colorsStream << gtkColorsHelper("unfocused_insensitive_borders", unfocusedDisabledBordersColor.name()); colorsStream << gtkColorsHelper("warning_color_insensitive_backdrop", disabledColorSchemes[0].foreground(KColorScheme::NeutralText).color().name()); colorsStream << gtkColorsHelper("success_color_insensitive_backdrop", disabledColorSchemes[0].foreground(KColorScheme::PositiveText).color().name()); colorsStream << gtkColorsHelper("error_color_insensitive_backdrop", disabledColorSchemes[0].foreground(KColorScheme::NegativeText).color().name()); /* Ignorant Colors (These colors do not care about backdrop or insensitive states) */ colorsStream << gtkColorsHelper("link_color", activeColorSchemes[0].foreground(KColorScheme::LinkText).color().name()); colorsStream << gtkColorsHelper("link_visited_color", activeColorSchemes[0].foreground(KColorScheme::VisitedText).color().name()); QColor tooltipForegroundColor = activeColorSchemes[4].foreground(KColorScheme::NormalText).color(); QColor tooltipBackgroundColor = activeColorSchemes[4].background(KColorScheme::NormalBackground).color(); QColor tooltipBorderColor = KColorUtils::mix(tooltipBackgroundColor, tooltipForegroundColor, 0.25); colorsStream << gtkColorsHelper("tooltip_text", tooltipForegroundColor.name()); colorsStream << gtkColorsHelper("tooltip_background", tooltipBackgroundColor.name()); colorsStream << gtkColorsHelper("tooltip_border", tooltipBorderColor.name()); colorsStream << gtkColorsHelper("content_view_bg", activeColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); // Titlebar colors colorsStream << gtkColorsHelper("theme_titlebar_background", "rgb(" + groupWMTheme.readEntry("activeBackground", "") + ")"); colorsStream << gtkColorsHelper("theme_titlebar_foreground", "rgb(" + groupWMTheme.readEntry("activeForeground", "") + ")"); colorsStream << gtkColorsHelper("theme_titlebar_background_light", activeColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_titlebar_foreground_backdrop", "rgb(" + groupWMTheme.readEntry("inactiveForeground", "") + ")"); colorsStream << gtkColorsHelper("theme_titlebar_background_backdrop", "rgb(" + groupWMTheme.readEntry("inactiveBackground", "") + ")"); colorsStream << gtkColorsHelper("theme_titlebar_foreground_insensitive", "rgb(" + groupWMTheme.readEntry("inactiveForeground", "") + ")"); colorsStream << gtkColorsHelper("theme_titlebar_foreground_insensitive_backdrop", "rgb(" + groupWMTheme.readEntry("inactiveForeground", "") + ")"); } void saveGtkColors(KSharedConfigPtr& config) { checkGtkCss(); QFile colorsCss(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/gtk-3.0/colors.css"); if (colorsCss.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream colorsStream(&colorsCss); /* 0 Active View 1 Active Window 2 Active Button 3 Active Selection 4 Active Tooltip 5 Active Complimentary */ QList activeColorSchemes{ KColorScheme(QPalette::Active, KColorScheme::View, config), KColorScheme(QPalette::Active, KColorScheme::Window, config), KColorScheme(QPalette::Active, KColorScheme::Button, config), KColorScheme(QPalette::Active, KColorScheme::Selection, config), KColorScheme(QPalette::Active, KColorScheme::Tooltip, config), KColorScheme(QPalette::Active, KColorScheme::Complementary, config) }; QList inactiveColorSchemes{ KColorScheme(QPalette::Inactive, KColorScheme::View, config), KColorScheme(QPalette::Inactive, KColorScheme::Window, config), KColorScheme(QPalette::Inactive, KColorScheme::Button, config), KColorScheme(QPalette::Inactive, KColorScheme::Selection, config), KColorScheme(QPalette::Inactive, KColorScheme::Tooltip, config), KColorScheme(QPalette::Inactive, KColorScheme::Complementary, config) }; QList disabledColorSchemes{ KColorScheme(QPalette::Disabled, KColorScheme::View, config), KColorScheme(QPalette::Disabled, KColorScheme::Window, config), KColorScheme(QPalette::Disabled, KColorScheme::Button, config), KColorScheme(QPalette::Disabled, KColorScheme::Selection, config), KColorScheme(QPalette::Disabled, KColorScheme::Tooltip, config), KColorScheme(QPalette::Disabled, KColorScheme::Complementary, config) }; KConfigGroup groupWMTheme(config, "WM"); exportGtkColors(activeColorSchemes, inactiveColorSchemes, disabledColorSchemes, groupWMTheme, colorsStream); } } void saveGtkColors() { checkGtkCss(); QFile colorsCss(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/gtk-3.0/colors.css"); KConfigGroup groupWMTheme(KSharedConfig::openConfig(), "WM"); if (colorsCss.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream colorsStream(&colorsCss); /* 0 Active View 1 Active Window 2 Active Button 3 Active Selection 4 Active Tooltip 5 Active Complimentary */ QList activeColorSchemes{ KColorScheme(QPalette::Active, KColorScheme::View), KColorScheme(QPalette::Active, KColorScheme::Window), KColorScheme(QPalette::Active, KColorScheme::Button), KColorScheme(QPalette::Active, KColorScheme::Selection), KColorScheme(QPalette::Active, KColorScheme::Tooltip), KColorScheme(QPalette::Active, KColorScheme::Complementary) }; QList inactiveColorSchemes{ KColorScheme(QPalette::Inactive, KColorScheme::View), KColorScheme(QPalette::Inactive, KColorScheme::Window), KColorScheme(QPalette::Inactive, KColorScheme::Button), KColorScheme(QPalette::Inactive, KColorScheme::Selection), KColorScheme(QPalette::Inactive, KColorScheme::Tooltip), KColorScheme(QPalette::Inactive, KColorScheme::Complementary) }; QList disabledColorSchemes{ KColorScheme(QPalette::Disabled, KColorScheme::View), KColorScheme(QPalette::Disabled, KColorScheme::Window), KColorScheme(QPalette::Disabled, KColorScheme::Button), KColorScheme(QPalette::Disabled, KColorScheme::Selection), KColorScheme(QPalette::Disabled, KColorScheme::Tooltip), KColorScheme(QPalette::Disabled, KColorScheme::Complementary) }; exportGtkColors(activeColorSchemes, inactiveColorSchemes, disabledColorSchemes, groupWMTheme, colorsStream); } } // ----------------------------------------------------------------------------- void runRdb( uint flags ) { // Obtain the application palette that is about to be set. bool exportColors = flags & KRdbExportColors; bool exportQtColors = flags & KRdbExportQtColors; bool exportQtSettings = flags & KRdbExportQtSettings; bool exportXftSettings = flags & KRdbExportXftSettings; bool exportGtkTheme = flags & KRdbExportGtkTheme; bool exportGtkColors = flags & KRdbExportGtkColors; KSharedConfigPtr kglobalcfg = KSharedConfig::openConfig( QStringLiteral("kdeglobals") ); KConfigGroup kglobals(kglobalcfg, "KDE"); QPalette newPal = KColorScheme::createApplicationPalette(kglobalcfg); QTemporaryFile tmpFile; if (!tmpFile.open()) { qDebug() << "Couldn't open temp file"; exit(0); } KConfigGroup generalCfgGroup(kglobalcfg, "General"); QString gtkTheme; if (kglobals.hasKey("widgetStyle")) gtkTheme = kglobals.readEntry("widgetStyle"); else gtkTheme = QStringLiteral("oxygen"); createGtkrc( exportColors, newPal, exportGtkTheme, gtkTheme, 1 ); createGtkrc( exportColors, newPal, exportGtkTheme, gtkTheme, 2 ); // Export colors to non-(KDE/Qt) apps (e.g. Motif, GTK+ apps) if (exportColors) { KConfigGroup g(KSharedConfig::openConfig(), "WM"); QString preproc; QColor backCol = newPal.color( QPalette::Active, QPalette::Window ); addColorDef(preproc, "FOREGROUND" , newPal.color( QPalette::Active, QPalette::WindowText ) ); addColorDef(preproc, "BACKGROUND" , backCol); addColorDef(preproc, "HIGHLIGHT" , backCol.lighter(100+(2*KColorScheme::contrast()+4)*16/1)); addColorDef(preproc, "LOWLIGHT" , backCol.darker(100+(2*KColorScheme::contrast()+4)*10)); addColorDef(preproc, "SELECT_BACKGROUND" , newPal.color( QPalette::Active, QPalette::Highlight)); addColorDef(preproc, "SELECT_FOREGROUND" , newPal.color( QPalette::Active, QPalette::HighlightedText)); addColorDef(preproc, "WINDOW_BACKGROUND" , newPal.color( QPalette::Active, QPalette::Base ) ); addColorDef(preproc, "WINDOW_FOREGROUND" , newPal.color( QPalette::Active, QPalette::Text ) ); addColorDef(preproc, "INACTIVE_BACKGROUND", g.readEntry("inactiveBackground", QColor(224, 223, 222))); addColorDef(preproc, "INACTIVE_FOREGROUND", g.readEntry("inactiveBackground", QColor(224, 223, 222))); addColorDef(preproc, "ACTIVE_BACKGROUND" , g.readEntry("activeBackground", QColor(48, 174, 232))); addColorDef(preproc, "ACTIVE_FOREGROUND" , g.readEntry("activeBackground", QColor(48, 174, 232))); //--------------------------------------------------------------- tmpFile.write( preproc.toLatin1(), preproc.length() ); QStringList list; const QStringList adPaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kdisplay/app-defaults/"), QStandardPaths::LocateDirectory); for (QStringList::ConstIterator it = adPaths.constBegin(); it != adPaths.constEnd(); ++it) { QDir dSys( *it ); if ( dSys.exists() ) { dSys.setFilter( QDir::Files ); dSys.setSorting( QDir::Name ); dSys.setNameFilters(QStringList(QStringLiteral("*.ad"))); list += dSys.entryList(); } } for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) copyFile(tmpFile, QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kdisplay/app-defaults/"+(*it)), true); } // Merge ~/.Xresources or fallback to ~/.Xdefaults QString homeDir = QDir::homePath(); QString xResources = homeDir + "/.Xresources"; // very primitive support for ~/.Xresources by appending it if ( QFile::exists( xResources ) ) copyFile(tmpFile, xResources, true); else copyFile(tmpFile, homeDir + "/.Xdefaults", true); // Export the Xcursor theme & size settings KConfigGroup mousecfg(KSharedConfig::openConfig( QStringLiteral("kcminputrc") ), "Mouse" ); QString theme = mousecfg.readEntry("cursorTheme", QString()); QString size = mousecfg.readEntry("cursorSize", QString()); QString contents; if (!theme.isNull()) contents = "Xcursor.theme: " + theme + '\n'; if (!size.isNull()) contents += "Xcursor.size: " + size + '\n'; if (exportXftSettings) { contents += QLatin1String("Xft.antialias: "); if(generalCfgGroup.readEntry("XftAntialias", true)) contents += QLatin1String("1\n"); else contents += QLatin1String("0\n"); QString hintStyle = generalCfgGroup.readEntry("XftHintStyle", "hintslight"); contents += QLatin1String("Xft.hinting: "); if(hintStyle.isEmpty()) contents += QLatin1String("-1\n"); else { if(hintStyle!=QLatin1String("hintnone")) contents += QLatin1String("1\n"); else contents += QLatin1String("0\n"); contents += "Xft.hintstyle: " + hintStyle + '\n'; } QString subPixel = generalCfgGroup.readEntry("XftSubPixel", "rgb"); if(!subPixel.isEmpty()) contents += "Xft.rgba: " + subPixel + '\n'; KConfig _cfgfonts( QStringLiteral("kcmfonts") ); KConfigGroup cfgfonts(&_cfgfonts, "General"); int dpi; //even though this sets up the X rdb, we want to use the value the //user has set to use when under wayland - as X apps will be scaled by the compositor if (KWindowSystem::isPlatformWayland()) { dpi = cfgfonts.readEntry( "forceFontDPIWayland", 0); if (dpi == 0) { //with wayland we want xwayland to run at 96 dpi (unless set otherwise) as we have wayland scaling on top dpi = 96; } } else { dpi = cfgfonts.readEntry( "forceFontDPI", 0); } if( dpi != 0 ) contents += "Xft.dpi: " + QString::number(dpi) + '\n'; else { KProcess proc; proc << QStringLiteral("xrdb") << QStringLiteral("-quiet") << QStringLiteral("-remove") << QStringLiteral("-nocpp"); proc.start(); if (proc.waitForStarted()) { proc.write( QByteArray( "Xft.dpi\n" ) ); proc.closeWriteChannel(); proc.waitForFinished(); } } } if (contents.length() > 0) tmpFile.write( contents.toLatin1(), contents.length() ); tmpFile.flush(); KProcess proc; #ifndef NDEBUG proc << QStringLiteral("xrdb") << QStringLiteral("-merge") << tmpFile.fileName(); #else proc << "xrdb" << "-quiet" << "-merge" << tmpFile.fileName(); #endif proc.execute(); applyGtkStyles(exportColors, 1); applyGtkStyles(exportColors, 2); /* Qt exports */ if ( exportQtColors || exportQtSettings ) { QSettings* settings = new QSettings(QStringLiteral("Trolltech")); if ( exportQtColors ) applyQtColors( kglobalcfg, *settings, newPal ); // For kcmcolors if ( exportQtSettings ) applyQtSettings( kglobalcfg, *settings ); // For kcmstyle delete settings; QApplication::flush(); #if HAVE_X11 - if (qApp->platformName() == QStringLiteral("xcb")) { + if (qApp->platformName() == QLatin1String("xcb")) { // We let KIPC take care of ourselves, as we are in a KDE app with // QApp::setDesktopSettingsAware(false); // Instead of calling QApp::x11_apply_settings() directly, we instead // modify the timestamp which propagates the settings changes onto // Qt-only apps without adversely affecting ourselves. // Cheat and use the current timestamp, since we just saved to qtrc. QDateTime settingsstamp = QDateTime::currentDateTime(); static Atom qt_settings_timestamp = 0; if (!qt_settings_timestamp) { QString atomname(QStringLiteral("_QT_SETTINGS_TIMESTAMP_")); atomname += XDisplayName( nullptr ); // Use the $DISPLAY envvar. qt_settings_timestamp = XInternAtom( QX11Info::display(), atomname.toLatin1(), False); } QBuffer stamp; QDataStream s(&stamp.buffer(), QIODevice::WriteOnly); s << settingsstamp; XChangeProperty( QX11Info::display(), QX11Info::appRootWindow(), qt_settings_timestamp, qt_settings_timestamp, 8, PropModeReplace, (unsigned char*) stamp.buffer().data(), stamp.buffer().size() ); QApplication::flush(); } #endif } //Legacy support: //Try to sync kde4 settings with ours Kdelibs4Migration migration; //kf5 congig groups for general and icons KConfigGroup generalGroup(kglobalcfg, "General"); KConfigGroup iconsGroup(kglobalcfg, "Icons"); const QString colorSchemeName = generalGroup.readEntry("ColorScheme", QString()); //if no valid color scheme saved, something weird is going on, abort if (colorSchemeName.isEmpty()) { return; } QString colorSchemeSrcFile; if (colorSchemeName != QLatin1String("Default")) { //fix filename, copied from ColorsCM::saveScheme() QString colorSchemeFilename = colorSchemeName; colorSchemeFilename.remove('\''); // So Foo's does not become FooS QRegExp fixer(QStringLiteral("[\\W,.-]+(.?)")); int offset; while ((offset = fixer.indexIn(colorSchemeFilename)) >= 0) colorSchemeFilename.replace(offset, fixer.matchedLength(), fixer.cap(1).toUpper()); colorSchemeFilename.replace(0, 1, colorSchemeFilename.at(0).toUpper()); //clone the color scheme colorSchemeSrcFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "color-schemes/" + colorSchemeFilename + ".colors"); const QString dest = migration.saveLocation("data", QStringLiteral("color-schemes")) + colorSchemeName + ".colors"; QFile::remove(dest); QFile::copy(colorSchemeSrcFile, dest); } //Apply the color scheme QString configFilePath = migration.saveLocation("config") + "kdeglobals"; if (configFilePath.isEmpty()) { return; } KConfig kde4config(configFilePath, KConfig::SimpleConfig); KConfigGroup kde4generalGroup(&kde4config, "General"); kde4generalGroup.writeEntry("ColorScheme", colorSchemeName); //fonts QString font = generalGroup.readEntry("font", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("font", font); } font = generalGroup.readEntry("desktopFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("desktopFont", font); } font = generalGroup.readEntry("menuFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("menuFont", font); } font = generalGroup.readEntry("smallestReadableFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("smallestReadableFont", font); } font = generalGroup.readEntry("taskbarFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("taskbarFont", font); } font = generalGroup.readEntry("toolBarFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("toolBarFont", font); } //TODO: does exist any way to check if a qt4 widget style is present from a qt5 app? //kde4generalGroup.writeEntry("widgetStyle", "qtcurve"); kde4generalGroup.sync(); KConfigGroup kde4IconGroup(&kde4config, "Icons"); QString iconTheme = iconsGroup.readEntry("Theme", QString()); if (!iconTheme.isEmpty()) { kde4IconGroup.writeEntry("Theme", iconTheme); } kde4IconGroup.sync(); if (!colorSchemeSrcFile.isEmpty()) { //copy all the groups in the color scheme in kdeglobals KSharedConfigPtr kde4ColorConfig = KSharedConfig::openConfig(colorSchemeSrcFile, KConfig::SimpleConfig); foreach (const QString &grp, kde4ColorConfig->groupList()) { KConfigGroup cg(kde4ColorConfig, grp); KConfigGroup cg2(&kde4config, grp); cg.copyTo(&cg2); } } //widgets settings KConfigGroup kglobals4(&kde4config, "KDE"); kglobals4.writeEntry("ShowIconsInMenuItems", kglobals.readEntry("ShowIconsInMenuItems", true)); kglobals4.writeEntry("ShowIconsOnPushButtons", kglobals.readEntry("ShowIconsOnPushButtons", true)); kglobals4.writeEntry("contrast", kglobals.readEntry("contrast", 4)); //FIXME: this should somehow check if the kde4 version of the style is installed kde4generalGroup.writeEntry("widgetStyle", kglobals.readEntry("widgetStyle", "breeze")); //toolbar style KConfigGroup toolbars4(&kde4config, "Toolbar style"); KConfigGroup toolbars5(kglobalcfg, "Toolbar style"); toolbars4.writeEntry("ToolButtonStyle", toolbars5.readEntry("ToolButtonStyle", "TextBesideIcon")); toolbars4.writeEntry("ToolButtonStyleOtherToolbars", toolbars5.readEntry("ToolButtonStyleOtherToolbars", "TextBesideIcon")); if (exportGtkColors) { saveGtkColors(); } -} \ No newline at end of file +} diff --git a/kcms/krdb/krdb_clearlibrarypath.cpp b/kcms/krdb/krdb_clearlibrarypath.cpp index 8fa017a16..1a6fdb3eb 100644 --- a/kcms/krdb/krdb_clearlibrarypath.cpp +++ b/kcms/krdb/krdb_clearlibrarypath.cpp @@ -1,75 +1,75 @@ /* This file is part of the KDE project Copyright (C) 2008 Matthias Kretz Copyright (C) 2011 David Faure 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.), Trolltech ASA (or its successors, if any) and the KDE Free Qt Foundation, 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 #include #include #include #include #include #include int main(int argc, char **argv) { QCoreApplication app(argc, argv); QSettings settings(QStringLiteral("Trolltech")); QString qversion = qVersion(); if (qversion.count('.') > 1) { qversion.truncate(qversion.lastIndexOf('.')); } if (qversion.contains('-')) { qversion.truncate(qversion.lastIndexOf('-')); } const QString &libPathKey = QStringLiteral("/qt/%1/libraryPath").arg(qversion); QStringList kdeAdded; KComponentData kcd("krdb libraryPath fix"); const QStringList &plugins = KGlobal::dirs()->resourceDirs("qtplugins"); foreach (const QString &_path, plugins) { QString path = QDir(_path).canonicalPath(); if (path.isEmpty() || kdeAdded.contains(path)) { continue; } kdeAdded.prepend(path); - if (path.contains(QStringLiteral("/lib64/"))) { + if (path.contains(QLatin1String("/lib64/"))) { path.replace(QLatin1String("/lib64/"), QLatin1String("/lib/")); if (!kdeAdded.contains(path)) { kdeAdded.prepend(path); } } } // Don't use toStringList! That's a different storage format QStringList libraryPath = settings.value(libPathKey, QString()) .toString().split(QLatin1Char(':'), QString::SkipEmptyParts); // Remove all KDE paths, not needed anymore, done by $QT_PLUGIN_PATH foreach (const QString &path, const_cast(kdeAdded)) { libraryPath.removeAll(path); } settings.remove(QStringLiteral("/qt/KDE/kdeAddedLibraryPaths")); - settings.setValue(libPathKey, libraryPath.join(QStringLiteral(":"))); + settings.setValue(libPathKey, libraryPath.join(QLatin1String(":"))); return 0; } diff --git a/kcms/ksmserver/kcmsmserver.cpp b/kcms/ksmserver/kcmsmserver.cpp index 41480f840..6f53afe03 100644 --- a/kcms/ksmserver/kcmsmserver.cpp +++ b/kcms/ksmserver/kcmsmserver.cpp @@ -1,234 +1,234 @@ /* * kcmsmserver.cpp * Copyright (c) 2000,2002 Oswald Buddenhagen * * based on kcmtaskbar.cpp * Copyright (c) 2000 Kurt Granroth * * 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, write to the Free Software */ #include #include #include #include #include #include //Added by qt3to4: #include #include #include #include #include #include #include #include #include #include #include #include #include "kcmsmserver.h" #include "smserverconfigimpl.h" #include #include #include #include "kworkspace.h" #include #include "login1_manager.h" K_PLUGIN_FACTORY(SMSFactory, registerPlugin();) SMServerConfig::SMServerConfig(QWidget *parent, const QVariantList &args) : KCModule(parent, args) , m_login1Manager(new OrgFreedesktopLogin1ManagerInterface(QStringLiteral("org.freedesktop.login1"), QStringLiteral("/org/freedesktop/login1"), QDBusConnection::systemBus(), this)) { setQuickHelp( i18n("

Session Manager

" " You can configure the session manager here." " This includes options such as whether or not the session exit (logout)" " should be confirmed, whether the session should be restored again when logging in" " and whether the computer should be automatically shut down after session" " exit by default.")); QVBoxLayout *topLayout = new QVBoxLayout(this); topLayout->setContentsMargins(0, 0, 0, 0); dialog = new SMServerConfigImpl(this); connect(dialog, SIGNAL(changed()), SLOT(changed())); initFirmwareSetup(); checkFirmwareSetupRequested(); topLayout->addWidget(dialog); } void SMServerConfig::initFirmwareSetup() { m_rebootNowAction = new QAction(QIcon::fromTheme(QStringLiteral("system-reboot")), i18n("Restart Now")); connect(m_rebootNowAction, &QAction::triggered, this, [this] { auto sm = new SessionManagement(this); auto doShutdown=[sm]() { sm->requestReboot(); delete sm; }; if (sm->state() == SessionManagement::State::Loading) { connect(sm, &SessionManagement::stateChanged, this, doShutdown); } else { doShutdown(); } }); connect(dialog->firmwareSetupCheck, &QCheckBox::clicked, this, [this](bool enable) { dialog->firmwareSetupMessageWidget->removeAction(m_rebootNowAction); dialog->firmwareSetupMessageWidget->animatedHide(); QDBusMessage message = QDBusMessage::createMethodCall(m_login1Manager->service(), m_login1Manager->path(), m_login1Manager->interface(), QStringLiteral("SetRebootToFirmwareSetup")); message.setArguments({enable}); // This cannot be set through a generated DBus interface, so we have to create the message ourself. message.setInteractiveAuthorizationAllowed(true); QDBusPendingReply call = m_login1Manager->connection().asyncCall(message); QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(call, this); connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this, enable](QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; watcher->deleteLater(); checkFirmwareSetupRequested(); KMessageWidget *message = dialog->firmwareSetupMessageWidget; if (reply.isError()) { // User likely canceled the PolKit prompt, don't show an error in this case if (reply.error().type() != QDBusError::AccessDenied) { message->setMessageType(KMessageWidget::Error); message->setText(i18n("Failed to request restart to firmware setup: %1", reply.error().message())); message->animatedShow(); } return; } if (!enable) { return; } message->setMessageType(KMessageWidget::Information); if (m_isUefi) { message->setText(i18n("Next time the computer is restarted, it will enter the UEFI setup screen.")); } else { message->setText(i18n("Next time the computer is restarted, it will enter the firmware setup screen.")); } message->addAction(m_rebootNowAction); message->animatedShow(); }); }); const QString canFirmareSetup = m_login1Manager->CanRebootToFirmwareSetup().value(); if (canFirmareSetup == QLatin1String("yes") || canFirmareSetup == QLatin1String("challenge")) { // now check whether we're UEFI to provide a more descriptive button label if (QFileInfo(QStringLiteral("/sys/firmware/efi")).isDir()) { m_isUefi = true; dialog->firmwareSetupBox->setTitle(i18n("UEFI Setup")); dialog->firmwareSetupCheck->setText(i18n("Enter UEFI setup on next restart")); } dialog->firmwareSetupBox->setVisible(true); } } void SMServerConfig::checkFirmwareSetupRequested() { dialog->firmwareSetupCheck->setChecked(m_login1Manager->property("RebootToFirmwareSetup").toBool()); } void SMServerConfig::load() { KConfigGroup c(KSharedConfig::openConfig(QStringLiteral("ksmserverrc"), KConfig::NoGlobals), QStringLiteral("General")); dialog->confirmLogoutCheck->setChecked(c.readEntry("confirmLogout", true)); bool en = c.readEntry("offerShutdown", true); dialog->offerShutdownCheck->setChecked(en); dialog->sdGroup->setEnabled(en); QString s = c.readEntry( "loginMode" ); - if ( s == QStringLiteral("default") ) + if ( s == QLatin1String("default") ) dialog->emptySessionRadio->setChecked(true); - else if ( s == QStringLiteral("restoreSavedSession") ) + else if ( s == QLatin1String("restoreSavedSession") ) dialog->savedSessionRadio->setChecked(true); else // "restorePreviousLogout" dialog->previousSessionRadio->setChecked(true); switch (c.readEntry("shutdownType", int(KWorkSpace::ShutdownTypeNone))) { case int(KWorkSpace::ShutdownTypeHalt): dialog->haltRadio->setChecked(true); break; case int(KWorkSpace::ShutdownTypeReboot): dialog->rebootRadio->setChecked(true); break; default: dialog->logoutRadio->setChecked(true); break; } dialog->excludeLineedit->setText( c.readEntry("excludeApps")); emit changed(false); } void SMServerConfig::save() { KConfig c(QStringLiteral("ksmserverrc"), KConfig::NoGlobals); KConfigGroup group = c.group(QStringLiteral("General")); group.writeEntry( "confirmLogout", dialog->confirmLogoutCheck->isChecked()); group.writeEntry( "offerShutdown", dialog->offerShutdownCheck->isChecked()); QString s = QStringLiteral("restorePreviousLogout"); if ( dialog->emptySessionRadio->isChecked() ) s = QStringLiteral("default"); else if ( dialog->savedSessionRadio->isChecked() ) s = QStringLiteral("restoreSavedSession"); group.writeEntry( "loginMode", s ); group.writeEntry( "shutdownType", dialog->haltRadio->isChecked() ? int(KWorkSpace::ShutdownTypeHalt) : dialog->rebootRadio->isChecked() ? int(KWorkSpace::ShutdownTypeReboot) : int(KWorkSpace::ShutdownTypeNone)); group.writeEntry("excludeApps", dialog->excludeLineedit->text()); c.sync(); # if 0 // update the k menu if necessary QDBusInterface kicker("org.kde.kicker", "/kicker", "org.kde.kicker"); kicker.call("configure"); #endif } void SMServerConfig::defaults() { dialog->previousSessionRadio->setChecked(true); dialog->confirmLogoutCheck->setChecked(true); dialog->offerShutdownCheck->setChecked(true); dialog->sdGroup->setEnabled(true); dialog->logoutRadio->setChecked(true); dialog->excludeLineedit->clear(); } #include "kcmsmserver.moc" diff --git a/kcms/solid_actions/ActionItem.cpp b/kcms/solid_actions/ActionItem.cpp index 941ec53ba..d0964962c 100644 --- a/kcms/solid_actions/ActionItem.cpp +++ b/kcms/solid_actions/ActionItem.cpp @@ -1,157 +1,157 @@ /*************************************************************************** * Copyright (C) 2009 by Ben Cooksley * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include "ActionItem.h" #include "SolidActionData.h" #include #include #include #include #include ActionItem::ActionItem(const QString& pathToDesktop, const QString& action, QObject *parent) { Q_UNUSED(parent); desktopMasterPath = pathToDesktop; actionName = action; // Create the desktop file desktopFileMaster = new KDesktopFile(desktopMasterPath); desktopWritePath = desktopFileMaster->locateLocal(desktopMasterPath); desktopFileWrite = new KDesktopFile(desktopWritePath); // Now we can fill the action groups list configGroups.append(desktopFileMaster->desktopGroup()); actionGroups.insertMulti(ActionItem::GroupDesktop, &configGroups.last()); configGroups.append(desktopFileMaster->actionGroup(actionName)); actionGroups.insertMulti(ActionItem::GroupAction, &configGroups.last()); configGroups.append(desktopFileWrite->desktopGroup()); actionGroups.insertMulti(ActionItem::GroupDesktop, &configGroups.last()); configGroups.append(desktopFileWrite->actionGroup(actionName)); actionGroups.insertMulti(ActionItem::GroupAction, &configGroups.last()); const QString predicateString = readKey(ActionItem::GroupDesktop, QStringLiteral("X-KDE-Solid-Predicate"), QLatin1String("")); predicateItem = Solid::Predicate::fromString( predicateString ); } ActionItem::~ActionItem() { delete desktopFileWrite; delete desktopFileMaster; } /// Public functions below bool ActionItem::isUserSupplied() const { return hasKey(ActionItem::GroupDesktop, QStringLiteral("X-KDE-Action-Custom")); } QString ActionItem::icon() const { return readKey(ActionItem::GroupAction, QStringLiteral("Icon"), QLatin1String("")); } QString ActionItem::exec() const { return readKey(ActionItem::GroupAction, QStringLiteral("Exec"), QLatin1String("")); } QString ActionItem::name() const { return readKey(ActionItem::GroupAction, QStringLiteral("Name"), QLatin1String("")); } Solid::Predicate ActionItem::predicate() const { return predicateItem; } QString ActionItem::involvedTypes() const { SolidActionData * actData = SolidActionData::instance(); QSet devTypeList = predicateItem.usedTypes(); QStringList deviceTypes; foreach( Solid::DeviceInterface::Type devType, devTypeList ) { deviceTypes << actData->nameFromInterface( devType ); } - return deviceTypes.join(QStringLiteral(", ")); + return deviceTypes.join(QLatin1String(", ")); } void ActionItem::setIcon(const QString& nameOfIcon) { setKey(ActionItem::GroupAction, QStringLiteral("Icon"), nameOfIcon); } void ActionItem::setName(const QString& nameOfAction) { setKey(ActionItem::GroupAction, QStringLiteral("Name"), nameOfAction); } void ActionItem::setExec(const QString& execUrl) { setKey(ActionItem::GroupAction, QStringLiteral("Exec"), execUrl); } void ActionItem::setPredicate( const QString& newPredicate ) { setKey(ActionItem::GroupDesktop, QStringLiteral("X-KDE-Solid-Predicate"), newPredicate); predicateItem = Solid::Predicate::fromString( newPredicate ); } /// Private functions below QString ActionItem::readKey(GroupType keyGroup, const QString& keyName, const QString& defaultValue) const { return configItem(ActionItem::DesktopRead, keyGroup, keyName)->readEntry(keyName, defaultValue); } void ActionItem::setKey(GroupType keyGroup, const QString& keyName, const QString& keyContents) { configItem(ActionItem::DesktopWrite, keyGroup)->writeEntry(keyName, keyContents); } bool ActionItem::hasKey(GroupType keyGroup, const QString& keyName) const { return configItem(ActionItem::DesktopRead, keyGroup, keyName)->hasKey(keyName); } KConfigGroup * ActionItem::configItem(DesktopAction actionType, GroupType keyGroup, const QString& keyName) const { int countAccess = 0; if (actionType == ActionItem::DesktopRead) { foreach(KConfigGroup * possibleGroup, actionGroups.values(keyGroup)) { if (possibleGroup->hasKey(keyName)) { return possibleGroup; break; } } } else if (actionType == ActionItem::DesktopWrite) { if (isUserSupplied()) { countAccess = 1; } return actionGroups.values(keyGroup)[countAccess]; } return actionGroups.values(keyGroup)[0]; // Implement a backstop so a valid value is always returned } diff --git a/kcms/solid_actions/DesktopFileGenerator.cpp b/kcms/solid_actions/DesktopFileGenerator.cpp index 43ebb8d35..75979f700 100644 --- a/kcms/solid_actions/DesktopFileGenerator.cpp +++ b/kcms/solid_actions/DesktopFileGenerator.cpp @@ -1,81 +1,81 @@ /*************************************************************************** * Copyright (C) 2009 by Ben Cooksley * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include #include #include #include #include "SolidActionData.h" int main( int argc, char *argv[] ) { QCoreApplication application(argc, argv); KLocalizedString::setApplicationDomain("kcm_solid_actions"); // About data KAboutData aboutData(QStringLiteral("solid-action-desktop-gen"), i18n("Solid Action Desktop File Generator"), QStringLiteral("0.4"), i18n("Tool to automatically generate Desktop Files from Solid DeviceInterface classes for translation"), KAboutLicense::GPL, i18n("(c) 2009, Ben Cooksley")); aboutData.addAuthor(i18n("Ben Cooksley"), i18n("Maintainer"), QStringLiteral("ben@eclipse.endoftheinternet.org")); KAboutData::setApplicationData(aboutData); QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.process(application); aboutData.processCommandLine(&parser); SolidActionData * availActions = SolidActionData::instance(); foreach( Solid::DeviceInterface::Type internalType, availActions->interfaceTypeList() ) { const QString typeName = Solid::DeviceInterface::typeToString( internalType ); KDesktopFile typeFile(QStandardPaths::GenericDataLocation, "solid/devices/solid-device-" + typeName + ".desktop" ); KConfigGroup tConfig = typeFile.desktopGroup(); tConfig.writeEntry( "Name", "Solid Device" ); tConfig.writeEntry( "X-KDE-ServiceTypes", "SolidDevice" ); tConfig.writeEntry( "Type", "Service" ); if( !tConfig.hasKey("X-KDE-Solid-Actions-Type") ) { tConfig.writeEntry( "X-KDE-Solid-Actions-Type", typeName ); } const QStringList typeValues = availActions->propertyInternalList( internalType ); - const QString actionText = typeValues.join(QStringLiteral(";")).append(";"); + const QString actionText = typeValues.join(QLatin1String(";")).append(";"); tConfig.writeEntry( "Actions", actionText ); qWarning() << "Desktop file created: " + typeFile.fileName(); foreach( const QString &tValue, typeValues ) { KConfigGroup vConfig = typeFile.actionGroup( tValue ); if( !vConfig.hasKey("Name") ) { vConfig.writeEntry( "Name", availActions->propertyName( internalType, tValue ) ); } vConfig.sync(); } tConfig.sync(); typeFile.sync(); } qWarning() << "Generation now completed"; return 0; } diff --git a/kcms/solid_actions/SolidActionData.cpp b/kcms/solid_actions/SolidActionData.cpp index d14a8f2c0..d28b7e3e5 100644 --- a/kcms/solid_actions/SolidActionData.cpp +++ b/kcms/solid_actions/SolidActionData.cpp @@ -1,176 +1,176 @@ /*************************************************************************** * Copyright (C) 2009 by Ben Cooksley * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include "SolidActionData.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static SolidActionData * actData = nullptr; SolidActionData::SolidActionData(bool includeFiles) { const int propertyOffset = Solid::DeviceInterface::staticMetaObject.propertyOffset(); QList interfaceList = fillInterfaceList(); foreach( const QMetaObject &interface, interfaceList ) { QString ifaceName = interface.className(); ifaceName.remove(0, ifaceName.lastIndexOf(':') + 1); Solid::DeviceInterface::Type ifaceDev = Solid::DeviceInterface::stringToType( ifaceName ); const QString cleanName = Solid::DeviceInterface::typeDescription( ifaceDev ); types.insert( ifaceDev, cleanName ); QMap deviceValues; for( int doneProps = propertyOffset; interface.propertyCount() > doneProps; doneProps = doneProps + 1 ) { QMetaProperty ifaceProp = interface.property(doneProps); deviceValues.insert( ifaceProp.name(), generateUserString(ifaceProp.name()) ); } values.insert( ifaceDev, deviceValues ); } if( includeFiles ) { // Fill the lists of possible device types / device values const QString deviceDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("/solid/devices/"), QStandardPaths::LocateDirectory); // List all the known device actions, then add their name and all values to the appropriate lists QDirIterator it(deviceDir, QStringList() << QStringLiteral("*.desktop")); while (it.hasNext()) { it.next(); const QString desktop = it.filePath(); KDesktopFile deviceFile(desktop); KConfigGroup deviceType = deviceFile.desktopGroup(); // Retrieve the configuration group where the user friendly name is const QString ifaceName = deviceType.readEntry("X-KDE-Solid-Actions-Type"); Solid::DeviceInterface::Type ifaceDev = Solid::DeviceInterface::stringToType( ifaceName ); const QString cleanName = Solid::DeviceInterface::typeDescription( ifaceDev ); types.insert( ifaceDev, cleanName ); // Read the user friendly name QMap deviceValues = values.value( ifaceDev ); foreach( const QString &text, deviceFile.readActions() ) { // We want every single action KConfigGroup actionType = deviceFile.actionGroup( text ); deviceValues.insert( text, actionType.readEntry("Name") ); // Add to the type - actions map } values.insert( ifaceDev, deviceValues ); } } } QList SolidActionData::propertyList( Solid::DeviceInterface::Type devInterface ) { return values.value( devInterface ).values(); } QList SolidActionData::propertyInternalList( Solid::DeviceInterface::Type devInterface ) { return values.value( devInterface ).keys(); } QString SolidActionData::propertyInternal( Solid::DeviceInterface::Type devInterface, QString property ) { return values.value( devInterface ).key( property ); } QString SolidActionData::propertyName( Solid::DeviceInterface::Type devInterface, QString property ) { return values.value( devInterface ).value( property ); } int SolidActionData::propertyPosition( Solid::DeviceInterface::Type devInterface, QString property ) { return values.value( devInterface ).keys().indexOf( property ); } QList SolidActionData::interfaceList() { return types.values(); } QList SolidActionData::interfaceTypeList() { return types.keys(); } Solid::DeviceInterface::Type SolidActionData::interfaceFromName( const QString& name ) { return types.key( name ); } QString SolidActionData::nameFromInterface( Solid::DeviceInterface::Type devInterface ) { return types.value( devInterface ); } int SolidActionData::interfacePosition( Solid::DeviceInterface::Type devInterface ) { return types.keys().indexOf( devInterface ); } QString SolidActionData::generateUserString( QString className ) { QString finalString; QRegExp camelCase(QStringLiteral("([A-Z])")); // Create the split regexp finalString = className.remove(0, className.lastIndexOf(':') + 1); // Remove any Class information - finalString = finalString.replace( camelCase, QStringLiteral(" \\1") ); // Use Camel Casing to add spaces + finalString.replace( camelCase, QStringLiteral(" \\1") ); // Use Camel Casing to add spaces finalString = KStringHandler::capwords( finalString ); // Capitalize everything return finalString.trimmed(); } SolidActionData * SolidActionData::instance() { if( actData == nullptr ) { actData = new SolidActionData( true ); } return actData; } QList SolidActionData::fillInterfaceList() { QList interfaces; interfaces.append( Solid::Battery::staticMetaObject ); interfaces.append( Solid::Block::staticMetaObject ); interfaces.append( Solid::Camera::staticMetaObject ); interfaces.append( Solid::PortableMediaPlayer::staticMetaObject ); interfaces.append( Solid::Processor::staticMetaObject ); interfaces.append( Solid::StorageAccess::staticMetaObject ); interfaces.append( Solid::StorageDrive::staticMetaObject ); interfaces.append( Solid::OpticalDrive::staticMetaObject ); interfaces.append( Solid::StorageVolume::staticMetaObject ); interfaces.append( Solid::OpticalDisc::staticMetaObject ); return interfaces; }