diff --git a/applets/kicker/plugin/computermodel.cpp b/applets/kicker/plugin/computermodel.cpp index be37af31b..4e6272c2a 100644 --- a/applets/kicker/plugin/computermodel.cpp +++ b/applets/kicker/plugin/computermodel.cpp @@ -1,301 +1,301 @@ /*************************************************************************** * Copyright (C) 2007 Kevin Ottens * * Copyright (C) 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 "computermodel.h" #include "actionlist.h" #include "simplefavoritesmodel.h" #include #include #include #include #include #include #include #include "krunner_interface.h" FilteredPlacesModel::FilteredPlacesModel(QObject *parent) : QSortFilterProxyModel(parent) , m_placesModel(new KFilePlacesModel(this)) { setSourceModel(m_placesModel); sort(0); } FilteredPlacesModel::~FilteredPlacesModel() { } QUrl FilteredPlacesModel::url(const QModelIndex &index) const { return KFilePlacesModel::convertedUrl(m_placesModel->url(mapToSource(index))); } bool FilteredPlacesModel::isDevice(const QModelIndex &index) const { return m_placesModel->isDevice(mapToSource(index)); } Solid::Device FilteredPlacesModel::deviceForIndex(const QModelIndex &index) const { return m_placesModel->deviceForIndex(mapToSource(index)); } bool FilteredPlacesModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { const QModelIndex index = m_placesModel->index(sourceRow, 0, sourceParent); return !m_placesModel->isHidden(index) && !m_placesModel->data(index, KFilePlacesModel::FixedDeviceRole).toBool(); } bool FilteredPlacesModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { bool lDevice = m_placesModel->isDevice(left); bool rDevice = m_placesModel->isDevice(right); if (lDevice && !rDevice) { return false; } else if (!lDevice && rDevice) { return true; } return (left.row() < right.row()); } RunCommandModel::RunCommandModel(QObject *parent) : AbstractModel(parent) { } RunCommandModel::~RunCommandModel() { } QString RunCommandModel::description() const { return QString(); } QVariant RunCommandModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == Qt::DisplayRole) { return i18n("Run Command..."); } else if (role == Qt::DecorationRole) { return QIcon::fromTheme(QStringLiteral("system-run")); } else if (role == Kicker::DescriptionRole) { return i18n("Run a command or a search query"); } else if (role == Kicker::GroupRole) { return i18n("Applications"); } return QVariant(); } int RunCommandModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : (KAuthorized::authorize(QStringLiteral("run_command")) ? 1 : 0); } Q_INVOKABLE bool RunCommandModel::trigger(int row, const QString &actionId, const QVariant &argument) { Q_UNUSED(actionId) Q_UNUSED(argument) if (row == 0 && KAuthorized::authorize(QStringLiteral("run_command"))) { org::kde::krunner::App krunner(QStringLiteral("org.kde.krunner"), QStringLiteral("/App"), QDBusConnection::sessionBus()); krunner.display(); return true; } return false; } ComputerModel::ComputerModel(QObject *parent) : ForwardingModel(parent) , m_concatProxy(new KConcatenateRowsProxyModel(this)) , m_runCommandModel(new RunCommandModel(this)) , m_systemAppsModel(new SimpleFavoritesModel(this)) , m_filteredPlacesModel(new FilteredPlacesModel(this)) , m_appNameFormat(AppEntry::NameOnly) , m_appletInterface(nullptr) { connect(m_systemAppsModel, &SimpleFavoritesModel::favoritesChanged, this, &ComputerModel::systemApplicationsChanged); m_systemAppsModel->setFavorites(QStringList() << QStringLiteral("systemsettings.desktop")); m_concatProxy->addSourceModel(m_runCommandModel); m_concatProxy->addSourceModel(m_systemAppsModel); m_concatProxy->addSourceModel(m_filteredPlacesModel); setSourceModel(m_concatProxy); } ComputerModel::~ComputerModel() { } QString ComputerModel::description() const { return i18n("Computer"); } int ComputerModel::appNameFormat() const { return m_appNameFormat; } void ComputerModel::setAppNameFormat(int format) { if (m_appNameFormat != (AppEntry::NameFormat)format) { m_appNameFormat = (AppEntry::NameFormat)format; m_systemAppsModel->refresh(); emit appNameFormatChanged(); } } QObject *ComputerModel::appletInterface() const { return m_appletInterface; } void ComputerModel::setAppletInterface(QObject *appletInterface) { if (m_appletInterface != appletInterface) { m_appletInterface = appletInterface; emit appletInterfaceChanged(); } } QStringList ComputerModel::systemApplications() const { return m_systemAppsModel->favorites(); } void ComputerModel::setSystemApplications(const QStringList &apps) { m_systemAppsModel->setFavorites(apps); } QVariant ComputerModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } const QModelIndex sourceIndex = m_concatProxy->mapToSource(m_concatProxy->index(index.row(), index.column())); bool isPlace = (sourceIndex.model() == m_filteredPlacesModel); if (isPlace) { if (role == Kicker::DescriptionRole) { if (m_filteredPlacesModel->isDevice(sourceIndex)) { Solid::Device device = m_filteredPlacesModel->deviceForIndex(sourceIndex); Solid::StorageAccess *access = device.as(); if (access) { return access->filePath(); } else { return QString(); } } else { const QUrl &url = m_filteredPlacesModel->url(sourceIndex); return url.toString(QUrl::PreferLocalFile); } } else if (role == Kicker::FavoriteIdRole) { if (!m_filteredPlacesModel->isDevice(sourceIndex)) { return m_filteredPlacesModel->url(sourceIndex); } } else if (role == Kicker::UrlRole) { return m_filteredPlacesModel->url(sourceIndex); } else if (role == Kicker::GroupRole) { return sourceIndex.data(KFilePlacesModel::GroupRole).toString(); } else if (role == Qt::DisplayRole || role == Qt::DecorationRole) { return sourceIndex.data(role); } } else if (role == Kicker::GroupRole) { return i18n("Applications"); } else { return sourceIndex.data(role); } return QVariant(); } bool ComputerModel::trigger(int row, const QString &actionId, const QVariant &argument) { const QModelIndex sourceIndex = m_concatProxy->mapToSource(m_concatProxy->index(row, 0)); if (sourceIndex.model() == m_filteredPlacesModel) { const QUrl &url = m_filteredPlacesModel->url(sourceIndex); if (url.isValid()) { - new KRun(url, 0); + new KRun(url, nullptr); return true; } Solid::Device device = m_filteredPlacesModel->deviceForIndex(sourceIndex); Solid::StorageAccess *access = device.as(); if (access && !access->isAccessible()) { connect(access, &Solid::StorageAccess::setupDone, this, &ComputerModel::onSetupDone); access->setup(); return true; } } else { AbstractModel *model = nullptr; if (sourceIndex.model() == m_systemAppsModel) { model = m_systemAppsModel; } else { model = m_runCommandModel; } return model->trigger(sourceIndex.row(), actionId, argument); } return false; } void ComputerModel::onSetupDone(Solid::ErrorType error, QVariant errorData, const QString &udi) { Q_UNUSED(errorData); if (error != Solid::NoError) { return; } Solid::Device device(udi); Solid::StorageAccess *access = device.as(); Q_ASSERT(access); - new KRun(QUrl::fromLocalFile(access->filePath()), 0); + new KRun(QUrl::fromLocalFile(access->filePath()), nullptr); } diff --git a/applets/kicker/plugin/fileentry.cpp b/applets/kicker/plugin/fileentry.cpp index 8913c4c86..c61dcf739 100644 --- a/applets/kicker/plugin/fileentry.cpp +++ b/applets/kicker/plugin/fileentry.cpp @@ -1,123 +1,123 @@ /*************************************************************************** * Copyright (C) 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 "fileentry.h" #include "actionlist.h" #include #include FileEntry::FileEntry(AbstractModel *owner, const QUrl &url) : AbstractEntry(owner) , m_fileItem(nullptr) { if (url.isValid()) { m_fileItem = new KFileItem(url); m_fileItem->determineMimeType(); } } FileEntry::~FileEntry() { delete m_fileItem; } bool FileEntry::isValid() const { return m_fileItem && (m_fileItem->isFile() || m_fileItem->isDir()); } QIcon FileEntry::icon() const { if (m_fileItem) { return QIcon::fromTheme(m_fileItem->iconName(), QIcon::fromTheme(QStringLiteral("unknown"))); } return QIcon::fromTheme(QStringLiteral("unknown")); } QString FileEntry::name() const { if (m_fileItem) { return m_fileItem->text(); } return QString(); } QString FileEntry::description() const { if (m_fileItem) { return m_fileItem->url().toString(QUrl::PreferLocalFile); } return QString(); } QString FileEntry::id() const { if (m_fileItem) { return m_fileItem->url().toString(); } return QString(); } QUrl FileEntry::url() const { if (m_fileItem) { return m_fileItem->url(); } return QUrl(); } bool FileEntry::hasActions() const { return m_fileItem && m_fileItem->isFile(); } QVariantList FileEntry::actions() const { if (m_fileItem) { return Kicker::createActionListForFileItem(*m_fileItem); } return QVariantList(); } bool FileEntry::run(const QString& actionId, const QVariant &argument) { if (!m_fileItem) { return false; } if (actionId.isEmpty()) { - new KRun(m_fileItem->url(), 0); + new KRun(m_fileItem->url(), nullptr); return true; } else { bool close = false; if (Kicker::handleFileItemAction(*m_fileItem, actionId, argument, &close)) { return close; } } return false; } diff --git a/applets/kicker/plugin/forwardingmodel.cpp b/applets/kicker/plugin/forwardingmodel.cpp index 6313ed72c..a0cb86a8f 100644 --- a/applets/kicker/plugin/forwardingmodel.cpp +++ b/applets/kicker/plugin/forwardingmodel.cpp @@ -1,265 +1,265 @@ /*************************************************************************** * Copyright (C) 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 "forwardingmodel.h" ForwardingModel::ForwardingModel(QObject *parent) : AbstractModel(parent) { } ForwardingModel::~ForwardingModel() { } QString ForwardingModel::description() const { if (!m_sourceModel) { return QString(); } AbstractModel *abstractModel = qobject_cast(m_sourceModel); if (!abstractModel) { return QString(); } return abstractModel->description(); } QAbstractItemModel *ForwardingModel::sourceModel() const { return m_sourceModel; } void ForwardingModel::setSourceModel(QAbstractItemModel *sourceModel) { disconnectSignals(); beginResetModel(); m_sourceModel = sourceModel; connectSignals(); endResetModel(); emit countChanged(); emit sourceModelChanged(); emit descriptionChanged(); } bool ForwardingModel::canFetchMore(const QModelIndex &parent) const { if (!m_sourceModel) { return false; } return m_sourceModel->canFetchMore(indexToSourceIndex(parent)); } void ForwardingModel::fetchMore(const QModelIndex &parent) { if (m_sourceModel) { m_sourceModel->fetchMore(indexToSourceIndex(parent)); } } QModelIndex ForwardingModel::index(int row, int column, const QModelIndex &parent) const { Q_UNUSED(parent) if (!m_sourceModel) { return QModelIndex(); } return createIndex(row, column); } QModelIndex ForwardingModel::parent(const QModelIndex &index) const { Q_UNUSED(index) return QModelIndex(); } QVariant ForwardingModel::data(const QModelIndex &index, int role) const { if (!m_sourceModel) { return QVariant(); } return m_sourceModel->data(indexToSourceIndex(index), role); } int ForwardingModel::rowCount(const QModelIndex &parent) const { if (!m_sourceModel) { return 0; } return m_sourceModel->rowCount(indexToSourceIndex(parent)); } QModelIndex ForwardingModel::indexToSourceIndex(const QModelIndex& index) const { if (!m_sourceModel || !index.isValid()) { return QModelIndex(); } return m_sourceModel->index(index.row(), index.column(), index.parent().isValid() ? indexToSourceIndex(index.parent()) : QModelIndex()); } bool ForwardingModel::trigger(int row, const QString &actionId, const QVariant &argument) { if (!m_sourceModel) { return false; } AbstractModel *abstractModel = qobject_cast(m_sourceModel); if (!abstractModel) { return false; } return abstractModel->trigger(row, actionId, argument); } QString ForwardingModel::labelForRow(int row) { if (!m_sourceModel) { return QString(); } AbstractModel *abstractModel = qobject_cast(m_sourceModel); if (!abstractModel) { return QString(); } return abstractModel->labelForRow(row); } AbstractModel* ForwardingModel::modelForRow(int row) { if (!m_sourceModel) { - return 0; + return nullptr; } AbstractModel *abstractModel = qobject_cast(m_sourceModel); if (!abstractModel) { - return 0; + return nullptr; } return abstractModel->modelForRow(row); } AbstractModel* ForwardingModel::favoritesModel() { AbstractModel *sourceModel = qobject_cast(m_sourceModel); if (sourceModel) { return sourceModel->favoritesModel(); } return AbstractModel::favoritesModel(); } int ForwardingModel::separatorCount() const { if (!m_sourceModel) { return 0; } AbstractModel *abstractModel = qobject_cast(m_sourceModel); if (!abstractModel) { return 0; } return abstractModel->separatorCount(); } void ForwardingModel::reset() { beginResetModel(); endResetModel(); emit countChanged(); emit separatorCountChanged(); } void ForwardingModel::connectSignals() { if (!m_sourceModel) { return; } connect(m_sourceModel, SIGNAL(destroyed()), this, SLOT(reset())); connect(m_sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), this, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), this, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(layoutAboutToBeChanged(QList,QAbstractItemModel::LayoutChangeHint)), this, SIGNAL(layoutAboutToBeChanged(QList,QAbstractItemModel::LayoutChangeHint)), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(rowsInserted(QModelIndex,int,int)), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged()), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(rowsRemoved(QModelIndex,int,int)), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged()), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(modelAboutToBeReset()), this, SIGNAL(modelAboutToBeReset()), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(modelReset()), this, SIGNAL(modelReset()), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(modelReset()), this, SIGNAL(countChanged()), Qt::UniqueConnection); connect(m_sourceModel, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), this, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), Qt::UniqueConnection); } void ForwardingModel::disconnectSignals() { if (!m_sourceModel) { return; } - disconnect(m_sourceModel, 0, this, 0); + disconnect(m_sourceModel, nullptr, this, nullptr); } diff --git a/applets/kicker/plugin/menuentryeditor.cpp b/applets/kicker/plugin/menuentryeditor.cpp index 358ee4a37..4b4a759e5 100644 --- a/applets/kicker/plugin/menuentryeditor.cpp +++ b/applets/kicker/plugin/menuentryeditor.cpp @@ -1,68 +1,68 @@ /*************************************************************************** * 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 "menuentryeditor.h" #include #include #include #include MenuEntryEditor::MenuEntryEditor(QObject* parent) : QObject(parent) { } MenuEntryEditor::~MenuEntryEditor() { } bool MenuEntryEditor::canEdit(const QString& entryPath) const { KFileItemList itemList; itemList << KFileItem(QUrl::fromLocalFile(entryPath)); return KPropertiesDialog::canDisplay(itemList); } void MenuEntryEditor::edit(const QString& entryPath, const QString& menuId) { const QString &appsPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); const QUrl &entryUrl = QUrl::fromLocalFile(entryPath); if (!appsPath.isEmpty() && entryUrl.isValid()) { const QDir appsDir(appsPath); const QString &fileName = entryUrl.fileName(); if (appsDir.exists(fileName)) { - KPropertiesDialog::showDialog(entryUrl, 0, false); + KPropertiesDialog::showDialog(entryUrl, nullptr, false); } else { if (!appsDir.exists()) { if (!QDir::root().mkpath(appsPath)) { return; } } KPropertiesDialog *dialog = new KPropertiesDialog(entryUrl, QUrl::fromLocalFile(appsPath), menuId); //KPropertiesDialog deletes itself dialog->show(); } } } diff --git a/applets/kicker/plugin/placeholdermodel.cpp b/applets/kicker/plugin/placeholdermodel.cpp index e0b5f763a..4168e20eb 100644 --- a/applets/kicker/plugin/placeholdermodel.cpp +++ b/applets/kicker/plugin/placeholdermodel.cpp @@ -1,407 +1,407 @@ /*************************************************************************** * Copyright (C) 2015 by Eike Hein * * Copyright (C) 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 "placeholdermodel.h" #include "actionlist.h" #include "debug.h" #include PlaceholderModel::PlaceholderModel(QObject *parent) : AbstractModel(parent) , m_dropPlaceholderIndex(-1) , m_isTriggerInhibited(false) { connect(&m_triggerInhibitor, &QTimer::timeout, this, [&] { qCDebug(KICKER_DEBUG) << "%%% Inhibit stopped"; m_isTriggerInhibited = false; }); m_triggerInhibitor.setInterval(500); m_triggerInhibitor.setSingleShot(true); } void PlaceholderModel::inhibitTriggering() { qCDebug(KICKER_DEBUG) << "%%% Inhibit started"; m_isTriggerInhibited = true; m_triggerInhibitor.start(); } PlaceholderModel::~PlaceholderModel() { } QString PlaceholderModel::description() const { if (auto abstractModel = qobject_cast(m_sourceModel)) { return abstractModel->description(); } else { return QString(); } } QAbstractItemModel *PlaceholderModel::sourceModel() const { return m_sourceModel; } void PlaceholderModel::setSourceModel(QAbstractItemModel *sourceModel) { disconnectSignals(); beginResetModel(); m_sourceModel = sourceModel; connectSignals(); endResetModel(); emit countChanged(); emit sourceModelChanged(); emit descriptionChanged(); } bool PlaceholderModel::canFetchMore(const QModelIndex &parent) const { return m_sourceModel && m_sourceModel->canFetchMore(indexToSourceIndex(parent)); } void PlaceholderModel::fetchMore(const QModelIndex &parent) { if (m_sourceModel) { m_sourceModel->fetchMore(indexToSourceIndex(parent)); } } QModelIndex PlaceholderModel::index(int row, int column, const QModelIndex &parent) const { Q_UNUSED(parent) return m_sourceModel ? createIndex(row, column) : QModelIndex(); } QModelIndex PlaceholderModel::parent(const QModelIndex &index) const { Q_UNUSED(index) return QModelIndex(); } QVariant PlaceholderModel::data(const QModelIndex &index, int role) const { const auto row = index.row(); if (m_dropPlaceholderIndex == row) { switch (role) { case Kicker::IsDropPlaceholderRole: return true; // TODO: Maybe it would be nice to show something here? // case Qt::DisplayRole: // return "placeholder"; // // case Qt::DecorationRole: // return "select"; default: return QVariant(); } } return m_sourceModel ? m_sourceModel->data(indexToSourceIndex(index), role) : QVariant(); } int PlaceholderModel::rowCount(const QModelIndex &parent) const { if (!m_sourceModel || parent.isValid()) { return 0; } return m_sourceModel->rowCount() + (m_dropPlaceholderIndex != -1 ? 1 : 0); } QModelIndex PlaceholderModel::indexToSourceIndex(const QModelIndex& index) const { if (!m_sourceModel || !index.isValid()) { return QModelIndex(); } const auto row = index.row(); const auto column = index.column(); return index.parent().isValid() ? // We do not support tree models QModelIndex() : // If we are on top-level, lets add a placeholder m_sourceModel->index( row - (m_dropPlaceholderIndex != -1 && row > m_dropPlaceholderIndex ? 1 : 0), column, QModelIndex() ); } int PlaceholderModel::sourceRowToRow(int sourceRow) const { return sourceRow + (m_dropPlaceholderIndex != -1 && sourceRow >= m_dropPlaceholderIndex ? 1 : 0); } int PlaceholderModel::rowToSourceRow(int row) const { return row == m_dropPlaceholderIndex ? -1 : row - (m_dropPlaceholderIndex != -1 && row > m_dropPlaceholderIndex ? 1 : 0); } QModelIndex PlaceholderModel::sourceIndexToIndex(const QModelIndex& sourceIndex) const { if (!m_sourceModel || !sourceIndex.isValid()) { return QModelIndex(); } const auto sourceRow = sourceIndex.row(); const auto sourceColumn = sourceIndex.column(); return sourceIndex.parent().isValid() ? // We do not support tree-models QModelIndex() : // If we are on top-level, lets add a placeholder index( sourceRowToRow(sourceRow), sourceColumn, QModelIndex() ); } bool PlaceholderModel::trigger(int row, const QString &actionId, const QVariant &argument) { if (m_isTriggerInhibited) return false; if (auto abstractModel = qobject_cast(m_sourceModel)) { return abstractModel->trigger(rowToSourceRow(row), actionId, argument); } else { return false; } } QString PlaceholderModel::labelForRow(int row) { if (auto abstractModel = qobject_cast(m_sourceModel)) { return abstractModel->labelForRow(rowToSourceRow(row)); } else { return QString(); } } AbstractModel* PlaceholderModel::modelForRow(int row) { if (auto abstractModel = qobject_cast(m_sourceModel)) { return abstractModel->modelForRow(rowToSourceRow(row)); } else { - return 0; + return nullptr; } } AbstractModel* PlaceholderModel::favoritesModel() { if (auto abstractModel = qobject_cast(m_sourceModel)) { return abstractModel->favoritesModel(); } else { return AbstractModel::favoritesModel(); } } int PlaceholderModel::separatorCount() const { if (auto abstractModel = qobject_cast(m_sourceModel)) { return abstractModel->separatorCount(); } else { return 0; } } void PlaceholderModel::reset() { emit beginResetModel(); emit endResetModel(); emit countChanged(); emit separatorCountChanged(); } void PlaceholderModel::connectSignals() { if (!m_sourceModel) { return; } const auto sourceModelPtr = m_sourceModel.data(); connect(sourceModelPtr, SIGNAL(destroyed()), this, SLOT(reset())); connect(sourceModelPtr, &QAbstractItemModel::dataChanged, this, [this] (const QModelIndex &from, const QModelIndex &to, const QVector &roles) { emit dataChanged(sourceIndexToIndex(from), sourceIndexToIndex(to), roles); }); connect(sourceModelPtr, &QAbstractItemModel::rowsAboutToBeInserted, this, [this] (const QModelIndex &parent, int from, int to) { if (parent.isValid()) { qWarning() << "We do not support tree models"; } else { beginInsertRows(QModelIndex(), sourceRowToRow(from), sourceRowToRow(to)); } }); connect(sourceModelPtr, &QAbstractItemModel::rowsInserted, this, [this] { endInsertRows(); emit countChanged(); }); connect(sourceModelPtr, &QAbstractItemModel::rowsAboutToBeMoved, this, [this] (const QModelIndex &source, int from, int to, const QModelIndex &dest, int destRow) { if (source.isValid() || dest.isValid()) { qWarning() << "We do not support tree models"; } else { beginMoveRows(QModelIndex(), sourceRowToRow(from), sourceRowToRow(to), QModelIndex(), sourceRowToRow(destRow)); } }); connect(sourceModelPtr, &QAbstractItemModel::rowsMoved, this, [this] { endMoveRows(); }); connect(sourceModelPtr, &QAbstractItemModel::rowsAboutToBeRemoved, this, [this] (const QModelIndex &parent, int from, int to) { if (parent.isValid()) { qWarning() << "We do not support tree models"; } else { beginRemoveRows(QModelIndex(), sourceRowToRow(from), sourceRowToRow(to)); } }); connect(sourceModelPtr, &QAbstractItemModel::rowsRemoved, this, [this] { endRemoveRows(); emit countChanged(); }); connect(sourceModelPtr, &QAbstractItemModel::modelAboutToBeReset, this, [this] { beginResetModel(); }); connect(sourceModelPtr, &QAbstractItemModel::modelReset, this, [this] { endResetModel(); emit countChanged(); }); // We do not have persistant indices // connect(sourceModelPtr, &QAbstractItemModel::layoutAboutToBeChanged), // this, &PlaceholderModel::layoutAboutToBeChanged); // connect(sourceModelPtr, &QAbstractItemModel::layoutChanged), // this, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), // Qt::UniqueConnection); } void PlaceholderModel::disconnectSignals() { if (!m_sourceModel) { return; } - disconnect(m_sourceModel, 0, this, 0); + disconnect(m_sourceModel, nullptr, this, nullptr); } int PlaceholderModel::dropPlaceholderIndex() const { return m_dropPlaceholderIndex; } void PlaceholderModel::setDropPlaceholderIndex(int index) { if (index == m_dropPlaceholderIndex) return; inhibitTriggering(); if (index == -1 && m_dropPlaceholderIndex != -1) { // Removing the placeholder beginRemoveRows(QModelIndex(), m_dropPlaceholderIndex, m_dropPlaceholderIndex); m_dropPlaceholderIndex = index; endRemoveRows(); emit countChanged(); } else if (index != -1 && m_dropPlaceholderIndex == -1) { // Creating the placeholder beginInsertRows(QModelIndex(), index, index); m_dropPlaceholderIndex = index; endInsertRows(); emit countChanged(); } else if (m_dropPlaceholderIndex != index) { // Moving the placeholder int modelTo = index + (index > m_dropPlaceholderIndex ? 1 : 0); if (beginMoveRows( QModelIndex(), m_dropPlaceholderIndex, m_dropPlaceholderIndex, QModelIndex(), modelTo)) { m_dropPlaceholderIndex = index; endMoveRows(); } } emit dropPlaceholderIndexChanged(); } diff --git a/applets/kimpanel/backend/ibus/ibus15/app.cpp b/applets/kimpanel/backend/ibus/ibus15/app.cpp index 5ef6dc619..b12d1de8c 100644 --- a/applets/kimpanel/backend/ibus/ibus15/app.cpp +++ b/applets/kimpanel/backend/ibus/ibus15/app.cpp @@ -1,477 +1,477 @@ /* * Copyright (C) 2013-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 "app.h" #include "gtkaccelparse_p.h" #include "gdkkeysyms_p.h" #include #include #include #include #include #include #define USED_MASK (XCB_MOD_MASK_SHIFT | XCB_MOD_MASK_CONTROL | XCB_MOD_MASK_1 | XCB_MOD_MASK_4) bool XcbEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long int *result) { Q_UNUSED(result); if (eventType != "xcb_generic_event_t") { return false; } return qobject_cast(qApp)->nativeEvent(static_cast(message)); } // callback functions from glib code static void name_acquired_cb (GDBusConnection* connection, const gchar* sender_name, const gchar* object_path, const gchar* interface_name, const gchar* signal_name, GVariant* parameters, gpointer self) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); App* app = (App*) self; app->nameAcquired(); } static void name_lost_cb (GDBusConnection* connection, const gchar* sender_name, const gchar* object_path, const gchar* interface_name, const gchar* signal_name, GVariant* parameters, gpointer self) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); App* app = (App*) self; app->nameLost(); } static void ibus_connected_cb (IBusBus *m_bus, gpointer user_data) { Q_UNUSED(m_bus); App* app = (App*) user_data; app->init(); } static void ibus_disconnected_cb (IBusBus *m_bus, gpointer user_data) { Q_UNUSED(m_bus); App* app = (App*) user_data; app->finalize(); } static void initIconMap(QMap& iconMap) { iconMap["gtk-about"] = "help-about"; iconMap["gtk-add"] = "list-add"; iconMap["gtk-bold"] = "format-text-bold"; iconMap["gtk-cdrom"] = "media-optical"; iconMap["gtk-clear"] = "edit-clear"; iconMap["gtk-close"] = "window-close"; iconMap["gtk-copy"] = "edit-copy"; iconMap["gtk-cut"] = "edit-cut"; iconMap["gtk-delete"] = "edit-delete"; iconMap["gtk-dialog-authentication"] = "dialog-password"; iconMap["gtk-dialog-info"] = "dialog-information"; iconMap["gtk-dialog-warning"] = "dialog-warning"; iconMap["gtk-dialog-error"] = "dialog-error"; iconMap["gtk-dialog-question"] = "dialog-question"; iconMap["gtk-directory"] = "folder"; iconMap["gtk-execute"] = "system-run"; iconMap["gtk-file"] = "text-x-generic"; iconMap["gtk-find"] = "edit-find"; iconMap["gtk-find-and-replace"] = "edit-find-replace"; iconMap["gtk-floppy"] = "media-floppy"; iconMap["gtk-fullscreen"] = "view-fullscreen"; iconMap["gtk-goto-bottom"] = "go-bottom"; iconMap["gtk-goto-first"] = "go-first"; iconMap["gtk-goto-last"] = "go-last"; iconMap["gtk-goto-top"] = "go-top"; iconMap["gtk-go-back"] = "go-previous"; iconMap["gtk-go-down"] = "go-down"; iconMap["gtk-go-forward"] = "go-next"; iconMap["gtk-go-up"] = "go-up"; iconMap["gtk-harddisk"] = "drive-harddisk"; iconMap["gtk-help"] = "help-browser"; iconMap["gtk-home"] = "go-home"; iconMap["gtk-indent"] = "format-indent-more"; iconMap["gtk-info"] = "dialog-information"; iconMap["gtk-italic"] = "format-text-italic"; iconMap["gtk-jump-to"] = "go-jump"; iconMap["gtk-justify-center"] = "format-justify-center"; iconMap["gtk-justify-fill"] = "format-justify-fill"; iconMap["gtk-justify-left"] = "format-justify-left"; iconMap["gtk-justify-right"] = "format-justify-right"; iconMap["gtk-leave-fullscreen"] = "view-restore"; iconMap["gtk-missing-image"] = "image-missing"; iconMap["gtk-media-forward"] = "media-seek-forward"; iconMap["gtk-media-next"] = "media-skip-forward"; iconMap["gtk-media-pause"] = "media-playback-pause"; iconMap["gtk-media-play"] = "media-playback-start"; iconMap["gtk-media-previous"] = "media-skip-backward"; iconMap["gtk-media-record"] = "media-record"; iconMap["gtk-media-rewind"] = "media-seek-backward"; iconMap["gtk-media-stop"] = "media-playback-stop"; iconMap["gtk-network"] = "network-workgroup"; iconMap["gtk-new"] = "document-new"; iconMap["gtk-open"] = "document-open"; iconMap["gtk-page-setup"] = "document-page-setup"; iconMap["gtk-paste"] = "edit-paste"; iconMap["gtk-preferences"] = "preferences-system"; iconMap["gtk-print"] = "document-print"; iconMap["gtk-print-error"] = "printer-error"; iconMap["gtk-properties"] = "document-properties"; iconMap["gtk-quit"] = "application-exit"; iconMap["gtk-redo"] = "edit-redo"; iconMap["gtk-refresh"] = "view-refresh"; iconMap["gtk-remove"] = "list-remove"; iconMap["gtk-revert-to-saved"] = "document-revert"; iconMap["gtk-save"] = "document-save"; iconMap["gtk-save-as"] = "document-save-as"; iconMap["gtk-select-all"] = "edit-select-all"; iconMap["gtk-sort-ascending"] = "view-sort-ascending"; iconMap["gtk-sort-descending"] = "view-sort-descending"; iconMap["gtk-spell-check"] = "tools-check-spelling"; iconMap["gtk-stop"] = "process-stop"; iconMap["gtk-strikethrough"] = "format-text-strikethrough"; iconMap["gtk-underline"] = "format-text-underline"; iconMap["gtk-undo"] = "edit-undo"; iconMap["gtk-unindent"] = "format-indent-less"; iconMap["gtk-zoom-100"] = "zoom-original"; iconMap["gtk-zoom-fit"] = "zoom-fit-best"; iconMap["gtk-zoom-in"] = "zoom-in"; iconMap["gtk-zoom-out"] = "zoom-out"; } App::App(int &argc, char* argv[]): QGuiApplication(argc, argv) ,m_eventFilter(new XcbEventFilter) ,m_init(false) ,m_bus(ibus_bus_new ()) - ,m_impanel(0) + ,m_impanel(nullptr) ,m_keyboardGrabbed(false) ,m_doGrab(false) - ,m_syms(0) + ,m_syms(nullptr) ,m_watcher(new QDBusServiceWatcher(this)) { m_syms = xcb_key_symbols_alloc(QX11Info::connection()); installNativeEventFilter(m_eventFilter.data()); initIconMap(m_iconMap); m_watcher->setConnection(QDBusConnection::sessionBus()); m_watcher->addWatchedService("org.kde.impanel"); init(); } uint App::getPrimaryModifier(uint state) { const GdkModifierType masks[] = { GDK_MOD5_MASK, GDK_MOD4_MASK, GDK_MOD3_MASK, GDK_MOD2_MASK, GDK_MOD1_MASK, GDK_CONTROL_MASK, GDK_LOCK_MASK, GDK_LOCK_MASK }; for (size_t i = 0; i < sizeof(masks) / sizeof(masks[0]); i++) { GdkModifierType mask = masks[i]; if ((state & mask) == mask) return mask; } return 0; } bool App::nativeEvent(xcb_generic_event_t* event) { if ((event->response_type & ~0x80) == XCB_KEY_PRESS) { auto keypress = reinterpret_cast(event); if (keypress->event == QX11Info::appRootWindow()) { auto sym = xcb_key_press_lookup_keysym(m_syms, keypress, 0); uint state = keypress->state & USED_MASK; bool forward; if ((forward = m_triggersList.contains(qMakePair(sym, state))) || m_triggersList.contains(qMakePair(sym, state & (~XCB_MOD_MASK_SHIFT)))) { if (m_keyboardGrabbed) { ibus_panel_impanel_navigate(m_impanel, false, forward); } else { if (grabXKeyboard()) { ibus_panel_impanel_navigate(m_impanel, true, forward); } else { ibus_panel_impanel_move_next(m_impanel); } } } } } else if ((event->response_type & ~0x80) == XCB_KEY_RELEASE) { auto keyrelease = reinterpret_cast(event); if (keyrelease->event == QX11Info::appRootWindow()) { keyRelease(keyrelease); } } return false; } void App::keyRelease(const xcb_key_release_event_t* event) { unsigned int mk = event->state & USED_MASK; // ev.state is state before the key release, so just checking mk being 0 isn't enough // using XQueryPointer() also doesn't seem to work well, so the check that all // modifiers are released: only one modifier is active and the currently released // key is this modifier - if yes, release the grab int mod_index = -1; for (int i = XCB_MAP_INDEX_SHIFT; i <= XCB_MAP_INDEX_5; ++i) if ((mk & (1 << i)) != 0) { if (mod_index >= 0) return; mod_index = i; } bool release = false; if (mod_index == -1) release = true; else { auto cookie = xcb_get_modifier_mapping(QX11Info::connection()); - auto reply = xcb_get_modifier_mapping_reply(QX11Info::connection(), cookie, NULL); + auto reply = xcb_get_modifier_mapping_reply(QX11Info::connection(), cookie, nullptr); if (reply) { auto keycodes = xcb_get_modifier_mapping_keycodes(reply); for (int i = 0; i < reply->keycodes_per_modifier; i++) { if (keycodes[reply->keycodes_per_modifier * mod_index + i] == event->detail) { release = true; } } } free(reply); } if (!release) { return; } if (m_keyboardGrabbed) { accept(); } } void App::init() { // only init once if (m_init) { return; } if (!ibus_bus_is_connected (m_bus)) { return; } g_signal_connect (m_bus, "connected", G_CALLBACK (ibus_connected_cb), this); g_signal_connect (m_bus, "disconnected", G_CALLBACK (ibus_disconnected_cb), this); connect(m_watcher, &QDBusServiceWatcher::serviceUnregistered, this, &App::finalize); GDBusConnection* connection = ibus_bus_get_connection (m_bus); g_dbus_connection_signal_subscribe (connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameAcquired", "/org/freedesktop/DBus", IBUS_SERVICE_PANEL, G_DBUS_SIGNAL_FLAGS_NONE, - name_acquired_cb, this, NULL); + name_acquired_cb, this, nullptr); g_dbus_connection_signal_subscribe (connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameLost", "/org/freedesktop/DBus", IBUS_SERVICE_PANEL, G_DBUS_SIGNAL_FLAGS_NONE, - name_lost_cb, this, NULL); + name_lost_cb, this, nullptr); ibus_bus_request_name (m_bus, IBUS_SERVICE_PANEL, IBUS_BUS_NAME_FLAG_ALLOW_REPLACEMENT | IBUS_BUS_NAME_FLAG_REPLACE_EXISTING); m_init = true; } void App::nameAcquired() { if (m_impanel) { g_object_unref(m_impanel); } m_impanel = ibus_panel_impanel_new (ibus_bus_get_connection (m_bus)); ibus_panel_impanel_set_bus(m_impanel, m_bus); ibus_panel_impanel_set_app(m_impanel, this); } void App::nameLost() { setDoGrab(false); if (m_impanel) { g_object_unref(m_impanel); } - m_impanel = NULL; + m_impanel = nullptr; } QByteArray App::normalizeIconName(const QByteArray& icon) const { if (m_iconMap.contains(icon)) { return m_iconMap[icon]; } return icon; } void App::setTriggerKeys(QList< TriggerKey > triggersList) { if (m_doGrab) { ungrabKey(); } m_triggersList = triggersList; if (m_doGrab) { grabKey(); } } void App::setDoGrab(bool doGrab) { if (m_doGrab != doGrab) {; if (doGrab) { grabKey(); } else { ungrabKey(); } m_doGrab = doGrab; } } void App::grabKey() { Q_FOREACH(const TriggerKey& key, m_triggersList) { xcb_keysym_t sym = key.first; uint modifiers = key.second; xcb_keycode_t* keycode = xcb_key_symbols_get_keycode(m_syms, sym); if (!keycode) { g_warning ("Can not convert keyval=%u to keycode!", sym); } else { xcb_grab_key(QX11Info::connection(), true, QX11Info::appRootWindow(), modifiers, keycode[0], XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); if ((modifiers & XCB_MOD_MASK_SHIFT) == 0) { xcb_grab_key(QX11Info::connection(), true, QX11Info::appRootWindow(), modifiers | XCB_MOD_MASK_SHIFT, keycode[0], XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); } } free(keycode); } } void App::ungrabKey() { Q_FOREACH(const TriggerKey& key, m_triggersList) { xcb_keysym_t sym = key.first; uint modifiers = key.second; xcb_keycode_t* keycode = xcb_key_symbols_get_keycode(m_syms, sym); if (!keycode) { g_warning ("Can not convert keyval=%u to keycode!", sym); } else { xcb_ungrab_key(QX11Info::connection(), keycode[0], QX11Info::appRootWindow(), modifiers); if ((modifiers & XCB_MOD_MASK_SHIFT) == 0) { xcb_ungrab_key(QX11Info::connection(), keycode[0], QX11Info::appRootWindow(), modifiers | XCB_MOD_MASK_SHIFT); } } free(keycode); } } bool App::grabXKeyboard() { if (m_keyboardGrabbed) return false; auto w = QX11Info::appRootWindow(); auto cookie = xcb_grab_keyboard(QX11Info::connection(), false, w, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); - auto reply = xcb_grab_keyboard_reply(QX11Info::connection(), cookie, NULL); + auto reply = xcb_grab_keyboard_reply(QX11Info::connection(), cookie, nullptr); if (reply && reply->status == XCB_GRAB_STATUS_SUCCESS) { m_keyboardGrabbed = true; } free(reply); return m_keyboardGrabbed; } void App::ungrabXKeyboard() { if (!m_keyboardGrabbed) { // grabXKeyboard() may fail sometimes, so don't fail, but at least warn anyway qDebug() << "ungrabXKeyboard() called but keyboard not grabbed!"; } m_keyboardGrabbed = false; xcb_ungrab_keyboard(QX11Info::connection(), XCB_CURRENT_TIME); } void App::accept() { if (m_keyboardGrabbed) { ungrabXKeyboard(); } ibus_panel_impanel_accept(m_impanel); } void App::finalize() { clean(); App::exit(0); } void App::clean() { if (m_impanel) { g_object_unref(m_impanel); - m_impanel = 0; + m_impanel = nullptr; } if (m_bus) { g_signal_handlers_disconnect_by_func(m_bus, (gpointer) ibus_disconnected_cb, this); g_signal_handlers_disconnect_by_func(m_bus, (gpointer) ibus_connected_cb, this); g_object_unref(m_bus); - m_bus = 0; + m_bus = nullptr; } ungrabKey(); } App::~App() { clean(); if (m_syms) { xcb_key_symbols_free(m_syms); } } diff --git a/applets/kimpanel/backend/ibus/ibus15/enginemanager.cpp b/applets/kimpanel/backend/ibus/ibus15/enginemanager.cpp index 949dae845..de87b16d3 100644 --- a/applets/kimpanel/backend/ibus/ibus15/enginemanager.cpp +++ b/applets/kimpanel/backend/ibus/ibus15/enginemanager.cpp @@ -1,174 +1,174 @@ /* * Copyright (C) 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 "enginemanager.h" #include #define THRESHOLD 256 -EngineManager::EngineManager() : m_engines(0), m_length(0) +EngineManager::EngineManager() : m_engines(nullptr), m_length(0) { } EngineManager::~EngineManager() { freeOldEngine(); } void EngineManager::freeOldEngine() { if (m_engines) { for (size_t i = 0; i < m_length; i++) { g_object_unref(m_engines[i]); } g_free(m_engines); } } void EngineManager::setEngines(IBusEngineDesc** engines) { freeOldEngine(); m_engineMap.clear(); m_history.clear(); m_engines = engines; m_length = 0; if (engines) { while (engines[m_length]) { m_length++; } } } void EngineManager::setUseGlobalEngine(gboolean use) { m_useGlobalEngine = use; if (use) { m_engineMap.clear(); } } void EngineManager::setCurrentContext(const gchar* input_context_path) { m_currentContext = QString::fromLatin1(input_context_path); } QString EngineManager::currentEngine() { if (m_engineMap.contains(m_currentContext)) { return m_engineMap[m_currentContext]; } else if (m_length > 0) { return QString::fromUtf8(ibus_engine_desc_get_name(m_engines[0])); } else { return QString(); } } void EngineManager::setCurrentEngine(const char* name) { if (!m_useGlobalEngine && !m_currentContext.isEmpty()) { if (!m_engineMap.contains(m_currentContext)) { m_history.enqueue(m_currentContext); } m_engineMap[m_currentContext] = QString::fromUtf8(name); if (m_engineMap.size() > THRESHOLD) { m_engineMap.remove(m_history.dequeue()); Q_ASSERT(m_engineMap.size() == m_history.size()); } } } const char* EngineManager::navigate(IBusEngineDesc* engine, bool forward) { if (length() == 0) { return ""; } size_t i = 0; for ( ; i < m_length; i ++) { if (m_engines[i] == engine || 0 == g_strcmp0(ibus_engine_desc_get_name(engine), ibus_engine_desc_get_name(m_engines[i]))) { break; } } i = (i + (forward ? 1 : (length() - 1))) % length(); return ibus_engine_desc_get_name(m_engines[i]); } void EngineManager::moveToFirst(IBusEngineDesc* engine) { size_t i = 0; while (i < length()) { if (m_engines[i] == engine || 0 == g_strcmp0(ibus_engine_desc_get_name(engine), ibus_engine_desc_get_name(m_engines[i]))) { break; } i++; } if (i == 0) { return; } if (i >= m_length) { return; } engine = m_engines[i]; for (int j = i; j > 0; j--) { m_engines[j] = m_engines[j - 1]; } m_engines[0] = engine; } size_t EngineManager::getIndexByName(const char* name) { size_t i = 0; for ( ; i < m_length; i++) { if (0 == g_strcmp0(name, ibus_engine_desc_get_name(m_engines[i]))) { break; } } return i; } void EngineManager::setOrder(const gchar** engine_names, size_t len) { size_t k = 0; for (size_t i = 0; i < len; i ++) { size_t j = getIndexByName(engine_names[i]); if (j < length() && j >= k) { if (j != k) { IBusEngineDesc* temp = m_engines[k]; m_engines[k] = m_engines[j]; m_engines[j] = temp; } k ++; } } } QStringList EngineManager::engineOrder() { QStringList list; for (size_t i = 0; i < m_length; i++) { list << QString::fromUtf8(ibus_engine_desc_get_name(m_engines[i])); } return list; } diff --git a/applets/kimpanel/backend/ibus/ibus15/panel.cpp b/applets/kimpanel/backend/ibus/ibus15/panel.cpp index 5782d6788..798d1c11f 100644 --- a/applets/kimpanel/backend/ibus/ibus15/panel.cpp +++ b/applets/kimpanel/backend/ibus/ibus15/panel.cpp @@ -1,1558 +1,1558 @@ /* * Copyright (C) 2011-2012 Ni Hui * Copyright (C) 2013-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 #include #include #include #include #include #include #include #include #include "panel.h" #include "propertymanager.h" #include "enginemanager.h" #include "xkblayoutmanager.h" #include "app.h" #include "gtkaccelparse_p.h" #ifndef DBUS_ERROR_FAILED #define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed" #endif /* DBUS_ERROR_FAILED */ #define IBUS_SCHEMA_GENERAL "org.freedesktop.ibus.general" #define IBUS_SCHEMA_HOTKEY "org.freedesktop.ibus.general.hotkey" #define IBUS_SCHEMA_PANEL "org.freedesktop.ibus.panel" typedef struct _IBusPanelImpanelClass IBusPanelImpanelClass; struct _IBusPanelImpanel { IBusPanelService parent; IBusBus *bus; GDBusConnection *conn; PropertyManager* propManager; EngineManager* engineManager; XkbLayoutManager* xkbLayoutManager; App* app; gboolean useSystemKeyboardLayout; int selected; GSettings *settings_general; GSettings *settings_hotkey; }; struct _IBusPanelImpanelClass { IBusPanelServiceClass parent; }; /* functions prototype */ static void ibus_panel_impanel_class_init (IBusPanelImpanelClass *klass); static void ibus_panel_impanel_init (IBusPanelImpanel *impanel); static void ibus_panel_impanel_destroy (IBusPanelImpanel *impanel); static void ibus_panel_impanel_focus_in (IBusPanelService *panel, const gchar *input_context_path); static void ibus_panel_impanel_focus_out (IBusPanelService *panel, const gchar *input_context_path); static void ibus_panel_impanel_register_properties (IBusPanelService *panel, IBusPropList *prop_list); static void ibus_panel_impanel_real_register_properties (IBusPanelImpanel *impanel); static void ibus_panel_impanel_set_cursor_location (IBusPanelService *panel, gint x, gint y, gint w, gint h); static void ibus_panel_impanel_update_auxiliary_text (IBusPanelService *panel, IBusText *text, gboolean visible); static void ibus_panel_impanel_update_lookup_table (IBusPanelService *panel, IBusLookupTable *lookup_table, gboolean visible); static void ibus_panel_impanel_update_preedit_text (IBusPanelService *panel, IBusText *text, guint cursor_pos, gboolean visible); static void ibus_panel_impanel_update_property (IBusPanelService *panel, IBusProperty *prop); static void ibus_panel_impanel_cursor_down_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_cursor_up_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_hide_auxiliary_text (IBusPanelService *panel); static void ibus_panel_impanel_hide_language_bar (IBusPanelService *panel); static void ibus_panel_impanel_hide_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_hide_preedit_text (IBusPanelService *panel); static void ibus_panel_impanel_page_down_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_page_up_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_reset (IBusPanelService *panel); static void ibus_panel_impanel_show_auxiliary_text (IBusPanelService *panel); static void ibus_panel_impanel_show_language_bar (IBusPanelService *panel); static void ibus_panel_impanel_show_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_show_preedit_text (IBusPanelService *panel); static void ibus_panel_impanel_start_setup (IBusPanelService *panel); static void ibus_panel_impanel_state_changed (IBusPanelService *panel); /* impanel signal handler function */ static void ibus_panel_impanel_exec_im_menu (IBusPanelImpanel* impanel); static void ibus_panel_impanel_exec_menu (IBusPanelImpanel* impanel, IBusPropList* prop_list); static void impanel_set_engine(IBusPanelImpanel* impanel, const char* name); static QByteArray ibus_property_to_propstr (IBusProperty *property, gboolean useSymbol = FALSE); static QByteArray ibus_engine_desc_to_logo_propstr(IBusEngineDesc* engine); void impanel_update_logo_by_engine(IBusPanelImpanel* impanel, IBusEngineDesc* engine_desc) { if (!impanel->conn) { return; } QByteArray propstr = ibus_engine_desc_to_logo_propstr(engine_desc); g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty", (g_variant_new ("(s)", propstr.constData())), - NULL); + nullptr); } void ibus_panel_impanel_set_bus (IBusPanelImpanel *impanel, IBusBus *bus) { impanel->bus = bus; } void ibus_panel_impanel_set_app(IBusPanelImpanel* impanel, App* app) { impanel->app = app; } void ibus_panel_impanel_accept(IBusPanelImpanel* impanel) { if (impanel->selected >= 0 && static_cast(impanel->selected) < impanel->engineManager->length()) { impanel_set_engine(impanel, ibus_engine_desc_get_name(impanel->engineManager->engines()[impanel->selected])); impanel->selected = -1; } } void ibus_panel_impanel_navigate(IBusPanelImpanel* impanel, gboolean start, gboolean forward) { if (start) { impanel->selected = -1; } if (impanel->engineManager->length() < 2) { return; } - IBusEngineDesc* engine_desc = NULL; + IBusEngineDesc* engine_desc = nullptr; if (impanel->selected < 0) { engine_desc = ibus_bus_get_global_engine(impanel->bus); } else if (static_cast(impanel->selected) < impanel->engineManager->length()) { engine_desc = impanel->engineManager->engines()[impanel->selected]; g_object_ref(engine_desc); } if (!engine_desc) { engine_desc = impanel->engineManager->engines()[0]; g_object_ref(engine_desc); } if (engine_desc) { const char* name = impanel->engineManager->navigate(engine_desc, forward); impanel->selected = impanel->engineManager->getIndexByName(name); g_object_unref(engine_desc); } else { return; } if (impanel->selected >= 0 && static_cast(impanel->selected) < impanel->engineManager->length()) { ibus_panel_impanel_real_register_properties(impanel); } } void ibus_panel_impanel_move_next(IBusPanelImpanel* impanel) { if (impanel->engineManager->length() >= 2) { impanel_set_engine(impanel, ibus_engine_desc_get_name(impanel->engineManager->engines()[1])); } } -static GDBusNodeInfo *introspection_data = NULL; +static GDBusNodeInfo *introspection_data = nullptr; static guint owner_id; static const gchar introspection_xml[] = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static const char prop_sep[] = ":"; static QByteArray ibus_property_args_to_propstr (const char *key, const char *label, const char *icon, const char *tooltip, const char *hint = "") { QByteArray propstr("/IBus/"); QByteArray str(key); str.replace(':', '!'); App* app = static_cast(qApp); propstr += str; propstr += prop_sep; propstr += QByteArray(label).replace(':', '-').constData(); propstr += prop_sep; propstr += app->normalizeIconName(QByteArray(icon).replace(':', '-')); propstr += prop_sep; propstr += QByteArray(tooltip).replace(':', '-').constData(); propstr += prop_sep; propstr += QByteArray(hint).replace(':', '-').constData(); return propstr; } static QByteArray ibus_engine_desc_to_logo_propstr(IBusEngineDesc* engine) { const gchar* label = "IBus"; const gchar* tooltip = ""; const gchar* icon = "input-keyboard"; gchar xkbLabel[3]; if (engine) { const gchar* iconname = ibus_engine_desc_get_icon(engine); if (iconname && iconname[0]) { icon = iconname; } if (strncmp("xkb:", ibus_engine_desc_get_name(engine), 4) == 0) { strncpy(xkbLabel, ibus_engine_desc_get_name(engine) + 4, 2); xkbLabel[2] = 0; int i = 0; while (xkbLabel[i]) { if (xkbLabel[i] == ':') { xkbLabel[i] = 0; } i++; } label = xkbLabel; icon = ""; } const gchar* longname = ibus_engine_desc_get_longname(engine); if (longname && longname[0]) { tooltip = longname; } } return ibus_property_args_to_propstr("Logo", label, icon, tooltip); } static QByteArray ibus_property_to_propstr (IBusProperty *property, gboolean useSymbol) { - const gchar* label = NULL; + const gchar* label = nullptr; const gchar* tooltip = ibus_text_get_text (ibus_property_get_tooltip (property)); const gchar* icon = ibus_property_get_icon (property); if (useSymbol) { label = ibus_text_get_text(ibus_property_get_symbol (property)); if (!label || label[0] == '\0') { label = ibus_text_get_text(ibus_property_get_label(property)); } } else { label = ibus_text_get_text(ibus_property_get_label(property)); } const char* hint = ""; if (ibus_property_get_prop_type(property) == PROP_TYPE_TOGGLE) { if (ibus_property_get_state(property) != PROP_STATE_CHECKED) { hint = "disable"; } } else if (ibus_property_get_prop_type(property) == PROP_TYPE_RADIO) { if (ibus_property_get_state(property) == PROP_STATE_CHECKED) { hint = "checked"; } } return ibus_property_args_to_propstr(ibus_property_get_key (property), label, icon, tooltip, hint); } static QByteArray ibus_engine_desc_args_to_propstr (const char *name, const char *language, const char *longname, const char *icon, const char *description) { QByteArray propstr("/IBus/Engine/"); QByteArray data(name); data.replace(':', '!'); propstr += data; propstr += prop_sep; if (language) { propstr += language; propstr += " - "; } propstr += longname; propstr += prop_sep; propstr += icon; propstr += prop_sep; propstr += description; return propstr; } static QByteArray ibus_engine_desc_to_propstr (IBusEngineDesc *engine_desc) { return ibus_engine_desc_args_to_propstr(ibus_engine_desc_get_name(engine_desc), ibus_engine_desc_get_language(engine_desc), ibus_engine_desc_get_longname(engine_desc), ibus_engine_desc_get_icon(engine_desc), ibus_engine_desc_get_description(engine_desc)); } static void impanel_get_default_engine(IBusPanelImpanel* impanel, char*** pengine_names, gsize* plen) { GList* engines = ibus_bus_list_engines(impanel->bus); if (!engines) { *pengine_names = g_new0 (gchar*, 2); *plen = 1; (*pengine_names)[0] = g_strdup ("xkb:us::eng"); return; } QList engineList; impanel->xkbLayoutManager->getLayout(); QStringList layouts = impanel->xkbLayoutManager->defaultLayout().split(','); QStringList variants = impanel->xkbLayoutManager->defaultVariant().split(','); for (int i = 0; i < layouts.size(); i ++ ) { QString variant; if (i < variants.size()) { variant = variants[i]; } - for (GList* engine = g_list_first(engines); engine != NULL ; + for (GList* engine = g_list_first(engines); engine != nullptr ; engine = g_list_next(engine)) { IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data); QByteArray name = ibus_engine_desc_get_name(desc); if (!name.startsWith("xkb:")) { continue; } if (QLatin1String(ibus_engine_desc_get_layout(desc)) == layouts[i] && QLatin1String(ibus_engine_desc_get_layout_variant(desc)) == variant) { engineList << name; } } } - const char* locale = setlocale(LC_CTYPE, NULL); + const char* locale = setlocale(LC_CTYPE, nullptr); if (!locale) { locale = "C"; } QStringList localeList = QString(locale).split('.'); QString lang = localeList.size() > 0 ? localeList[0] : ""; bool added = false; - for (GList* engine = g_list_first(engines); engine != NULL ; + for (GList* engine = g_list_first(engines); engine != nullptr ; engine = g_list_next(engine)) { IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data); QByteArray name = ibus_engine_desc_get_name(desc); if (name.startsWith("xkb:")) { continue; } if (QLatin1String(ibus_engine_desc_get_language(desc)) == lang && ibus_engine_desc_get_rank(desc) > 0) { engineList << name; added = true; } } if (!added) { localeList = QString(lang).split('_'); QString lang = localeList.size() > 0 ? localeList[0] : ""; - for (GList* engine = g_list_first(engines); engine != NULL ; + for (GList* engine = g_list_first(engines); engine != nullptr ; engine = g_list_next(engine)) { IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data); QByteArray name = ibus_engine_desc_get_name(desc); if (name.startsWith("xkb:")) { continue; } if (QLatin1String(ibus_engine_desc_get_language(desc)) == lang && ibus_engine_desc_get_rank(desc) > 0) { engineList << name; } } } - for (GList* engine = g_list_first(engines); engine != NULL ; + for (GList* engine = g_list_first(engines); engine != nullptr ; engine = g_list_next(engine)) { IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data); g_object_unref(desc); } g_list_free(engines); if (engineList.size() == 0) { *pengine_names = g_new0 (gchar*, 2); *plen = 1; (*pengine_names)[0] = g_strdup ("xkb:us::eng"); return; } else { *pengine_names = g_new0 (gchar*, engineList.size() + 1); *plen = engineList.size(); size_t i = 0; Q_FOREACH(const QByteArray& name, engineList) { (*pengine_names)[i] = g_strdup (name.constData()); i ++; } } } static void impanel_update_engines(IBusPanelImpanel* impanel, GVariant* var_engines) { - gchar** engine_names = NULL; + gchar** engine_names = nullptr; size_t len = 0; if (var_engines) { engine_names = g_variant_dup_strv(var_engines, &len); } if (len == 0) { g_strfreev(engine_names); - engine_names = NULL; + engine_names = nullptr; } if (!engine_names) { impanel_get_default_engine(impanel, &engine_names, &len); GVariant* var = g_variant_new_strv(engine_names, len); g_settings_set_value(impanel->settings_general, "preload-engines", var); } IBusEngineDesc** engines = ibus_bus_get_engines_by_names(impanel->bus, engine_names); g_strfreev(engine_names); impanel->engineManager->setEngines(engines); if (engines && engines[0]) { ibus_bus_set_global_engine(impanel->bus, ibus_engine_desc_get_name(engines[0])); } impanel->app->setDoGrab(len > 1); } static void impanel_update_engines_order(IBusPanelImpanel* impanel, GVariant* var_engines) { - const gchar** engine_names = NULL; + const gchar** engine_names = nullptr; size_t len = 0; engine_names = g_variant_get_strv(var_engines, &len); if (len) { impanel->engineManager->setOrder(engine_names, len); if (impanel->engineManager->engines()) { ibus_bus_set_global_engine(impanel->bus, ibus_engine_desc_get_name(impanel->engineManager->engines()[0])); } } g_free(engine_names); } static void impanel_update_triggers(IBusPanelImpanel* impanel, GVariant* variant) { - gchar** triggers = NULL; + gchar** triggers = nullptr; size_t len = 0; if (variant) { triggers = g_variant_dup_strv(variant, &len); } if (len == 0) { g_strfreev(triggers); - triggers = 0; + triggers = nullptr; } if (!triggers) { triggers = g_new0 (gchar*, 2); len = 1; triggers[0] = g_strdup ("space"); } QList > triggersList; for (size_t i = 0; i < len; i ++) { guint key = 0; GdkModifierType mod = (GdkModifierType) 0; _gtk_accelerator_parse(triggers[i], &key, &mod); if (key) { triggersList << qMakePair(key, (uint) mod); } } impanel->app->setTriggerKeys(triggersList); } static void impanel_update_use_system_keyboard_layout(IBusPanelImpanel* impanel, GVariant* variant) { impanel->useSystemKeyboardLayout = g_variant_get_boolean(variant); } static void impanel_update_use_global_engine(IBusPanelImpanel* impanel, GVariant* variant) { impanel->engineManager->setUseGlobalEngine(g_variant_get_boolean(variant)); } static void impanel_update_latin_layouts(IBusPanelImpanel* impanel, GVariant* variant) { if (!variant) { return; } gsize length; const gchar** variants = g_variant_get_strv(variant, &length); impanel->xkbLayoutManager->setLatinLayouts(variants, length); g_free(variants); } static void impanel_settings_changed_callback (GSettings* settings, const gchar* key, gpointer user_data) { IBusPanelImpanel* impanel = ((IBusPanelImpanel *)user_data); - gchar *schema = NULL; + gchar *schema = nullptr; GVariant *value = g_settings_get_value (settings, key); g_object_get(G_OBJECT(settings), "schema", &schema, NULL); if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "preload-engines") == 0) { impanel_update_engines(impanel, value); } else if (g_strcmp0(schema, IBUS_SCHEMA_HOTKEY) == 0 && g_strcmp0(key, "triggers") == 0) { impanel_update_triggers(impanel, value); } else if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "use-system-keyboard-layout") == 0) { impanel_update_use_system_keyboard_layout(impanel, value); } else if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "use-global-engine") == 0) { impanel_update_use_global_engine(impanel, value); } g_free (schema); } static void impanel_exit_callback (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); IBusPanelImpanel* impanel = ((IBusPanelImpanel *)user_data); if (impanel->bus) { ibus_bus_exit(impanel->bus, FALSE); } } static void impanel_panel_created_callback (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); IBusPanelImpanel* impanel = ((IBusPanelImpanel *)user_data); ibus_panel_impanel_real_register_properties(impanel); } static void impanel_set_engine(IBusPanelImpanel* impanel, const char* name) { if (!name || !name[0]) { return; } if (ibus_bus_set_global_engine(impanel->bus, name)) { if (!impanel->useSystemKeyboardLayout) { IBusEngineDesc* engine_desc = ibus_bus_get_global_engine(impanel->bus); if (engine_desc) { impanel->xkbLayoutManager->setLayout(engine_desc); } g_object_unref(engine_desc); } impanel->engineManager->setCurrentEngine(name); } else { qDebug() << "set engine failed."; } } static void impanel_trigger_property_callback (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(user_data); - gchar *s0 = NULL; + gchar *s0 = nullptr; g_variant_get (parameters, "(s)", &s0); if (!s0 || strlen(s0) <= 6) return; QByteArray prop_key(s0 + 6);// +6 to skip "/IBus/" prop_key.replace('!', ':'); if (g_ascii_strncasecmp (prop_key.constData(), "Logo", 4) == 0) ibus_panel_impanel_exec_im_menu(impanel); else if (g_ascii_strncasecmp (prop_key.constData(), "Engine/", 7) == 0) { impanel_set_engine(impanel, prop_key.constData() + 7); } else { IBusProperty* property = impanel->propManager->property(prop_key.constData()); if (property) { IBusPropState newstate = ibus_property_get_state(property); switch (ibus_property_get_prop_type(property)) { case PROP_TYPE_RADIO: case PROP_TYPE_TOGGLE: if (ibus_property_get_prop_type(property) == PROP_TYPE_TOGGLE) { if (newstate == PROP_STATE_CHECKED) newstate = PROP_STATE_UNCHECKED; else if (newstate == PROP_STATE_UNCHECKED) newstate = PROP_STATE_CHECKED; } else if (ibus_property_get_prop_type(property) == PROP_TYPE_RADIO) { newstate = PROP_STATE_CHECKED; } case PROP_TYPE_NORMAL: ibus_property_set_state(property, newstate); ibus_panel_service_property_activate((IBusPanelService *)impanel, prop_key.constData(), newstate); break; case PROP_TYPE_MENU: ibus_panel_impanel_exec_menu(impanel, ibus_property_get_sub_props(property)); case PROP_TYPE_SEPARATOR: break; default: break; } } else { ibus_panel_service_property_activate((IBusPanelService *)impanel, prop_key.constData(), PROP_STATE_CHECKED); } } g_free(s0); } static void impanel_select_candidate_callback (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); gint i; g_variant_get (parameters, "(i)", &i); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(user_data); ibus_panel_service_candidate_clicked((IBusPanelService *)impanel, i, 0, 0); } static void impanel_prev_page_callback (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(user_data); ibus_panel_service_page_up((IBusPanelService *)impanel); } static void impanel_next_page_callback (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(user_data); ibus_panel_service_page_down((IBusPanelService *)impanel); } static void impanel_configure_callback (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); Q_UNUSED(user_data); pid_t pid = fork(); if (pid == 0) { - execlp ("ibus-setup", "ibus-setup", (char *)0); + execlp ("ibus-setup", "ibus-setup", (char *)nullptr); exit (0); } } static void on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { Q_UNUSED(name); IBusPanelImpanel* impanel = ((IBusPanelImpanel *)user_data); impanel->conn = connection; g_dbus_connection_register_object (connection, "/kimpanel", introspection_data->interfaces[0], - NULL, /*&interface_vtable*/ - NULL, /* user_data */ - NULL, /* user_data_free_func */ - NULL); /* GError** */ + nullptr, /*&interface_vtable*/ + nullptr, /* user_data */ + nullptr, /* user_data_free_func */ + nullptr); /* GError** */ g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "TriggerProperty", "/org/kde/impanel", - NULL, + nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_trigger_property_callback, user_data, - NULL); + nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "SelectCandidate", "/org/kde/impanel", - NULL, + nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_select_candidate_callback, user_data, - NULL); + nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "LookupTablePageUp", "/org/kde/impanel", - NULL, + nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_prev_page_callback, user_data, - NULL); + nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "LookupTablePageDown", "/org/kde/impanel", - NULL, + nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_next_page_callback, user_data, - NULL); + nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "PanelCreated", "/org/kde/impanel", - NULL, + nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_panel_created_callback, user_data, - NULL); + nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "Exit", "/org/kde/impanel", - NULL, + nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_exit_callback, user_data, - NULL); + nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "Configure", "/org/kde/impanel", - NULL, + nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_configure_callback, user_data, - NULL); + nullptr); GVariant* var_engines = g_settings_get_value(impanel->settings_general, "preload-engines"); impanel_update_engines(impanel, var_engines); if (var_engines) { g_variant_unref(var_engines); } var_engines = g_settings_get_value(impanel->settings_general, "engines-order"); if (var_engines) { impanel_update_engines_order(impanel, var_engines); g_variant_unref(var_engines); } GVariant* var_triggers = g_settings_get_value(impanel->settings_hotkey, "triggers"); impanel_update_triggers(impanel, var_triggers); if (var_triggers) { g_variant_unref(var_triggers); } GVariant* var_layouts = g_settings_get_value(impanel->settings_general, "xkb-latin-layouts"); if (var_layouts) { impanel_update_latin_layouts(impanel, var_layouts); g_variant_unref(var_layouts); } GVariant* var = g_settings_get_value(impanel->settings_general, "use-system-keyboard-layout"); if (var) { impanel_update_use_system_keyboard_layout(impanel, var); g_variant_unref(var); } var = g_settings_get_value(impanel->settings_general, "use-global-engine"); if (var) { impanel_update_use_global_engine(impanel, var); g_variant_unref(var); } ibus_panel_impanel_real_register_properties(impanel); } static void on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(name); Q_UNUSED(user_data); } static void on_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(name); Q_UNUSED(user_data); exit (1); } G_DEFINE_TYPE (IBusPanelImpanel, ibus_panel_impanel, IBUS_TYPE_PANEL_SERVICE) static void ibus_panel_impanel_class_init (IBusPanelImpanelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); IBUS_OBJECT_CLASS (object_class)->destroy = (IBusObjectDestroyFunc) ibus_panel_impanel_destroy; IBUS_PANEL_SERVICE_CLASS (object_class)->focus_in = ibus_panel_impanel_focus_in; IBUS_PANEL_SERVICE_CLASS (object_class)->focus_out = ibus_panel_impanel_focus_out; IBUS_PANEL_SERVICE_CLASS (object_class)->register_properties = ibus_panel_impanel_register_properties; IBUS_PANEL_SERVICE_CLASS (object_class)->set_cursor_location = ibus_panel_impanel_set_cursor_location; IBUS_PANEL_SERVICE_CLASS (object_class)->update_auxiliary_text = ibus_panel_impanel_update_auxiliary_text; IBUS_PANEL_SERVICE_CLASS (object_class)->update_lookup_table = ibus_panel_impanel_update_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->update_preedit_text = ibus_panel_impanel_update_preedit_text; IBUS_PANEL_SERVICE_CLASS (object_class)->update_property = ibus_panel_impanel_update_property; IBUS_PANEL_SERVICE_CLASS (object_class)->cursor_down_lookup_table = ibus_panel_impanel_cursor_down_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->cursor_up_lookup_table = ibus_panel_impanel_cursor_up_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->hide_auxiliary_text = ibus_panel_impanel_hide_auxiliary_text; IBUS_PANEL_SERVICE_CLASS (object_class)->hide_language_bar = ibus_panel_impanel_hide_language_bar; IBUS_PANEL_SERVICE_CLASS (object_class)->hide_lookup_table = ibus_panel_impanel_hide_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->hide_preedit_text = ibus_panel_impanel_hide_preedit_text; IBUS_PANEL_SERVICE_CLASS (object_class)->page_down_lookup_table = ibus_panel_impanel_page_down_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->page_up_lookup_table = ibus_panel_impanel_page_up_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->reset = ibus_panel_impanel_reset; IBUS_PANEL_SERVICE_CLASS (object_class)->show_auxiliary_text = ibus_panel_impanel_show_auxiliary_text; IBUS_PANEL_SERVICE_CLASS (object_class)->show_language_bar = ibus_panel_impanel_show_language_bar; IBUS_PANEL_SERVICE_CLASS (object_class)->show_lookup_table = ibus_panel_impanel_show_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->show_preedit_text = ibus_panel_impanel_show_preedit_text; IBUS_PANEL_SERVICE_CLASS (object_class)->start_setup = ibus_panel_impanel_start_setup; IBUS_PANEL_SERVICE_CLASS (object_class)->state_changed = ibus_panel_impanel_state_changed; } static void ibus_panel_impanel_init (IBusPanelImpanel *impanel) { - impanel->bus = NULL; - impanel->app = NULL; + impanel->bus = nullptr; + impanel->app = nullptr; impanel->useSystemKeyboardLayout = false; impanel->selected = -1; - introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); + introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, nullptr); owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, "org.kde.kimpanel.inputmethod", G_BUS_NAME_OWNER_FLAGS_REPLACE, on_bus_acquired, on_name_acquired, on_name_lost, - impanel, NULL); + impanel, nullptr); impanel->propManager = new PropertyManager; impanel->engineManager = new EngineManager; impanel->xkbLayoutManager = new XkbLayoutManager; impanel->settings_general = g_settings_new (IBUS_SCHEMA_GENERAL); impanel->settings_hotkey = g_settings_new (IBUS_SCHEMA_HOTKEY); g_signal_connect(impanel->settings_general, "changed", G_CALLBACK (impanel_settings_changed_callback), impanel); g_signal_connect(impanel->settings_hotkey, "changed", G_CALLBACK (impanel_settings_changed_callback), impanel); } static void ibus_panel_impanel_destroy (IBusPanelImpanel *impanel) { delete impanel->propManager; - impanel->propManager = NULL; + impanel->propManager = nullptr; delete impanel->engineManager; - impanel->engineManager = NULL; + impanel->engineManager = nullptr; delete impanel->xkbLayoutManager; - impanel->xkbLayoutManager = NULL; + impanel->xkbLayoutManager = nullptr; g_signal_handlers_disconnect_by_func (impanel->settings_general, (gpointer)impanel_settings_changed_callback, impanel); g_signal_handlers_disconnect_by_func (impanel->settings_hotkey, (gpointer)impanel_settings_changed_callback, impanel); g_clear_object (&impanel->settings_general); g_clear_object (&impanel->settings_hotkey); g_bus_unown_name (owner_id); g_dbus_node_info_unref (introspection_data); IBUS_OBJECT_CLASS (ibus_panel_impanel_parent_class)->destroy ((IBusObject *)impanel); } static void ibus_panel_impanel_focus_in (IBusPanelService *panel, const gchar *input_context_path) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL (panel); if (impanel->app->keyboardGrabbed()) { return; } IBusEngineDesc *engine_desc = ibus_bus_get_global_engine(impanel->bus); impanel_update_logo_by_engine(impanel, engine_desc); g_object_unref(engine_desc); impanel->engineManager->setCurrentContext(input_context_path); if (!impanel->engineManager->useGlobalEngine()) { impanel_set_engine(impanel, impanel->engineManager->currentEngine().toUtf8().constData()); } } static void ibus_panel_impanel_focus_out (IBusPanelService *panel, const gchar *input_context_path) { Q_UNUSED(panel); Q_UNUSED(input_context_path); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL (panel); if (impanel->app->keyboardGrabbed()) { return; } if (impanel->engineManager->useGlobalEngine()) { return; } impanel->engineManager->setCurrentContext(""); } static void ibus_panel_impanel_register_properties (IBusPanelService *panel, IBusPropList *prop_list) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL (panel); impanel->propManager->setProperties(prop_list); ibus_panel_impanel_real_register_properties(impanel); } static void ibus_panel_impanel_real_register_properties(IBusPanelImpanel* impanel) { if (!impanel->conn) return; - IBusProperty* property = NULL; + IBusProperty* property = nullptr; guint i = 0; GVariantBuilder builder; g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); if (impanel->selected >= 0 && static_cast(impanel->selected) < impanel->engineManager->length()) { auto engine_desc = impanel->engineManager->engines()[impanel->selected]; QByteArray propstr = ibus_engine_desc_to_logo_propstr(engine_desc); g_variant_builder_add (&builder, "s", propstr.constData()); } else { auto engine_desc = ibus_bus_get_global_engine(impanel->bus); QByteArray propstr = ibus_engine_desc_to_logo_propstr(engine_desc); g_variant_builder_add (&builder, "s", propstr.constData()); IBusPropList* prop_list = impanel->propManager->properties(); if (prop_list) { - while ( ( property = ibus_prop_list_get( prop_list, i ) ) != NULL ) { + while ( ( property = ibus_prop_list_get( prop_list, i ) ) != nullptr ) { propstr = ibus_property_to_propstr(property, TRUE); g_variant_builder_add (&builder, "s", propstr.constData()); ++i; } } g_object_unref(engine_desc); } g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "RegisterProperties", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "RegisterProperties", (g_variant_new ("(as)", &builder)), - NULL); + nullptr); } static void ibus_panel_impanel_set_cursor_location (IBusPanelService *panel, gint x, gint y, gint w, gint h) { g_dbus_connection_call(IBUS_PANEL_IMPANEL (panel)->conn, "org.kde.impanel", "/org/kde/impanel", "org.kde.impanel2", "SetSpotRect", (g_variant_new("(iiii)", x, y, w, h)), - NULL, + nullptr, G_DBUS_CALL_FLAGS_NONE, -1, /* timeout */ - NULL, - NULL, - NULL); + nullptr, + nullptr, + nullptr); } static void ibus_panel_impanel_update_auxiliary_text (IBusPanelService *panel, IBusText *text, gboolean visible) { const gchar* t = ibus_text_get_text (text); const gchar *attr = ""; IBusPanelImpanel* impanel = (IBusPanelImpanel*) panel; if (!impanel->conn) return; g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateAux", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateAux", (g_variant_new ("(ss)", t, attr)), - NULL); + nullptr); if (visible == 0) ibus_panel_impanel_hide_auxiliary_text(panel); else ibus_panel_impanel_show_auxiliary_text(panel); } static void ibus_panel_impanel_update_lookup_table (IBusPanelService *panel, IBusLookupTable *lookup_table, gboolean visible) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; guint page_size = ibus_lookup_table_get_page_size(lookup_table); guint cursor_pos = ibus_lookup_table_get_cursor_pos(lookup_table); guint page = cursor_pos / page_size; guint start = page * page_size; guint end = start + page_size; guint num = ibus_lookup_table_get_number_of_candidates(lookup_table); if (end > num) { end = num; } // fprintf(stderr, "%d ~ %d pgsize %d num %d\n", start, end, page_size, num); guint i; gchar label[16][4];// WARNING large enough I think --- nihui const gchar *candidate; GVariantBuilder builder_labels; GVariantBuilder builder_candidates; GVariantBuilder builder_attrs; g_variant_builder_init (&builder_labels, G_VARIANT_TYPE ("as")); g_variant_builder_init (&builder_candidates, G_VARIANT_TYPE ("as")); g_variant_builder_init (&builder_attrs, G_VARIANT_TYPE ("as")); const gchar *attr = ""; for (i = start; i < end; i++) { g_snprintf (label[i-start], 4, "%d", (i-start+1) % 10); // NOTE ibus always return NULL for ibus_lookup_table_get_label // label = ibus_lookup_table_get_label(lookup_table, i)->text; g_variant_builder_add (&builder_labels, "s", label[i-start]); candidate = ibus_text_get_text (ibus_lookup_table_get_candidate (lookup_table, i)); g_variant_builder_add (&builder_candidates, "s", candidate); g_variant_builder_add (&builder_attrs, "s", attr); } gboolean has_prev = 1; gboolean has_next = 1; guint cursor_pos_in_page; if (ibus_lookup_table_is_cursor_visible(lookup_table)) cursor_pos_in_page = cursor_pos % page_size; else cursor_pos_in_page = -1; gint orientation = ibus_lookup_table_get_orientation(lookup_table); if (orientation == IBUS_ORIENTATION_HORIZONTAL) { orientation = 2; } else if (orientation == IBUS_ORIENTATION_VERTICAL) { orientation = 1; } else { orientation = 0; } g_dbus_connection_call(impanel->conn, "org.kde.impanel", "/org/kde/impanel", "org.kde.impanel2", "SetLookupTable", (g_variant_new ("(asasasbbii)", &builder_labels, &builder_candidates, &builder_attrs, has_prev, has_next, cursor_pos_in_page, orientation)), - NULL, + nullptr, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - NULL, - NULL); + nullptr, + nullptr, + nullptr); if (visible == 0) ibus_panel_impanel_hide_lookup_table(panel); else ibus_panel_impanel_show_lookup_table(panel); } static void ibus_panel_impanel_update_preedit_text (IBusPanelService *panel, IBusText *text, guint cursor_pos, gboolean visible) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; const gchar* t = ibus_text_get_text (text); const gchar *attr = ""; g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditText", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditText", (g_variant_new ("(ss)", t, attr)), - NULL); + nullptr); g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditCaret", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditCaret", (g_variant_new ("(i)", cursor_pos)), - NULL); + nullptr); if (visible == 0) ibus_panel_impanel_hide_preedit_text(panel); else ibus_panel_impanel_show_preedit_text(panel); } static void ibus_panel_impanel_update_property (IBusPanelService *panel, IBusProperty *prop) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; impanel->propManager->updateProperty(prop); QByteArray propstr = ibus_property_to_propstr(prop, TRUE); g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty", (g_variant_new ("(s)", propstr.constData())), - NULL); + nullptr); } static void ibus_panel_impanel_cursor_down_lookup_table (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_cursor_up_lookup_table (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_hide_auxiliary_text (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 0; g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new ("(b)", toShow)), - NULL); + nullptr); } static void ibus_panel_impanel_hide_language_bar (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_hide_lookup_table (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 0; g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable", (g_variant_new ("(b)", toShow)), - NULL); + nullptr); } static void ibus_panel_impanel_hide_preedit_text (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 0; g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new ("(b)", toShow)), - NULL); + nullptr); } static void ibus_panel_impanel_page_down_lookup_table (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_page_up_lookup_table (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_reset (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_show_auxiliary_text (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 1; g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new ("(b)", toShow)), - NULL); + nullptr); } static void ibus_panel_impanel_show_language_bar (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_show_lookup_table (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 1; g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable", (g_variant_new ("(b)", toShow)), - NULL); + nullptr); } static void ibus_panel_impanel_show_preedit_text (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 1; g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new ("(b)", toShow)), - NULL); + nullptr); } static void ibus_panel_impanel_start_setup (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_state_changed (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; if (impanel->app->keyboardGrabbed()) { return; } IBusEngineDesc *engine_desc = ibus_bus_get_global_engine(impanel->bus); if (!engine_desc) { return; } impanel_update_logo_by_engine(impanel, engine_desc); g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "Enable", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "Enable", (g_variant_new ("(b)", TRUE)), - NULL); + nullptr); impanel->engineManager->moveToFirst(engine_desc); QStringList engineList = impanel->engineManager->engineOrder(); gchar** engine_names = g_new0 (gchar*, engineList.size() + 1); size_t i = 0; Q_FOREACH(const QString& name, engineList) { engine_names[i] = g_strdup (name.toUtf8().constData()); i ++; } GVariant* var = g_variant_new_strv(engine_names, engineList.size()); g_settings_set_value(impanel->settings_general, "engines-order", var); g_strfreev(engine_names); g_object_unref(engine_desc); } static void ibus_panel_impanel_exec_menu(IBusPanelImpanel* impanel, IBusPropList* prop_list) { if (!impanel->conn) return; GVariantBuilder builder; g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); int i = 0; while (true) { IBusProperty* prop = ibus_prop_list_get(prop_list, i); if (!prop) break; QByteArray propstr = ibus_property_to_propstr(prop); g_variant_builder_add (&builder, "s", propstr.constData()); i ++; } g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new ("(as)", &builder)), - NULL); + nullptr); } static void ibus_panel_impanel_exec_im_menu (IBusPanelImpanel* impanel) { if (!impanel->conn) return; GVariantBuilder builder; g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); IBusEngineDesc** engines = impanel->engineManager->engines(); if (engines) { int i = 0; while (engines[i]) { QByteArray propstr = ibus_engine_desc_to_propstr(engines[i]); g_variant_builder_add (&builder, "s", propstr.constData()); i ++; } } g_dbus_connection_emit_signal (impanel->conn, - NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", + nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new ("(as)", &builder)), - NULL); + nullptr); } IBusPanelImpanel * ibus_panel_impanel_new (GDBusConnection *connection) { IBusPanelImpanel *panel; panel = (IBusPanelImpanel *) g_object_new (IBUS_TYPE_PANEL_IMPANEL, "object-path", IBUS_PATH_PANEL, "connection", connection, NULL); return panel; } diff --git a/applets/kimpanel/backend/ibus/ibus15/propertymanager.cpp b/applets/kimpanel/backend/ibus/ibus15/propertymanager.cpp index bd144c9e6..5825b65ef 100644 --- a/applets/kimpanel/backend/ibus/ibus15/propertymanager.cpp +++ b/applets/kimpanel/backend/ibus/ibus15/propertymanager.cpp @@ -1,77 +1,77 @@ /* * Copyright (C) 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 "propertymanager.h" #include -PropertyManager::PropertyManager() : m_props(0) +PropertyManager::PropertyManager() : m_props(nullptr) { } PropertyManager::~PropertyManager() { if (m_props) g_object_unref(m_props); } void PropertyManager::setProperties(IBusPropList* props) { if (m_props) g_object_unref(m_props); m_props = props; if (m_props) g_object_ref(m_props); } IBusProperty* PropertyManager::property(const QByteArray& key) { if (!m_props) - return NULL; + return nullptr; return searchList(key, m_props); } IBusProperty* PropertyManager::searchList(const QByteArray& key, IBusPropList* props) { if (!props) - return NULL; + return nullptr; int i = 0; while (true) { IBusProperty* prop = ibus_prop_list_get(props, i); if (!prop) break; if (ibus_property_get_key(prop) == key) return prop; if (ibus_property_get_prop_type(prop) == PROP_TYPE_MENU) { IBusProperty* p = searchList(key, ibus_property_get_sub_props(prop)); if (p) return p; } i++; } - return NULL; + return nullptr; } void PropertyManager::updateProperty(IBusProperty* prop) { if (m_props) ibus_prop_list_update_property(m_props, prop); } diff --git a/applets/pager/plugin/pagermodel.cpp b/applets/pager/plugin/pagermodel.cpp index 9268ed630..e13898ef6 100644 --- a/applets/pager/plugin/pagermodel.cpp +++ b/applets/pager/plugin/pagermodel.cpp @@ -1,647 +1,647 @@ /******************************************************************** Copyright 2007 Daniel Laidig Copyright 2012 Luís Gabriel Lima Copyright 2016 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 "pagermodel.h" #include "windowmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace TaskManager; class PagerModel::Private { public: Private(PagerModel *q); ~Private(); static int instanceCount; bool componentComplete = false; PagerType pagerType = VirtualDesktops; bool enabled = false; bool showDesktop = false; bool showOnlyCurrentScreen = false; QRect screenGeometry; WindowTasksModel *tasksModel = nullptr; static ActivityInfo *activityInfo; QMetaObject::Connection activityNumberConn; QMetaObject::Connection activityNamesConn; static VirtualDesktopInfo *virtualDesktopInfo; QMetaObject::Connection virtualDesktopNumberConn; QMetaObject::Connection virtualDesktopNamesConn; QDesktopWidget *desktopWidget = QApplication::desktop(); QList windowModels; #if HAVE_X11 QList cachedStackingOrder = KWindowSystem::stackingOrder(); #endif void refreshDataSource(); private: PagerModel *q; }; int PagerModel::Private::instanceCount = 0; ActivityInfo *PagerModel::Private::activityInfo = nullptr; VirtualDesktopInfo *PagerModel::Private::virtualDesktopInfo = nullptr; PagerModel::Private::Private(PagerModel *q) : q(q) { ++instanceCount; if (!activityInfo) { activityInfo = new ActivityInfo(); } QObject::connect(activityInfo, &ActivityInfo::numberOfRunningActivitiesChanged, q, &PagerModel::shouldShowPagerChanged); if (!virtualDesktopInfo) { virtualDesktopInfo = new VirtualDesktopInfo(); } QObject::connect(virtualDesktopInfo, &VirtualDesktopInfo::numberOfDesktopsChanged, q, &PagerModel::shouldShowPagerChanged); QObject::connect(activityInfo, &ActivityInfo::currentActivityChanged, q, [this]() { if (pagerType == VirtualDesktops && windowModels.count()) { for (auto windowModel : windowModels) { windowModel->setActivity(activityInfo->currentActivity()); } } } ); QObject::connect(virtualDesktopInfo, &VirtualDesktopInfo::desktopLayoutRowsChanged, q, &PagerModel::layoutRowsChanged); QObject::connect(desktopWidget, &QDesktopWidget::screenCountChanged, q, &PagerModel::pagerItemSizeChanged); QObject::connect(desktopWidget, &QDesktopWidget::resized, q, &PagerModel::pagerItemSizeChanged); #if HAVE_X11 QObject::connect(KWindowSystem::self(), &KWindowSystem::stackingOrderChanged, q, [this]() { cachedStackingOrder = KWindowSystem::stackingOrder(); for (auto windowModel : windowModels) { windowModel->refreshStackingOrder(); } } ); #endif } PagerModel::Private::~Private() { --instanceCount; if (!instanceCount) { delete activityInfo; activityInfo = nullptr; delete virtualDesktopInfo; virtualDesktopInfo = nullptr; } } void PagerModel::Private::refreshDataSource() { if (pagerType == VirtualDesktops) { QObject::disconnect(virtualDesktopNumberConn); virtualDesktopNumberConn = QObject::connect(virtualDesktopInfo, &VirtualDesktopInfo::numberOfDesktopsChanged, q, [this]() { q->refresh(); }); QObject::disconnect(virtualDesktopNamesConn); virtualDesktopNamesConn = QObject::connect(virtualDesktopInfo, &VirtualDesktopInfo::desktopNamesChanged, q, [this]() { if (q->rowCount()) { emit q->dataChanged(q->index(0, 0), q->index(q->rowCount() - 1, 0), QVector{Qt::DisplayRole}); } } ); QObject::disconnect(activityNumberConn); QObject::disconnect(activityNamesConn); QObject::disconnect(activityInfo, &ActivityInfo::currentActivityChanged, q, &PagerModel::currentPageChanged); QObject::connect(virtualDesktopInfo, &VirtualDesktopInfo::currentDesktopChanged, q, &PagerModel::currentPageChanged, Qt::UniqueConnection); } else { QObject::disconnect(activityNumberConn); activityNumberConn = QObject::connect(activityInfo, &ActivityInfo::numberOfRunningActivitiesChanged, q, [this]() { q->refresh(); }); QObject::disconnect(activityNamesConn); activityNamesConn = QObject::connect(activityInfo, &ActivityInfo::namesOfRunningActivitiesChanged, q, [this]() { q->refresh(); }); QObject::disconnect(virtualDesktopNumberConn); QObject::disconnect(virtualDesktopNamesConn); QObject::disconnect(virtualDesktopInfo, &VirtualDesktopInfo::currentDesktopChanged, q, &PagerModel::currentPageChanged); QObject::connect(activityInfo, &ActivityInfo::currentActivityChanged, q, &PagerModel::currentPageChanged, Qt::UniqueConnection); } emit q->currentPageChanged(); } PagerModel::PagerModel(QObject *parent) : QAbstractListModel(parent) , d(new Private(this)) { d->tasksModel = new WindowTasksModel(this); } PagerModel::~PagerModel() { } QHash PagerModel::roleNames() const { QHash roles = QAbstractItemModel::roleNames(); QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles")); for (int i = 0; i < e.keyCount(); ++i) { roles.insert(e.value(i), e.key(i)); } return roles; } int PagerModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return d->windowModels.count(); } QVariant PagerModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() < 0 || index.row() >= d->windowModels.count()) { return QVariant(); } if (role == Qt::DisplayRole) { if (d->pagerType == VirtualDesktops) { return d->virtualDesktopInfo->desktopNames().at(index.row()); } else { QString activityId = d->activityInfo->runningActivities().at(index.row()); return d->activityInfo->activityName(activityId); } } else if (role == TasksModel) { return QVariant::fromValue(d->windowModels.at(index.row())); } return QVariant(); } PagerModel::PagerType PagerModel::pagerType() const { return d->pagerType; } void PagerModel::setPagerType(PagerType type) { if (d->pagerType != type) { d->pagerType = type; refresh(); emit pagerTypeChanged(); emit shouldShowPagerChanged(); } } bool PagerModel::enabled() const { return d->enabled; } void PagerModel::setEnabled(bool enabled) { if (enabled && !d->enabled) { refresh(); d->enabled = true; emit enabledChanged(); } else if (!enabled && d->enabled) { beginResetModel(); disconnect(d->activityNumberConn); disconnect(d->activityNamesConn); disconnect(d->virtualDesktopNumberConn); disconnect(d->virtualDesktopNamesConn); qDeleteAll(d->windowModels); d->windowModels.clear(); endResetModel(); d->enabled = false; emit enabledChanged(); emit countChanged(); } } bool PagerModel::shouldShowPager() const { return (d->pagerType == VirtualDesktops) ? d->virtualDesktopInfo->numberOfDesktops() > 1 : d->activityInfo->numberOfRunningActivities() > 1; } bool PagerModel::showDesktop() const { return d->showDesktop; } void PagerModel::setShowDesktop(bool show) { if (d->showDesktop != show) { d->showDesktop = show; emit showDesktopChanged(); } } bool PagerModel::showOnlyCurrentScreen() const { return d->showOnlyCurrentScreen; } void PagerModel::setShowOnlyCurrentScreen(bool show) { if (d->showOnlyCurrentScreen != show) { d->showOnlyCurrentScreen = show; if (d->screenGeometry.isValid()) { emit pagerItemSizeChanged(); refresh(); } emit showOnlyCurrentScreenChanged(); } } QRect PagerModel::screenGeometry() const { return d->screenGeometry; } void PagerModel::setScreenGeometry(const QRect &geometry) { if (d->screenGeometry != geometry) { d->screenGeometry = geometry; if (d->showOnlyCurrentScreen) { emit pagerItemSizeChanged(); refresh(); } emit showOnlyCurrentScreenChanged(); } } int PagerModel::currentPage() const { if (d->pagerType == VirtualDesktops) { return d->virtualDesktopInfo->currentDesktop() - 1; } else { return d->activityInfo->runningActivities().indexOf(d->activityInfo->currentActivity()); } } int PagerModel::layoutRows() const { return qBound(1, d->virtualDesktopInfo->desktopLayoutRows(), d->virtualDesktopInfo->numberOfDesktops()); } QSize PagerModel::pagerItemSize() const { if (d->showOnlyCurrentScreen && d->screenGeometry.isValid()) { return d->screenGeometry.size(); } QRect totalRect; for (int i = 0; i < d->desktopWidget->screenCount(); ++i) { totalRect |= d->desktopWidget->screenGeometry(i); } return totalRect.size(); } #if HAVE_X11 QList PagerModel::stackingOrder() const { return d->cachedStackingOrder; } #endif void PagerModel::refresh() { if (!d->componentComplete) { return; } beginResetModel(); d->refreshDataSource(); int modelCount = d->windowModels.count(); const int modelsNeeded = ((d->pagerType == VirtualDesktops) ? d->virtualDesktopInfo->numberOfDesktops() : d->activityInfo->numberOfRunningActivities()); if (modelCount > modelsNeeded) { while (modelCount != modelsNeeded) { delete d->windowModels.takeLast(); --modelCount; } } else if (modelsNeeded > modelCount) { while (modelCount != modelsNeeded) { WindowModel *windowModel = new WindowModel(this); windowModel->setFilterSkipPager(true); windowModel->setFilterByVirtualDesktop(true); windowModel->setFilterByActivity(true); windowModel->setDemandingAttentionSkipsFilters(false); windowModel->setSourceModel(d->tasksModel); d->windowModels.append(windowModel); ++modelCount; } } if (d->pagerType == VirtualDesktops) { int virtualDesktop = 1; for (auto windowModel : d->windowModels) { windowModel->setVirtualDesktop(virtualDesktop); ++virtualDesktop; windowModel->setActivity(d->activityInfo->currentActivity()); } } else { int activityIndex = 0; const QStringList &runningActivities = d->activityInfo->runningActivities(); for (auto windowModel : d->windowModels) { windowModel->setVirtualDesktop(0); windowModel->setActivity(runningActivities.at(activityIndex)); ++activityIndex; } } for (auto windowModel : d->windowModels) { if (d->showOnlyCurrentScreen && d->screenGeometry.isValid()) { windowModel->setScreenGeometry(d->screenGeometry); windowModel->setFilterByScreen(true); } else { windowModel->setFilterByScreen(false); } } endResetModel(); emit countChanged(); } void PagerModel::moveWindow(int window, double x, double y, int targetItemId, int sourceItemId, qreal widthScaleFactor, qreal heightScaleFactor) { #if HAVE_X11 if (!KWindowSystem::isPlatformX11()) { return; } const WId windowId = (WId)window; QPointF dest(x / widthScaleFactor, y / heightScaleFactor); // Don't move windows to negative positions. dest = QPointF(qMax(dest.x(), qreal(0.0)), qMax(dest.y(), qreal(0.0))); // Use _NET_MOVERESIZE_WINDOW rather than plain move, so that the WM knows this is a pager request. - NETRootInfo info(QX11Info::connection(), 0); + NETRootInfo info(QX11Info::connection(), nullptr); const int flags = (0x20 << 12) | (0x03 << 8) | 1; // From tool, x/y, northwest gravity. if (!KWindowSystem::mapViewport()) { KWindowInfo windowInfo(windowId, NET::WMDesktop | NET::WMState, NET::WM2Activities); if (d->pagerType == VirtualDesktops) { if (!windowInfo.onAllDesktops()) { KWindowSystem::setOnDesktop(windowId, targetItemId + 1); } } else { const QStringList &runningActivities = d->activityInfo->runningActivities(); if (targetItemId < runningActivities.length()) { const QString &newActivity = runningActivities.at(targetItemId); QStringList activities = windowInfo.activities(); if (!activities.contains(newActivity)) { activities.removeOne(runningActivities.at(sourceItemId)); activities.append(newActivity); KWindowSystem::setOnActivities(windowId, activities); } } } // Only move the window if it is not full screen and if it is kept within the same desktop. // Moving when dropping between desktop is too annoying due to the small drop area. if (!(windowInfo.state() & NET::FullScreen) && (targetItemId == sourceItemId || windowInfo.onAllDesktops())) { const QPoint &d = dest.toPoint(); info.moveResizeWindowRequest(windowId, flags, d.x(), d.y(), 0, 0); } } else { // setOnDesktop() with viewports is also moving a window, and since it takes a moment // for the WM to do the move, there's a race condition with figuring out how much to move, // so do it only as one move. dest += KWindowSystem::desktopToViewport(targetItemId + 1, false); const QPoint &d = KWindowSystem::constrainViewportRelativePosition(dest.toPoint()); info.moveResizeWindowRequest(windowId, flags, d.x(), d.y(), 0, 0); } #else Q_UNUSED(window) Q_UNUSED(x) Q_UNUSED(y) Q_UNUSED(targetDesktop) Q_UNUSED(sourceDesktop) #endif } void PagerModel::changePage(int page) { #if HAVE_X11 if (!KWindowSystem::isPlatformX11()) { return; } if (currentPage() == page) { if (d->showDesktop) { QDBusConnection::sessionBus().asyncCall(QDBusMessage::createMethodCall(QLatin1String("org.kde.plasmashell"), QLatin1String("/PlasmaShell"), QLatin1String("org.kde.PlasmaShell"), QLatin1String("toggleDashboard"))); } } else { if (d->pagerType == VirtualDesktops) { KWindowSystem::setCurrentDesktop(page + 1); } else { const QStringList &runningActivities = d->activityInfo->runningActivities(); if (page < runningActivities.length()) { KActivities::Controller activitiesController; activitiesController.setCurrentActivity(runningActivities.at(page)); } } } #else Q_UNUSED(itemId) #endif } void PagerModel::drop(QMimeData *mimeData, int itemId) { if (!mimeData) { return; } #if HAVE_X11 if (KWindowSystem::isPlatformX11()) { bool ok; const QList &ids = TaskManager::XWindowTasksModel::winIdsFromMimeData(mimeData, &ok); if (!ok) { return; } if (d->pagerType == VirtualDesktops) { for (const auto &id : ids) { KWindowSystem::setOnDesktop(id, itemId + 1); } } else { QString newActivity; const QStringList &runningActivities = d->activityInfo->runningActivities(); if (itemId < runningActivities.length()) { newActivity = runningActivities.at(itemId); } if (newActivity.isEmpty()) { return; } for (const auto &id : ids) { - QStringList activities = KWindowInfo(id, 0, NET::WM2Activities).activities(); + QStringList activities = KWindowInfo(id, nullptr, NET::WM2Activities).activities(); if (!activities.contains(newActivity)) { KWindowSystem::setOnActivities(id, activities << newActivity); } } } } #else Q_UNUSED(itemId) #endif } void PagerModel::addDesktop() { #if HAVE_X11 if (!KWindowSystem::isPlatformX11()) { return; } NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops); info.setNumberOfDesktops(info.numberOfDesktops() + 1); #endif } void PagerModel::removeDesktop() { #if HAVE_X11 if (!KWindowSystem::isPlatformX11()) { return; } NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops); if (info.numberOfDesktops() > 1) { info.setNumberOfDesktops(info.numberOfDesktops() - 1); } #endif } void PagerModel::classBegin() { } void PagerModel::componentComplete() { d->componentComplete = true; if (d->enabled) { refresh(); } } #include "moc_pagermodel.cpp" diff --git a/containments/desktop/plugins/folder/autotests/foldermodeltest.cpp b/containments/desktop/plugins/folder/autotests/foldermodeltest.cpp index 2e87e7d46..744fce76e 100644 --- a/containments/desktop/plugins/folder/autotests/foldermodeltest.cpp +++ b/containments/desktop/plugins/folder/autotests/foldermodeltest.cpp @@ -1,384 +1,384 @@ /*************************************************************************** * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company * * * * Author: Andras Mantia * * * * 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 "foldermodeltest.h" #include "foldermodel.h" #include "screenmapper.h" #include #include #include QTEST_MAIN(FolderModelTest) static const QLatin1String desktop(QLatin1String("Desktop")); static QUrl stringToUrl(const QString &path) { return QUrl::fromUserInput(path, {}, QUrl::AssumeLocalFile); } void FolderModelTest::createTestFolder(const QString &path) { QDir dir(m_folderDir->path()); dir.mkdir(path); dir.cd(path); dir.mkdir("firstDir"); QFile f; for (int i = 1; i < 10; i++) { f.setFileName(QStringLiteral("%1/file%2.txt").arg(dir.path(), QString::number(i))); f.open(QFile::WriteOnly); f.close(); } } void FolderModelTest::init() { m_folderDir = new QTemporaryDir(); createTestFolder(desktop); m_folderModel = new FolderModel(this); m_folderModel->classBegin(); m_folderModel->setUrl(m_folderDir->path() + QDir::separator() + desktop ); m_folderModel->componentComplete(); QSignalSpy s(m_folderModel, &FolderModel::listingCompleted); s.wait(1000); } void FolderModelTest::cleanup() { delete m_folderDir; - m_folderDir = 0; + m_folderDir = nullptr; delete m_folderModel; m_folderModel = nullptr; } void FolderModelTest::tst_listing() { QCOMPARE(m_folderModel->url(), m_folderDir->path() + QDir::separator() + desktop); const auto count = m_folderModel->rowCount(); QCOMPARE(count, 10); QCOMPARE(m_folderModel->index(0, 0).data(FolderModel::FileNameRole).toString(), QLatin1String("firstDir")); for (int i = 1; i < count; i++) { const auto index = m_folderModel->index(i, 0); QCOMPARE(index.data(FolderModel::FileNameRole).toString(), QStringLiteral("file%1.txt").arg(i)); } } void FolderModelTest::tst_listingDescending() { m_folderModel->setSortDesc(true); QCOMPARE(m_folderModel->index(0, 0).data(FolderModel::FileNameRole).toString(), QLatin1String("firstDir")); const auto count = m_folderModel->rowCount(); for (int i = 1; i < count; i++) { const auto index = m_folderModel->index(i, 0); QCOMPARE(index.data(FolderModel::FileNameRole).toString(), QStringLiteral("file%1.txt").arg(count - i)); } } void FolderModelTest::tst_listingFolderNotFirst() { const auto count = m_folderModel->rowCount(); m_folderModel->setSortDirsFirst(false); QCOMPARE(count, 10); QCOMPARE(m_folderModel->index(9, 0).data(FolderModel::FileNameRole).toString(), QLatin1String("firstDir")); for (int i = 0; i < count - 1; i++) { const auto index = m_folderModel->index(i, 0); QCOMPARE(index.data(FolderModel::FileNameRole).toString(), QStringLiteral("file%1.txt").arg(i + 1)); } } void FolderModelTest::tst_filterListing() { // a little bit weird API, as both pattern and mimetype needs to be set m_folderModel->setFilterPattern("*.txt"); m_folderModel->setFilterMimeTypes({"all/all"}); m_folderModel->setFilterMode(FolderModel::FilterShowMatches); const auto count = m_folderModel->rowCount(); QCOMPARE(count, 9); for (int i = 0; i < count; i++) { const auto index = m_folderModel->index(i, 0); QCOMPARE(index.data(FolderModel::FileNameRole).toString(), QStringLiteral("file%1.txt").arg(i + 1)); } } void FolderModelTest::tst_cd() { QSignalSpy s(m_folderModel, &FolderModel::listingCompleted); //go into firstDir subfolder const auto url = m_folderModel->resolvedUrl(); m_folderModel->cd(0); QVERIFY(s.wait(500)); const auto url2 = m_folderModel->resolvedUrl(); QVERIFY(url.isParentOf(url2)); //go back to Desktop m_folderModel->up(); QVERIFY(s.wait(500)); QCOMPARE(m_folderModel->resolvedUrl(), url); //try to cd to an invalid entry (a file) m_folderModel->cd(1); //Signal is not emitted here as it's invalided QVERIFY(!s.wait(500)); QCOMPARE(m_folderModel->resolvedUrl(), url); } void FolderModelTest::tst_rename_data() { QTest::addColumn("row"); QTest::addColumn("name"); QTest::newRow("Folder rename") << 0 << "firstDirRenamed"; QTest::newRow("File rename") << 1 << "file1.pdf"; QTest::newRow("Invalid rename") << 11 << "foo"; } void FolderModelTest::tst_rename() { QFETCH(int, row); QFETCH(QString, name); m_folderModel->rename(row, name); QSignalSpy s(m_folderModel, &FolderModel::listingCompleted); const auto index = m_folderModel->index(row, 0); s.wait(500); QEXPECT_FAIL("Invalid rename", "This is expected to fail", Continue); QCOMPARE(index.data(FolderModel::FileNameRole).toString(), name); } void FolderModelTest::tst_selection() { m_folderModel->setSelected(1); QVERIFY(m_folderModel->hasSelection()); QVERIFY(m_folderModel->isSelected(1)); m_folderModel->clearSelection(); QVERIFY(!m_folderModel->hasSelection()); m_folderModel->toggleSelected(1); QVERIFY(m_folderModel->isSelected(1)); m_folderModel->toggleSelected(1); QVERIFY(!m_folderModel->isSelected(1)); m_folderModel->setRangeSelected(1, 4); QVERIFY(m_folderModel->hasSelection()); for (int i = 1; i <= 4; i++) { QVERIFY(m_folderModel->isSelected(i)); } m_folderModel->updateSelection({5, 6}, false); for (int i = 1; i <= 4; i++) { QVERIFY(!m_folderModel->isSelected(i)); } QVERIFY(m_folderModel->isSelected(5)); QVERIFY(m_folderModel->isSelected(6)); m_folderModel->setRangeSelected(1, 4); m_folderModel->pinSelection(); m_folderModel->updateSelection({5, 6}, true); for (int i = 1; i <= 6; i++) { QVERIFY(m_folderModel->isSelected(i)); } m_folderModel->unpinSelection(); m_folderModel->updateSelection({5, 6}, true); for (int i = 1; i <= 6; i++) { if (i < 5) { QVERIFY(!m_folderModel->isSelected(i)); } else { QVERIFY(m_folderModel->isSelected(i)); } } } void FolderModelTest::tst_defaultValues() { FolderModel folderModel; QCOMPARE(folderModel.status(), FolderModel::Status::None); QVERIFY(folderModel.locked()); QVERIFY(!folderModel.sortDesc()); QVERIFY(folderModel.sortDirsFirst()); QVERIFY(!folderModel.parseDesktopFiles()); QVERIFY(!folderModel.previews()); QVERIFY(!folderModel.usedByContainment()); QCOMPARE(folderModel.sortMode(), 0); QCOMPARE(folderModel.filterMode(), (int)FolderModel::NoFilter); QVERIFY(folderModel.newMenu()); QCOMPARE(folderModel.filterCaseSensitivity(), Qt::CaseInsensitive); QVERIFY(folderModel.dynamicSortFilter()); QVERIFY(folderModel.isSortLocaleAware()); } void FolderModelTest::tst_actionMenu() { const QStringList lst { QStringLiteral("open"), QStringLiteral("cut"), QStringLiteral("open"), QStringLiteral("cut"), QStringLiteral("undo"), QStringLiteral("copy"), QStringLiteral("paste"), QStringLiteral("pasteto"), QStringLiteral("refresh"), QStringLiteral("rename"), QStringLiteral("trash"), QStringLiteral("del"), QStringLiteral("restoreFromTrash"), QStringLiteral("emptyTrash") }; for (const QString &str : lst) { QVERIFY(m_folderModel->action(str)); } } void FolderModelTest::tst_lockedChanged() { QSignalSpy s(m_folderModel, &FolderModel::lockedChanged); m_folderModel->setLocked(false); QCOMPARE(s.count(), 1); m_folderModel->setLocked(false); QCOMPARE(s.count(), 1); m_folderModel->setLocked(true); QCOMPARE(s.count(), 2); } void FolderModelTest::tst_multiScreen() { delete m_folderModel; // Custom instance for this test to set used by containment before marking component // as complete. m_folderModel = new FolderModel(this); m_folderModel->classBegin(); m_folderModel->setUrl(m_folderDir->path() + QDir::separator() + desktop ); m_folderModel->setUsedByContainment(true); m_folderModel->setScreen(0); m_folderModel->componentComplete(); auto *screenMapper = ScreenMapper::instance(); QSignalSpy s(m_folderModel, &FolderModel::listingCompleted); QVERIFY(s.wait(1000)); const auto count = m_folderModel->rowCount(); for (int i = 0; i < count; i++) { const auto index = m_folderModel->index(i, 0); const auto name = index.data(FolderModel::UrlRole).toUrl(); // all items are on the first screen by default QCOMPARE(screenMapper->screenForItem(name), 0); } // move one file to a new screen const auto movedItem = m_folderModel->index(0, 0).data(FolderModel::UrlRole).toUrl(); FolderModel secondFolderModel; secondFolderModel.classBegin(); secondFolderModel.setUrl(m_folderDir->path() + QDir::separator() + desktop ); secondFolderModel.setUsedByContainment(true); secondFolderModel.setScreen(1); secondFolderModel.componentComplete(); QSignalSpy s2(&secondFolderModel, &FolderModel::listingCompleted); QVERIFY(s2.wait(1000)); const auto count2 = secondFolderModel.rowCount(); QCOMPARE(count2, 0); screenMapper->addMapping(movedItem, 1); m_folderModel->invalidate(); secondFolderModel.invalidate(); s.wait(1000); s2.wait(1000); // we have one less item QCOMPARE(m_folderModel->rowCount(), count - 1); QCOMPARE(secondFolderModel.rowCount(), 1); QCOMPARE(secondFolderModel.index(0,0).data(FolderModel::UrlRole).toUrl(), movedItem); QCOMPARE(screenMapper->screenForItem(movedItem), 1); // remove extra screen, we have all items back screenMapper->removeScreen(1, stringToUrl(m_folderModel->url())); s.wait(500); QCOMPARE(m_folderModel->rowCount(), count); QCOMPARE(secondFolderModel.rowCount(), 0); QCOMPARE(screenMapper->screenForItem(movedItem), 0); // add back extra screen, the item is moved there screenMapper->addScreen(1, stringToUrl(m_folderModel->url())); s.wait(500); s2.wait(500); QCOMPARE(m_folderModel->rowCount(), count - 1); QCOMPARE(secondFolderModel.rowCount(), 1); QCOMPARE(secondFolderModel.index(0,0).data(FolderModel::UrlRole).toUrl(), movedItem); QCOMPARE(screenMapper->screenForItem(movedItem), 1); // create a new item, it appears on the first screen QDir dir(m_folderDir->path()); dir.cd(desktop); dir.mkdir("secondDir"); dir.cd("secondDir"); s.wait(1000); QCOMPARE(m_folderModel->rowCount(), count); QCOMPARE(secondFolderModel.rowCount(), 1); QCOMPARE(screenMapper->screenForItem(stringToUrl("file://" + dir.path())), 0); } void FolderModelTest::tst_multiScreenDifferenPath() { auto *screenMapper = ScreenMapper::instance(); m_folderModel->setUsedByContainment(true); m_folderModel->setScreen(0); QSignalSpy s(m_folderModel, &FolderModel::listingCompleted); s.wait(1000); const auto count = m_folderModel->rowCount(); QCOMPARE(count, 10); const QLatin1String desktop2(QLatin1String("Desktop2")); createTestFolder(desktop2); FolderModel secondFolderModel; secondFolderModel.setUsedByContainment(true); secondFolderModel.setUrl(m_folderDir->path() + QDir::separator() + desktop2 ); secondFolderModel.setScreen(1); QSignalSpy s2(&secondFolderModel, &FolderModel::listingCompleted); s2.wait(1000); const auto count2 = secondFolderModel.rowCount(); QCOMPARE(count2, 10); // create a new item, it appears on the first screen QDir dir(m_folderDir->path()); dir.cd(desktop); dir.mkdir("secondDir"); s.wait(1000); QCOMPARE(m_folderModel->rowCount(), count + 1); QCOMPARE(secondFolderModel.rowCount(), count2); // create a new item, it appears on the second screen dir.cd(m_folderDir->path() + QDir::separator() + desktop2); dir.mkdir("secondDir2"); s.wait(1000); QCOMPARE(m_folderModel->rowCount(), count + 1); QCOMPARE(secondFolderModel.rowCount(), count2 + 1); } diff --git a/containments/desktop/plugins/folder/labelgenerator.cpp b/containments/desktop/plugins/folder/labelgenerator.cpp index ccee50e22..b2d62cdcd 100644 --- a/containments/desktop/plugins/folder/labelgenerator.cpp +++ b/containments/desktop/plugins/folder/labelgenerator.cpp @@ -1,187 +1,187 @@ /*************************************************************************** * Copyright © 2008, 2009 Fredrik Höglund * * Copyright (C) 2013-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 "labelgenerator.h" #include #include #include "foldermodel.h" int LabelGenerator::s_instanceCount = 0; KFilePlacesModel *LabelGenerator::s_placesModel = nullptr; LabelGenerator::LabelGenerator(QObject* parent) : QObject(parent), m_rtl(false), m_labelMode(1) { ++s_instanceCount; } LabelGenerator::~LabelGenerator() { --s_instanceCount; if (!s_instanceCount) { delete s_placesModel; s_placesModel = nullptr; } } FolderModel *LabelGenerator::folderModel() const { return m_folderModel.data(); } void LabelGenerator::setFolderModel(FolderModel *folderModel) { if (m_folderModel.data() != folderModel) { if (m_folderModel.data()) { - disconnect(m_folderModel.data(), 0, this, 0); + disconnect(m_folderModel.data(), nullptr, this, nullptr); } m_folderModel = folderModel; connect(m_folderModel.data(), &FolderModel::listingCompleted, this, &LabelGenerator::updateDisplayLabel); connect(m_folderModel.data(), &FolderModel::listingCanceled, this, &LabelGenerator::updateDisplayLabel); emit folderModelChanged(); updateDisplayLabel(); } } bool LabelGenerator::rtl() const { return m_rtl; } void LabelGenerator::setRtl(bool rtl) { if (rtl != m_rtl) { m_rtl = rtl; emit rtlChanged(); updateDisplayLabel(); } } int LabelGenerator::labelMode() const { return m_labelMode; } void LabelGenerator::setLabelMode(int mode) { if (mode != m_labelMode) { m_labelMode = mode; emit labelModeChanged(); updateDisplayLabel(); } } QString LabelGenerator::labelText() const { return m_labelText; } void LabelGenerator::setLabelText(const QString& text) { if (text != m_labelText) { m_labelText = text; emit labelTextChanged(); updateDisplayLabel(); } } QString LabelGenerator::displayLabel() const { return m_displayLabel; } void LabelGenerator::updateDisplayLabel() { const QString displayLabel = generatedDisplayLabel(); if (m_displayLabel != displayLabel) { m_displayLabel = displayLabel; emit displayLabelChanged(); } } QString LabelGenerator::generatedDisplayLabel() { if (!m_folderModel) { return QString(); } QUrl url = m_folderModel->resolvedUrl(); if (m_labelMode == 1 /* Default */) { if (url.path().length() <= 1) { const KFileItem &rootItem = m_folderModel->rootItem(); if (rootItem.text() != QLatin1String(".")) { return rootItem.text(); } } QString label(url.toDisplayString(QUrl::PreferLocalFile | QUrl::StripTrailingSlash)); if (!s_placesModel) { s_placesModel = new KFilePlacesModel(); } connectPlacesModel(); const QModelIndex index = s_placesModel->closestItem(url); if (index.isValid()) { QString root = s_placesModel->url(index).toDisplayString(QUrl::PreferLocalFile | QUrl::StripTrailingSlash); label = label.right(label.length() - root.length()); if (!label.isEmpty()) { if (label.at(0) == QLatin1Char('/')) { label.remove(0, 1); } if (m_rtl) { label.prepend(QLatin1String(" < ")); } else { label.prepend(QLatin1String(" > ")); } } label.prepend(s_placesModel->text(index)); } return label; } else if (m_labelMode == 2 /* Full path */) { return QUrl(url).toDisplayString(QUrl::PreferLocalFile | QUrl::StripTrailingSlash); } else if (m_labelMode == 3 /* Custom title */) { return m_labelText; } return QString(); } void LabelGenerator::connectPlacesModel() { connect(s_placesModel, &KFilePlacesModel::rowsInserted, this, &LabelGenerator::updateDisplayLabel, Qt::UniqueConnection); connect(s_placesModel, &KFilePlacesModel::rowsRemoved, this, &LabelGenerator::updateDisplayLabel, Qt::UniqueConnection); connect(s_placesModel, &KFilePlacesModel::dataChanged, this, &LabelGenerator::updateDisplayLabel, Qt::UniqueConnection); } diff --git a/imports/activitymanager/sortedactivitiesmodel.cpp b/imports/activitymanager/sortedactivitiesmodel.cpp index 6d4a1de4f..596fdc26b 100644 --- a/imports/activitymanager/sortedactivitiesmodel.cpp +++ b/imports/activitymanager/sortedactivitiesmodel.cpp @@ -1,491 +1,491 @@ /* * Copyright (C) 2016 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Self #include "sortedactivitiesmodel.h" // C++ #include // Qt #include #include #include // KDE #include #include #include #include #include #define KWINDOWSYSTEM_NO_DEPRECATED #include #include #define PLASMACONFIG "plasma-org.kde.plasma.desktop-appletsrc" namespace { class BackgroundCache: public QObject { public: BackgroundCache() : initialized(false) , plasmaConfig(KSharedConfig::openConfig(PLASMACONFIG)) { using namespace std::placeholders; const QString configFile = QStandardPaths::writableLocation( QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + PLASMACONFIG; KDirWatch::self()->addFile(configFile); QObject::connect(KDirWatch::self(), &KDirWatch::dirty, this, &BackgroundCache::settingsFileChanged, Qt::QueuedConnection); QObject::connect(KDirWatch::self(), &KDirWatch::created, this, &BackgroundCache::settingsFileChanged, Qt::QueuedConnection); } void settingsFileChanged(const QString &file) { if (!file.endsWith(PLASMACONFIG)) { return; } if (initialized) { plasmaConfig->reparseConfiguration(); reload(); } } void subscribe(SortedActivitiesModel *model) { if (!initialized) { reload(); } models << model; } void unsubscribe(SortedActivitiesModel *model) { models.removeAll(model); if (models.isEmpty()) { initialized = false; forActivity.clear(); } } QString backgroundFromConfig(const KConfigGroup &config) const { auto wallpaperPlugin = config.readEntry("wallpaperplugin"); auto wallpaperConfig = config.group("Wallpaper").group(wallpaperPlugin).group("General"); if (wallpaperConfig.hasKey("Image")) { // Trying for the wallpaper auto wallpaper = wallpaperConfig.readEntry("Image", QString()); if (!wallpaper.isEmpty()) { return wallpaper; } } if (wallpaperConfig.hasKey("Color")) { auto backgroundColor = wallpaperConfig.readEntry("Color", QColor(0, 0, 0)); return backgroundColor.name(); } return QString(); } void reload() { auto newForActivity = forActivity; QHash lastScreenForActivity; // contains activities for which the wallpaper // has updated QStringList changedActivities; // Contains activities not covered by any containment QStringList ghostActivities = forActivity.keys(); // Traversing through all containments in search for // containments that define activities in plasma for (const auto& containmentId: plasmaConfigContainments().groupList()) { const auto containment = plasmaConfigContainments().group(containmentId); const auto lastScreen = containment.readEntry("lastScreen", 0); const auto activity = containment.readEntry("activityId", QString()); // Ignore the containment if the activity is not defined if (activity.isEmpty()) continue; // If we have already found the same activity from another // containment, we are using the new one only if // the previous one was a color and not a proper wallpaper, // or if the screen ID is closer to zero const bool processed = !ghostActivities.contains(activity) && newForActivity.contains(activity) && (lastScreenForActivity[activity] <= lastScreen); // qDebug() << "GREPME Searching containment " << containmentId // << "for the wallpaper of the " << activity << " activity - " // << "currently, we think that the wallpaper is " << processed << (processed ? newForActivity[activity] : QString()) // << "last screen is" << lastScreen // ; if (processed && newForActivity[activity][0] != '#') continue; // Marking the current activity as processed ghostActivities.removeAll(activity); const auto background = backgroundFromConfig(containment); // qDebug() << " GREPME Found wallpaper: " << background; if (background.isEmpty()) continue; // If we got this far and we already had a new wallpaper for // this activity, it means we now have a better one bool foundBetterWallpaper = changedActivities.contains(activity); if (foundBetterWallpaper || newForActivity[activity] != background) { if (!foundBetterWallpaper) { changedActivities << activity; } // qDebug() << " GREPME Setting: " << activity << " = " << background << "," << lastScreen; newForActivity[activity] = background; lastScreenForActivity[activity] = lastScreen; } } initialized = true; // Removing the activities from the list if we haven't found them // while traversing through the containments for (const auto& activity: ghostActivities) { newForActivity.remove(activity); } // If we have detected the changes, lets notify everyone if (!changedActivities.isEmpty()) { forActivity = newForActivity; for (auto model: models) { model->onBackgroundsUpdated(changedActivities); } } } KConfigGroup plasmaConfigContainments() { return plasmaConfig->group("Containments"); } QHash forActivity; QList models; bool initialized; KSharedConfig::Ptr plasmaConfig; }; static BackgroundCache &backgrounds() { // If you convert this to a shared pointer, // fix the connections to KDirWatcher static BackgroundCache cache; return cache; } } SortedActivitiesModel::SortedActivitiesModel(const QVector &states, QObject *parent) : QSortFilterProxyModel(parent) , m_activitiesModel(new KActivities::ActivitiesModel(states, this)) , m_activities(new KActivities::Consumer(this)) { setSourceModel(m_activitiesModel); setDynamicSortFilter(true); setSortRole(LastTimeUsed); sort(0, Qt::DescendingOrder); backgrounds().subscribe(this); const QList windows = KWindowSystem::stackingOrder(); for (const auto& window: windows) { KWindowInfo info(window, NET::WMVisibleName, NET::WM2Activities); const QStringList activities = info.activities(); if (activities.isEmpty() || activities.contains("00000000-0000-0000-0000-000000000000")) continue; for (const auto& activity: activities) { m_activitiesWindows[activity] << window; } } connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &SortedActivitiesModel::onWindowAdded); connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, &SortedActivitiesModel::onWindowRemoved); connect(KWindowSystem::self(), SIGNAL(windowChanged(WId, NET::Properties, NET::Properties2)), this, SLOT(onWindowChanged(WId, NET::Properties, NET::Properties2))); } SortedActivitiesModel::~SortedActivitiesModel() { backgrounds().unsubscribe(this); } bool SortedActivitiesModel::inhibitUpdates() const { return m_inhibitUpdates; } void SortedActivitiesModel::setInhibitUpdates(bool inhibitUpdates) { if (m_inhibitUpdates != inhibitUpdates) { m_inhibitUpdates = inhibitUpdates; emit inhibitUpdatesChanged(m_inhibitUpdates); setDynamicSortFilter(!inhibitUpdates); } } uint SortedActivitiesModel::lastUsedTime(const QString &activity) const { if (m_activities->currentActivity() == activity) { return ~(uint)0; } else { KConfig config("kactivitymanagerd-switcher", KConfig::SimpleConfig); KConfigGroup times(&config, "LastUsed"); return times.readEntry(activity, (uint)0); } } bool SortedActivitiesModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const { const auto activityLeft = sourceModel()->data(sourceLeft, KActivities::ActivitiesModel::ActivityId); const auto activityRight = sourceModel()->data(sourceRight, KActivities::ActivitiesModel::ActivityId); const auto timeLeft = lastUsedTime(activityLeft.toString()); const auto timeRight = lastUsedTime(activityRight.toString()); return (timeLeft < timeRight) || (timeLeft == timeRight && activityLeft < activityRight); } QHash SortedActivitiesModel::roleNames() const { if (!sourceModel()) return QHash(); auto roleNames = sourceModel()->roleNames(); roleNames[LastTimeUsed] = "lastTimeUsed"; roleNames[LastTimeUsedString] = "lastTimeUsedString"; roleNames[WindowCount] = "windowCount"; roleNames[HasWindows] = "hasWindows"; return roleNames; } QVariant SortedActivitiesModel::data(const QModelIndex &index, int role) const { if (role == KActivities::ActivitiesModel::ActivityBackground) { const auto activity = activityIdForIndex(index); return backgrounds().forActivity[activity]; } else if (role == LastTimeUsed || role == LastTimeUsedString) { const auto activity = activityIdForIndex(index); const auto time = lastUsedTime(activity); if (role == LastTimeUsed) { return QVariant(time); } else { const auto now = QDateTime::currentDateTime().toTime_t(); if (time == 0) return i18n("Used some time ago"); auto diff = now - time; // We do not need to be precise diff /= 60; const auto minutes = diff % 60; diff /= 60; const auto hours = diff % 24; diff /= 24; const auto days = diff % 30; diff /= 30; const auto months = diff % 12; diff /= 12; const auto years = diff; return (years > 0) ? i18n("Used more than a year ago") : (months > 0) ? i18ncp("amount in months", "Used a month ago", "Used %1 months ago", months) : (days > 0) ? i18ncp("amount in days", "Used a day ago", "Used %1 days ago", days) : (hours > 0) ? i18ncp("amount in hours", "Used an hour ago", "Used %1 hours ago", hours) : (minutes > 0) ? i18ncp("amount in minutes", "Used a minute ago", "Used %1 minutes ago", minutes) : i18n("Used a moment ago"); } } else if (role == HasWindows || role == WindowCount) { const auto activity = activityIdForIndex(index); if (role == HasWindows) { return (m_activitiesWindows[activity].size() > 0); } else { return m_activitiesWindows[activity].size(); } } else { return QSortFilterProxyModel::data(index, role); } } QString SortedActivitiesModel::activityIdForIndex(const QModelIndex &index) const { return data(index, KActivities::ActivitiesModel::ActivityId).toString(); } QString SortedActivitiesModel::activityIdForRow(int row) const { return activityIdForIndex(index(row, 0)); } int SortedActivitiesModel::rowForActivityId(const QString &activity) const { int position = -1; for (int row = 0; row < rowCount(); ++row) { if (activity == activityIdForRow(row)) { position = row; } } return position; } QString SortedActivitiesModel::relativeActivity(int relative) const { const auto currentActivity = m_activities->currentActivity(); if (!sourceModel()) return QString(); const auto currentRowCount = sourceModel()->rowCount(); //x % 0 is undefined in c++ if (currentRowCount == 0) { return QString(); } int currentActivityRow = 0; for (; currentActivityRow < currentRowCount; currentActivityRow++) { if (activityIdForRow(currentActivityRow) == currentActivity) break; } currentActivityRow = currentActivityRow + relative; //wrap to within bounds for both positive and negative currentActivityRows currentActivityRow = (currentRowCount + (currentActivityRow % currentRowCount)) % currentRowCount; return activityIdForRow(currentActivityRow); } void SortedActivitiesModel::onCurrentActivityChanged(const QString ¤tActivity) { if (m_previousActivity == currentActivity) return; const int previousActivityRow = rowForActivityId(m_previousActivity); emit rowChanged(previousActivityRow, { LastTimeUsed, LastTimeUsedString }); m_previousActivity = currentActivity; const int currentActivityRow = rowForActivityId(m_previousActivity); emit rowChanged(currentActivityRow, { LastTimeUsed, LastTimeUsedString }); } void SortedActivitiesModel::onBackgroundsUpdated(const QStringList &activities) { for (const auto &activity: activities) { const int row = rowForActivityId(activity); emit rowChanged(row, { KActivities::ActivitiesModel::ActivityBackground }); } } void SortedActivitiesModel::onWindowAdded(WId window) { - KWindowInfo info(window, 0, NET::WM2Activities); + KWindowInfo info(window, nullptr, NET::WM2Activities); const QStringList activities = info.activities(); if (activities.isEmpty() || activities.contains("00000000-0000-0000-0000-000000000000")) return; for (const auto& activity: activities) { if (!m_activitiesWindows[activity].contains(window)) { m_activitiesWindows[activity] << window; rowChanged(rowForActivityId(activity), m_activitiesWindows.size() == 1 ? QVector{WindowCount, HasWindows} : QVector{WindowCount}); } } } void SortedActivitiesModel::onWindowRemoved(WId window) { for (const auto& activity: m_activitiesWindows.keys()) { if (m_activitiesWindows[activity].contains(window)) { m_activitiesWindows[activity].removeAll(window); rowChanged(rowForActivityId(activity), m_activitiesWindows.size() == 0 ? QVector{WindowCount, HasWindows} : QVector{WindowCount}); } } } void SortedActivitiesModel::onWindowChanged(WId window, NET::Properties properties, NET::Properties2 properties2) { Q_UNUSED(properties); if (properties2 & NET::WM2Activities) { onWindowRemoved(window); onWindowAdded(window); } } void SortedActivitiesModel::rowChanged(int row, const QVector &roles) { if (row == -1) return; emit dataChanged(index(row, 0), index(row, 0), roles); } diff --git a/kaccess/kaccess.cpp b/kaccess/kaccess.cpp index 7a0a62e43..4b200c6dc 100644 --- a/kaccess/kaccess.cpp +++ b/kaccess/kaccess.cpp @@ -1,996 +1,996 @@ /* Copyright 2000 Matthias Hölzer-Klüpfel Copyright 2014 Frederik Gladhorn This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include "kaccess.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 #define XK_MISCELLANY #define XK_XKB_KEYS #include #include #include Q_LOGGING_CATEGORY(logKAccess, "kcm_kaccess") struct ModifierKey { const unsigned int mask; const KeySym keysym; const char *name; const char *lockedText; const char *latchedText; const char *unlatchedText; }; static const ModifierKey modifierKeys[] = { { ShiftMask, 0, "Shift", I18N_NOOP("The Shift key has been locked and is now active for all of the following keypresses."), I18N_NOOP("The Shift key is now active."), I18N_NOOP("The Shift key is now inactive.") }, { ControlMask, 0, "Control", I18N_NOOP("The Control key has been locked and is now active for all of the following keypresses."), I18N_NOOP("The Control key is now active."), I18N_NOOP("The Control key is now inactive.") }, { 0, XK_Alt_L, "Alt", I18N_NOOP("The Alt key has been locked and is now active for all of the following keypresses."), I18N_NOOP("The Alt key is now active."), I18N_NOOP("The Alt key is now inactive.") }, { 0, 0, "Win", I18N_NOOP("The Win key has been locked and is now active for all of the following keypresses."), I18N_NOOP("The Win key is now active."), I18N_NOOP("The Win key is now inactive.") }, { 0, XK_Meta_L, "Meta", I18N_NOOP("The Meta key has been locked and is now active for all of the following keypresses."), I18N_NOOP("The Meta key is now active."), I18N_NOOP("The Meta key is now inactive.") }, { 0, XK_Super_L, "Super", I18N_NOOP("The Super key has been locked and is now active for all of the following keypresses."), I18N_NOOP("The Super key is now active."), I18N_NOOP("The Super key is now inactive.") }, { 0, XK_Hyper_L, "Hyper", I18N_NOOP("The Hyper key has been locked and is now active for all of the following keypresses."), I18N_NOOP("The Hyper key is now active."), I18N_NOOP("The Hyper key is now inactive.") }, { 0, 0, "Alt Graph", I18N_NOOP("The Alt Graph key has been locked and is now active for all of the following keypresses."), I18N_NOOP("The Alt Graph key is now active."), I18N_NOOP("The Alt Graph key is now inactive.") }, { 0, XK_Num_Lock, "Num Lock", I18N_NOOP("The Num Lock key has been activated."), "", I18N_NOOP("The Num Lock key is now inactive.") }, { LockMask, 0, "Caps Lock", I18N_NOOP("The Caps Lock key has been activated."), "", I18N_NOOP("The Caps Lock key is now inactive.") }, { 0, XK_Scroll_Lock, "Scroll Lock", I18N_NOOP("The Scroll Lock key has been activated."), "", I18N_NOOP("The Scroll Lock key is now inactive.") }, { 0, 0, "", "", "", "" } }; /********************************************************************/ KAccessApp::KAccessApp() : overlay(nullptr), _player(nullptr), toggleScreenReaderAction(new QAction(this)) { m_error = false; _activeWindow = KWindowSystem::activeWindow(); connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &KAccessApp::activeWindowChanged); features = 0; requestedFeatures = 0; dialog = nullptr; if (!QX11Info::isPlatformX11()) { m_error = true; return; } initMasks(); XkbStateRec state_return; XkbGetState(QX11Info::display(), XkbUseCoreKbd, &state_return); unsigned char latched = XkbStateMods(&state_return); unsigned char locked = XkbModLocks(&state_return); state = ((int)locked) << 8 | latched; auto service = new KDBusService(KDBusService::Unique, this); connect(service, &KDBusService::activateRequested, this, &KAccessApp::newInstance); QTimer::singleShot(0, this, &KAccessApp::readSettings); } void KAccessApp::newInstance() { KSharedConfig::openConfig()->reparseConfiguration(); readSettings(); } void KAccessApp::readSettings() { KSharedConfig::Ptr _config = KSharedConfig::openConfig(); KConfigGroup cg(_config, "Bell"); // bell --------------------------------------------------------------- _systemBell = cg.readEntry("SystemBell", true); _artsBell = cg.readEntry("ArtsBell", false); _currentPlayerSource = cg.readPathEntry("ArtsBellFile", QString()); _visibleBell = cg.readEntry("VisibleBell", false); _visibleBellInvert = cg.readEntry("VisibleBellInvert", false); _visibleBellColor = cg.readEntry("VisibleBellColor", QColor(Qt::red)); _visibleBellPause = cg.readEntry("VisibleBellPause", 500); // select bell events if we need them int state = (_artsBell || _visibleBell) ? XkbBellNotifyMask : 0; XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd, XkbBellNotifyMask, state); // deactivate system bell if not needed if (!_systemBell) XkbChangeEnabledControls(QX11Info::display(), XkbUseCoreKbd, XkbAudibleBellMask, 0); else XkbChangeEnabledControls(QX11Info::display(), XkbUseCoreKbd, XkbAudibleBellMask, XkbAudibleBellMask); // keyboard ------------------------------------------------------------- KConfigGroup keyboardGroup(_config, "Keyboard"); // get keyboard state XkbDescPtr xkb = XkbGetMap(QX11Info::display(), 0, XkbUseCoreKbd); if (!xkb) return; if (XkbGetControls(QX11Info::display(), XkbAllControlsMask, xkb) != Success) return; // sticky keys if (keyboardGroup.readEntry("StickyKeys", false)) { if (keyboardGroup.readEntry("StickyKeysLatch", true)) xkb->ctrls->ax_options |= XkbAX_LatchToLockMask; else xkb->ctrls->ax_options &= ~XkbAX_LatchToLockMask; if (keyboardGroup.readEntry("StickyKeysAutoOff", false)) xkb->ctrls->ax_options |= XkbAX_TwoKeysMask; else xkb->ctrls->ax_options &= ~XkbAX_TwoKeysMask; if (keyboardGroup.readEntry("StickyKeysBeep", false)) xkb->ctrls->ax_options |= XkbAX_StickyKeysFBMask; else xkb->ctrls->ax_options &= ~XkbAX_StickyKeysFBMask; xkb->ctrls->enabled_ctrls |= XkbStickyKeysMask; } else xkb->ctrls->enabled_ctrls &= ~XkbStickyKeysMask; // toggle keys if (keyboardGroup.readEntry("ToggleKeysBeep", false)) xkb->ctrls->ax_options |= XkbAX_IndicatorFBMask; else xkb->ctrls->ax_options &= ~XkbAX_IndicatorFBMask; // slow keys if (keyboardGroup.readEntry("SlowKeys", false)) { if (keyboardGroup.readEntry("SlowKeysPressBeep", false)) xkb->ctrls->ax_options |= XkbAX_SKPressFBMask; else xkb->ctrls->ax_options &= ~XkbAX_SKPressFBMask; if (keyboardGroup.readEntry("SlowKeysAcceptBeep", false)) xkb->ctrls->ax_options |= XkbAX_SKAcceptFBMask; else xkb->ctrls->ax_options &= ~XkbAX_SKAcceptFBMask; if (keyboardGroup.readEntry("SlowKeysRejectBeep", false)) xkb->ctrls->ax_options |= XkbAX_SKRejectFBMask; else xkb->ctrls->ax_options &= ~XkbAX_SKRejectFBMask; xkb->ctrls->enabled_ctrls |= XkbSlowKeysMask; } else xkb->ctrls->enabled_ctrls &= ~XkbSlowKeysMask; xkb->ctrls->slow_keys_delay = keyboardGroup.readEntry("SlowKeysDelay", 500); // bounce keys if (keyboardGroup.readEntry("BounceKeys", false)) { if (keyboardGroup.readEntry("BounceKeysRejectBeep", false)) xkb->ctrls->ax_options |= XkbAX_BKRejectFBMask; else xkb->ctrls->ax_options &= ~XkbAX_BKRejectFBMask; xkb->ctrls->enabled_ctrls |= XkbBounceKeysMask; } else xkb->ctrls->enabled_ctrls &= ~XkbBounceKeysMask; xkb->ctrls->debounce_delay = keyboardGroup.readEntry("BounceKeysDelay", 500); // gestures for enabling the other features _gestures = keyboardGroup.readEntry("Gestures", false); if (_gestures) xkb->ctrls->enabled_ctrls |= XkbAccessXKeysMask; else xkb->ctrls->enabled_ctrls &= ~XkbAccessXKeysMask; // timeout if (keyboardGroup.readEntry("AccessXTimeout", false)) { xkb->ctrls->ax_timeout = keyboardGroup.readEntry("AccessXTimeoutDelay", 30) * 60; xkb->ctrls->axt_opts_mask = 0; xkb->ctrls->axt_opts_values = 0; xkb->ctrls->axt_ctrls_mask = XkbStickyKeysMask | XkbSlowKeysMask; xkb->ctrls->axt_ctrls_values = 0; xkb->ctrls->enabled_ctrls |= XkbAccessXTimeoutMask; } else xkb->ctrls->enabled_ctrls &= ~XkbAccessXTimeoutMask; // gestures for enabling the other features if (keyboardGroup.readEntry("AccessXBeep", true)) xkb->ctrls->ax_options |= XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask; else xkb->ctrls->ax_options &= ~(XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask); _gestureConfirmation = keyboardGroup.readEntry("GestureConfirmation", false); _kNotifyModifiers = keyboardGroup.readEntry("kNotifyModifiers", false); _kNotifyAccessX = keyboardGroup.readEntry("kNotifyAccessX", false); // mouse-by-keyboard ---------------------------------------------- KConfigGroup mouseGroup(_config, "Mouse"); if (mouseGroup.readEntry("MouseKeys", false)) { xkb->ctrls->mk_delay = mouseGroup.readEntry("MKDelay", 160); // Default for initial velocity: 200 pixels/sec int interval = mouseGroup.readEntry("MKInterval", 5); xkb->ctrls->mk_interval = interval; // Default time to reach maximum speed: 5000 msec xkb->ctrls->mk_time_to_max = mouseGroup.readEntry("MKTimeToMax", (5000 + interval / 2) / interval); // Default maximum speed: 1000 pixels/sec // (The old default maximum speed from KDE <= 3.4 // (100000 pixels/sec) was way too fast) xkb->ctrls->mk_max_speed = mouseGroup.readEntry("MKMaxSpeed", interval); xkb->ctrls->mk_curve = mouseGroup.readEntry("MKCurve", 0); xkb->ctrls->mk_dflt_btn = mouseGroup.readEntry("MKDefaultButton", 0); xkb->ctrls->enabled_ctrls |= XkbMouseKeysMask; } else xkb->ctrls->enabled_ctrls &= ~XkbMouseKeysMask; features = xkb->ctrls->enabled_ctrls & (XkbSlowKeysMask | XkbBounceKeysMask | XkbStickyKeysMask | XkbMouseKeysMask); if (dialog == nullptr) requestedFeatures = features; // set state XkbSetControls(QX11Info::display(), XkbControlsEnabledMask | XkbMouseKeysAccelMask | XkbStickyKeysMask | XkbSlowKeysMask | XkbBounceKeysMask | XkbAccessXKeysMask | XkbAccessXTimeoutMask, xkb); // select AccessX events XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd, XkbAllEventsMask, XkbAllEventsMask); if (!_artsBell && !_visibleBell && !(_gestures && _gestureConfirmation) && !_kNotifyModifiers && !_kNotifyAccessX) { uint ctrls = XkbStickyKeysMask | XkbSlowKeysMask | XkbBounceKeysMask | XkbMouseKeysMask | XkbAudibleBellMask | XkbControlsNotifyMask; uint values = xkb->ctrls->enabled_ctrls & ctrls; XkbSetAutoResetControls(QX11Info::display(), ctrls, &ctrls, &values); } else { // reset them after program exit uint ctrls = XkbStickyKeysMask | XkbSlowKeysMask | XkbBounceKeysMask | XkbMouseKeysMask | XkbAudibleBellMask | XkbControlsNotifyMask; uint values = XkbAudibleBellMask; XkbSetAutoResetControls(QX11Info::display(), ctrls, &ctrls, &values); } delete overlay; overlay = nullptr; KConfigGroup screenReaderGroup(_config, "ScreenReader"); setScreenReaderEnabled(screenReaderGroup.readEntry("Enabled", false)); QString shortcut = screenReaderGroup.readEntry("Shortcut", QStringLiteral("Meta+Alt+S")); toggleScreenReaderAction->setText(i18n("Toggle Screen Reader On and Off")); toggleScreenReaderAction->setObjectName(QStringLiteral("Toggle Screen Reader On and Off")); toggleScreenReaderAction->setProperty("componentDisplayName", i18nc("Name for kaccess shortcuts category", "Accessibility")); KGlobalAccel::self()->setGlobalShortcut(toggleScreenReaderAction, QKeySequence(shortcut)); connect(toggleScreenReaderAction, &QAction::triggered, this, &KAccessApp::toggleScreenReader); } void KAccessApp::toggleScreenReader() { KSharedConfig::Ptr _config = KSharedConfig::openConfig(); KConfigGroup screenReaderGroup(_config, "ScreenReader"); bool enabled = !screenReaderGroup.readEntry("Enabled", false); screenReaderGroup.writeEntry("Enabled", enabled); setScreenReaderEnabled(enabled); } void KAccessApp::setScreenReaderEnabled(bool enabled) { if (enabled) { QStringList args = { QStringLiteral("set"), QStringLiteral("org.gnome.desktop.a11y.applications"), QStringLiteral("screen-reader-enabled"), QStringLiteral("true")}; int ret = QProcess::execute(QStringLiteral("gsettings"), args); if (ret == 0) { qint64 pid = 0; QProcess::startDetached(QStringLiteral("orca"), {QStringLiteral("--replace")}, QString(), &pid); qCDebug(logKAccess) << "Launching Orca, pid:" << pid; } } else { QProcess::startDetached(QStringLiteral("gsettings"), { QStringLiteral("set"), QStringLiteral("org.gnome.desktop.a11y.applications"), QStringLiteral("screen-reader-enabled"), QStringLiteral("false")}); } } static int maskToBit(int mask) { for (int i = 0; i < 8; i++) if (mask & (1 << i)) return i; return -1; } void KAccessApp::initMasks() { for (int i = 0; i < 8; i++) keys [i] = -1; state = 0; for (int i = 0; strcmp(modifierKeys[i].name, "") != 0; i++) { int mask = modifierKeys[i].mask; if (mask == 0) { if (modifierKeys[i].keysym != 0) { mask = XkbKeysymToModifiers(QX11Info::display(), modifierKeys[i].keysym); } else { if (!strcmp(modifierKeys[i].name, "Win")) { mask = KKeyServer::modXMeta(); } else { mask = XkbKeysymToModifiers(QX11Info::display(), XK_Mode_switch) | XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Shift) | XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Latch) | XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Lock); } } } int bit = maskToBit(mask); if (bit != -1 && keys[bit] == -1) keys[bit] = i; } } struct xkb_any_ { uint8_t response_type; uint8_t xkbType; uint16_t sequence; xcb_timestamp_t time; uint8_t deviceID; }; bool KAccessApp::nativeEventFilter(const QByteArray& eventType, void* message, long int* result) { if (eventType == "xcb_generic_event_t") { xcb_generic_event_t* event = static_cast(message); if ((event->response_type & ~0x80) == XkbEventCode + xkb_opcode) { xkb_any_ *ev = reinterpret_cast(event); switch (ev->xkbType) { case XCB_XKB_EVENT_TYPE_STATE_NOTIFY: xkbStateNotify(); break; case XCB_XKB_EVENT_TYPE_BELL_NOTIFY: xkbBellNotify(reinterpret_cast(event)); break; case XCB_XKB_EVENT_TYPE_CONTROLS_NOTIFY: xkbControlsNotify(reinterpret_cast(event)); break; } return true; } } return false; } void VisualBell::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); QTimer::singleShot(_pause, this, &QWidget::hide); } void KAccessApp::activeWindowChanged(WId wid) { _activeWindow = wid; } void KAccessApp::xkbStateNotify() { XkbStateRec state_return; XkbGetState(QX11Info::display(), XkbUseCoreKbd, &state_return); unsigned char latched = XkbStateMods(&state_return); unsigned char locked = XkbModLocks(&state_return); int mods = ((int)locked) << 8 | latched; if (state != mods) { if (_kNotifyModifiers) for (int i = 0; i < 8; i++) { if (keys[i] != -1) { if (!strcmp(modifierKeys[keys[i]].latchedText, "") && ((((mods >> i) & 0x101) != 0) != (((state >> i) & 0x101) != 0))) { if ((mods >> i) & 1) { KNotification::event(QStringLiteral("lockkey-locked"), i18n(modifierKeys[keys[i]].lockedText)); } else { KNotification::event(QStringLiteral("lockkey-unlocked"), i18n(modifierKeys[keys[i]].unlatchedText)); } } else if (strcmp(modifierKeys[keys[i]].latchedText, "") && (((mods >> i) & 0x101) != ((state >> i) & 0x101))) { if ((mods >> i) & 0x100) { KNotification::event(QStringLiteral("modifierkey-locked"), i18n(modifierKeys[keys[i]].lockedText)); } else if ((mods >> i) & 1) { KNotification::event(QStringLiteral("modifierkey-latched"), i18n(modifierKeys[keys[i]].latchedText)); } else { KNotification::event(QStringLiteral("modifierkey-unlatched"), i18n(modifierKeys[keys[i]].unlatchedText)); } } } } state = mods; } } void KAccessApp::xkbBellNotify(xcb_xkb_bell_notify_event_t *event) { // bail out if we should not really ring if (event->eventOnly) return; // flash the visible bell if (_visibleBell) { // create overlay widget if (!overlay) overlay = new VisualBell(_visibleBellPause); WId id = _activeWindow; NETRect frame, window; NETWinInfo net(QX11Info::connection(), id, qApp->desktop()->winId(), NET::Properties(), NET::Properties2()); net.kdeGeometry(frame, window); overlay->setGeometry(window.pos.x, window.pos.y, window.size.width, window.size.height); if (_visibleBellInvert) { QPixmap screen = QPixmap::grabWindow(id, 0, 0, window.size.width, window.size.height); #ifdef __GNUC__ #warning is this the best way to invert a pixmap? #endif // QPixmap invert(window.size.width, window.size.height); QImage i = screen.toImage(); i.invertPixels(); QPalette pal = overlay->palette(); pal.setBrush(overlay->backgroundRole(), QBrush(QPixmap::fromImage(i))); overlay->setPalette(pal); /* QPainter p(&invert); p.setRasterOp(QPainter::NotCopyROP); p.drawPixmap(0, 0, screen); overlay->setBackgroundPixmap(invert); */ } else { QPalette pal = overlay->palette(); pal.setColor(overlay->backgroundRole(), _visibleBellColor); overlay->setPalette(pal); } // flash the overlay widget overlay->raise(); overlay->show(); qApp->flush(); } // ask Phonon to ring a nice bell if (_artsBell) { if (!_player) { // as creating the player is expensive, delay the creation _player = Phonon::createPlayer(Phonon::AccessibilityCategory); _player->setParent(this); _player->setCurrentSource(_currentPlayerSource); } _player->play(); } } QString mouseKeysShortcut(Display *display) { // Calculate the keycode KeySym sym = XK_MouseKeys_Enable; KeyCode code = XKeysymToKeycode(display, sym); if (code == 0) { sym = XK_Pointer_EnableKeys; code = XKeysymToKeycode(display, sym); if (code == 0) return QString(); // No shortcut available? } // Calculate the modifiers by searching the keysym in the X keyboard mapping XkbDescPtr xkbdesc = XkbGetMap(display, XkbKeyTypesMask | XkbKeySymsMask, XkbUseCoreKbd); if (!xkbdesc) return QString(); // Failed to obtain the mapping from server bool found = false; unsigned char modifiers = 0; int groups = XkbKeyNumGroups(xkbdesc, code); for (int grp = 0; grp < groups && !found; grp++) { int levels = XkbKeyGroupWidth(xkbdesc, code, grp); for (int level = 0; level < levels && !found; level++) { if (sym == XkbKeySymEntry(xkbdesc, code, level, grp)) { // keysym found => determine modifiers int typeIdx = xkbdesc->map->key_sym_map[code].kt_index[grp]; XkbKeyTypePtr type = &(xkbdesc->map->types[typeIdx]); for (int i = 0; i < type->map_count && !found; i++) { if (type->map[i].active && (type->map[i].level == level)) { modifiers = type->map[i].mods.mask; found = true; } } } } } XkbFreeClientMap(xkbdesc, 0, true); if (!found) return QString(); // Somehow the keycode -> keysym mapping is flawed XEvent ev; ev.type = KeyPress; ev.xkey.display = display; ev.xkey.keycode = code; ev.xkey.state = 0; int key; KKeyServer::xEventToQt(&ev, &key); QString keyname = QKeySequence(key).toString(); unsigned int AltMask = KKeyServer::modXAlt(); unsigned int WinMask = KKeyServer::modXMeta(); unsigned int NumMask = KKeyServer::modXNumLock(); unsigned int ScrollMask = KKeyServer::modXScrollLock(); unsigned int MetaMask = XkbKeysymToModifiers(display, XK_Meta_L); unsigned int SuperMask = XkbKeysymToModifiers(display, XK_Super_L); unsigned int HyperMask = XkbKeysymToModifiers(display, XK_Hyper_L); unsigned int AltGrMask = XkbKeysymToModifiers(display, XK_Mode_switch) | XkbKeysymToModifiers(display, XK_ISO_Level3_Shift) | XkbKeysymToModifiers(display, XK_ISO_Level3_Latch) | XkbKeysymToModifiers(display, XK_ISO_Level3_Lock); unsigned int mods = ShiftMask | ControlMask | AltMask | WinMask | LockMask | NumMask | ScrollMask; AltGrMask &= ~mods; MetaMask &= ~(mods | AltGrMask); SuperMask &= ~(mods | AltGrMask | MetaMask); HyperMask &= ~(mods | AltGrMask | MetaMask | SuperMask); if ((modifiers & AltGrMask) != 0) keyname = i18n("AltGraph") + QLatin1Char('+') + keyname; if ((modifiers & HyperMask) != 0) keyname = i18n("Hyper") + QLatin1Char('+') + keyname; if ((modifiers & SuperMask) != 0) keyname = i18n("Super") + QLatin1Char('+') + keyname; if ((modifiers & WinMask) != 0) keyname = i18n("Meta") + QLatin1Char('+') + keyname; if ((modifiers & WinMask) != 0) keyname = QKeySequence(Qt::META).toString() + QLatin1Char('+') + keyname; if ((modifiers & AltMask) != 0) keyname = QKeySequence(Qt::ALT).toString() + QLatin1Char('+') + keyname; if ((modifiers & ControlMask) != 0) keyname = QKeySequence(Qt::CTRL).toString() + QLatin1Char('+') + keyname; if ((modifiers & ShiftMask) != 0) keyname = QKeySequence(Qt::SHIFT).toString() + QLatin1Char('+') + keyname; return keyname; } void KAccessApp::createDialogContents() { if (dialog == nullptr) { dialog = new QDialog(nullptr); dialog->setWindowTitle(i18n("Warning")); dialog->setObjectName(QStringLiteral("AccessXWarning")); dialog->setModal(true); QWidget *topcontents = new QWidget(dialog); topcontents->setLayout(new QVBoxLayout(topcontents)); QWidget *contents = new QWidget(topcontents); QHBoxLayout * lay = new QHBoxLayout(contents); QLabel *label1 = new QLabel(contents); QIcon icon = QIcon::fromTheme(QStringLiteral("dialog-warning")); if (icon.isNull()) icon = QMessageBox::standardIcon(QMessageBox::Warning); label1->setPixmap(icon.pixmap(64, 64)); lay->addWidget(label1, 0, Qt::AlignCenter); QVBoxLayout * vlay = new QVBoxLayout(); lay->addItem(vlay); featuresLabel = new QLabel(QString(), contents); featuresLabel->setAlignment(Qt::AlignVCenter); featuresLabel->setWordWrap(true); vlay->addWidget(featuresLabel); vlay->addStretch(); QHBoxLayout * hlay = new QHBoxLayout(); vlay->addItem(hlay); QLabel *showModeLabel = new QLabel(i18n("&When a gesture was used:"), contents); hlay->addWidget(showModeLabel); showModeCombobox = new KComboBox(contents); hlay->addWidget(showModeCombobox); showModeLabel->setBuddy(showModeCombobox); showModeCombobox->insertItem(0, i18n("Change Settings Without Asking")); showModeCombobox->insertItem(1, i18n("Show This Confirmation Dialog")); showModeCombobox->insertItem(2, i18n("Deactivate All AccessX Features & Gestures")); showModeCombobox->setCurrentIndex(1); auto buttons = new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::No, dialog); lay->addWidget(buttons); connect(buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject); connect(dialog, &QDialog::accepted, this, &KAccessApp::yesClicked); connect(dialog, &QDialog::rejected, this, &KAccessApp::noClicked); } } void KAccessApp::xkbControlsNotify(xcb_xkb_controls_notify_event_t *event) { unsigned int newFeatures = event->enabledControls & ( XCB_XKB_BOOL_CTRL_SLOW_KEYS | XCB_XKB_BOOL_CTRL_BOUNCE_KEYS | XCB_XKB_BOOL_CTRL_STICKY_KEYS | XCB_XKB_BOOL_CTRL_MOUSE_KEYS); if (newFeatures != features) { unsigned int enabled = newFeatures & ~features; unsigned int disabled = features & ~newFeatures; if (!_gestureConfirmation) { requestedFeatures = enabled | (requestedFeatures & ~disabled); notifyChanges(); features = newFeatures; } else { // set the AccessX features back to what they were. We will // apply the changes later if the user allows us to do that. readSettings(); requestedFeatures = enabled | (requestedFeatures & ~disabled); enabled = requestedFeatures & ~features; disabled = features & ~requestedFeatures; QStringList enabledFeatures; QStringList disabledFeatures; if (enabled & XCB_XKB_BOOL_CTRL_SLOW_KEYS) enabledFeatures << i18n("Slow keys"); else if (disabled & XCB_XKB_BOOL_CTRL_SLOW_KEYS) disabledFeatures << i18n("Slow keys"); if (enabled & XCB_XKB_BOOL_CTRL_BOUNCE_KEYS) enabledFeatures << i18n("Bounce keys"); else if (disabled & XCB_XKB_BOOL_CTRL_BOUNCE_KEYS) disabledFeatures << i18n("Bounce keys"); if (enabled & XCB_XKB_BOOL_CTRL_STICKY_KEYS) enabledFeatures << i18n("Sticky keys"); else if (disabled & XCB_XKB_BOOL_CTRL_STICKY_KEYS) disabledFeatures << i18n("Sticky keys"); if (enabled & XCB_XKB_BOOL_CTRL_MOUSE_KEYS) enabledFeatures << i18n("Mouse keys"); else if (disabled & XCB_XKB_BOOL_CTRL_MOUSE_KEYS) disabledFeatures << i18n("Mouse keys"); QString question; switch (enabledFeatures.count()) { case 0: switch (disabledFeatures.count()) { case 1: question = i18n("Do you really want to deactivate \"%1\"?", disabledFeatures[0]); break; case 2: question = i18n("Do you really want to deactivate \"%1\" and \"%2\"?", disabledFeatures[0], disabledFeatures[1]); break; case 3: question = i18n("Do you really want to deactivate \"%1\", \"%2\" and \"%3\"?", disabledFeatures[0], disabledFeatures[1], disabledFeatures[2]); break; case 4: question = i18n("Do you really want to deactivate \"%1\", \"%2\", \"%3\" and \"%4\"?", disabledFeatures[0], disabledFeatures[1], disabledFeatures[2], disabledFeatures[3]); break; } break; case 1: switch (disabledFeatures.count()) { case 0: question = i18n("Do you really want to activate \"%1\"?", enabledFeatures[0]); break; case 1: question = i18n("Do you really want to activate \"%1\" and to deactivate \"%2\"?", enabledFeatures[0], disabledFeatures[0]); break; case 2: question = i18n("Do you really want to activate \"%1\" and to deactivate \"%2\" and \"%3\"?", enabledFeatures[0], disabledFeatures[0], disabledFeatures[1]); break; case 3: question = i18n("Do you really want to activate \"%1\" and to deactivate \"%2\", \"%3\" and \"%4\"?", enabledFeatures[0], disabledFeatures[0], disabledFeatures[1], disabledFeatures[2]); break; } break; case 2: switch (disabledFeatures.count()) { case 0: question = i18n("Do you really want to activate \"%1\" and \"%2\"?", enabledFeatures[0], enabledFeatures[1]); break; case 1: question = i18n("Do you really want to activate \"%1\" and \"%2\" and to deactivate \"%3\"?", enabledFeatures[0], enabledFeatures[1], disabledFeatures[0]); break; case 2: question = i18n("Do you really want to activate \"%1\", and \"%2\" and to deactivate \"%3\" and \"%4\"?", enabledFeatures[0], enabledFeatures[1], enabledFeatures[0], disabledFeatures[1]); break; } break; case 3: switch (disabledFeatures.count()) { case 0: question = i18n("Do you really want to activate \"%1\", \"%2\" and \"%3\"?", enabledFeatures[0], enabledFeatures[1], enabledFeatures[2]); break; case 1: question = i18n("Do you really want to activate \"%1\", \"%2\" and \"%3\" and to deactivate \"%4\"?", enabledFeatures[0], enabledFeatures[1], enabledFeatures[2], disabledFeatures[0]); break; } break; case 4: question = i18n("Do you really want to activate \"%1\", \"%2\", \"%3\" and \"%4\"?", enabledFeatures[0], enabledFeatures[1], enabledFeatures[2], enabledFeatures[3]); break; } QString explanation; if (enabledFeatures.count() + disabledFeatures.count() == 1) { explanation = i18n("An application has requested to change this setting."); if (_gestures) { if ((enabled | disabled) == XCB_XKB_BOOL_CTRL_SLOW_KEYS) explanation = i18n("You held down the Shift key for 8 seconds or an application has requested to change this setting."); else if ((enabled | disabled) == XCB_XKB_BOOL_CTRL_STICKY_KEYS) explanation = i18n("You pressed the Shift key 5 consecutive times or an application has requested to change this setting."); else if ((enabled | disabled) == XCB_XKB_BOOL_CTRL_MOUSE_KEYS) { QString shortcut = mouseKeysShortcut(QX11Info::display()); if (!shortcut.isEmpty() && !shortcut.isNull()) explanation = i18n("You pressed %1 or an application has requested to change this setting.", shortcut); } } } else { if (_gestures) explanation = i18n("An application has requested to change these settings, or you used a combination of several keyboard gestures."); else explanation = i18n("An application has requested to change these settings."); } createDialogContents(); featuresLabel->setText(question + QStringLiteral("\n\n") + explanation + QStringLiteral(" ") + i18n("These AccessX settings are needed for some users with motion impairments and can be configured in the KDE System Settings. You can also turn them on and off with standardized keyboard gestures.\n\nIf you do not need them, you can select \"Deactivate all AccessX features and gestures\".")); KWindowSystem::setState(dialog->winId(), NET::KeepAbove); KUserTimestamp::updateUserTimestamp(0); dialog->show(); } } } void KAccessApp::notifyChanges() { if (!_kNotifyAccessX) return; unsigned int enabled = requestedFeatures & ~features; unsigned int disabled = features & ~requestedFeatures; if (enabled & XCB_XKB_BOOL_CTRL_SLOW_KEYS) KNotification::event(QStringLiteral("slowkeys"), i18n("Slow keys has been enabled. From now on, you need to press each key for a certain length of time before it gets accepted.")); else if (disabled & XCB_XKB_BOOL_CTRL_SLOW_KEYS) KNotification::event(QStringLiteral("slowkeys"), i18n("Slow keys has been disabled.")); if (enabled & XCB_XKB_BOOL_CTRL_BOUNCE_KEYS) KNotification::event(QStringLiteral("bouncekeys"), i18n("Bounce keys has been enabled. From now on, each key will be blocked for a certain length of time after it was used.")); else if (disabled & XCB_XKB_BOOL_CTRL_BOUNCE_KEYS) KNotification::event(QStringLiteral("bouncekeys"), i18n("Bounce keys has been disabled.")); if (enabled & XCB_XKB_BOOL_CTRL_STICKY_KEYS) KNotification::event(QStringLiteral("stickykeys"), i18n("Sticky keys has been enabled. From now on, modifier keys will stay latched after you have released them.")); else if (disabled & XCB_XKB_BOOL_CTRL_STICKY_KEYS) KNotification::event(QStringLiteral("stickykeys"), i18n("Sticky keys has been disabled.")); if (enabled & XCB_XKB_BOOL_CTRL_MOUSE_KEYS) KNotification::event(QStringLiteral("mousekeys"), i18n("Mouse keys has been enabled. From now on, you can use the number pad of your keyboard in order to control the mouse.")); else if (disabled & XCB_XKB_BOOL_CTRL_MOUSE_KEYS) KNotification::event(QStringLiteral("mousekeys"), i18n("Mouse keys has been disabled.")); } void KAccessApp::applyChanges() { notifyChanges(); unsigned int enabled = requestedFeatures & ~features; unsigned int disabled = features & ~requestedFeatures; KConfigGroup config(KSharedConfig::openConfig(), "Keyboard"); if (enabled & XCB_XKB_BOOL_CTRL_SLOW_KEYS) config.writeEntry("SlowKeys", true); else if (disabled & XCB_XKB_BOOL_CTRL_SLOW_KEYS) config.writeEntry("SlowKeys", false); if (enabled & XCB_XKB_BOOL_CTRL_BOUNCE_KEYS) config.writeEntry("BounceKeys", true); else if (disabled & XCB_XKB_BOOL_CTRL_BOUNCE_KEYS) config.writeEntry("BounceKeys", false); if (enabled & XCB_XKB_BOOL_CTRL_STICKY_KEYS) config.writeEntry("StickyKeys", true); else if (disabled & XCB_XKB_BOOL_CTRL_STICKY_KEYS) config.writeEntry("StickyKeys", false); KConfigGroup mousegrp(KSharedConfig::openConfig(), "Mouse"); if (enabled & XCB_XKB_BOOL_CTRL_MOUSE_KEYS) mousegrp.writeEntry("MouseKeys", true); else if (disabled & XCB_XKB_BOOL_CTRL_MOUSE_KEYS) mousegrp.writeEntry("MouseKeys", false); mousegrp.sync(); config.sync(); } void KAccessApp::yesClicked() { if (dialog) dialog->deleteLater(); dialog = nullptr; KConfigGroup config(KSharedConfig::openConfig(), "Keyboard"); switch (showModeCombobox->currentIndex()) { case 0: config.writeEntry("Gestures", true); config.writeEntry("GestureConfirmation", false); break; default: config.writeEntry("Gestures", true); config.writeEntry("GestureConfirmation", true); break; case 2: requestedFeatures = 0; config.writeEntry("Gestures", false); config.writeEntry("GestureConfirmation", true); } config.sync(); if (features != requestedFeatures) { notifyChanges(); applyChanges(); } readSettings(); } void KAccessApp::noClicked() { if (dialog) dialog->deleteLater(); dialog = nullptr; requestedFeatures = features; KConfigGroup config(KSharedConfig::openConfig(), "Keyboard"); switch (showModeCombobox->currentIndex()) { case 0: config.writeEntry("Gestures", true); config.writeEntry("GestureConfirmation", false); break; default: config.writeEntry("Gestures", true); config.writeEntry("GestureConfirmation", true); break; case 2: requestedFeatures = 0; config.writeEntry("Gestures", false); config.writeEntry("GestureConfirmation", true); } config.sync(); if (features != requestedFeatures) applyChanges(); readSettings(); } void KAccessApp::dialogClosed() { - if (dialog != 0) + if (dialog != nullptr) dialog->deleteLater(); - dialog = 0; + dialog = nullptr; requestedFeatures = features; } void KAccessApp::setXkbOpcode(int opcode) { xkb_opcode = opcode; } diff --git a/kaccess/kaccess.h b/kaccess/kaccess.h index d0b1738c5..099ebd55c 100644 --- a/kaccess/kaccess.h +++ b/kaccess/kaccess.h @@ -1,138 +1,138 @@ /* Copyright 2000 Matthias Hölzer-Klüpfel Copyright 2014 Frederik Gladhorn This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef __K_ACCESS_H__ #define __K_ACCESS_H__ #include #include #include #include #include #include #include #define explicit int_explicit // avoid compiler name clash in XKBlib.h #include #include #undef explicit #include class QLabel; class KDialog; class KComboBox; class KAccessApp : public QObject, public QAbstractNativeEventFilter { Q_OBJECT public: explicit KAccessApp(); void newInstance(); void setXkbOpcode(int opcode); bool nativeEventFilter(const QByteArray& eventType, void* message, long int* result) override; bool isFailed() const { return m_error; } protected: void readSettings(); void xkbStateNotify(); void xkbBellNotify(xcb_xkb_bell_notify_event_t *event); void xkbControlsNotify(xcb_xkb_controls_notify_event_t *event); private Q_SLOTS: void activeWindowChanged(WId wid); void notifyChanges(); void applyChanges(); void yesClicked(); void noClicked(); void dialogClosed(); void toggleScreenReader(); private: void createDialogContents(); void initMasks(); void setScreenReaderEnabled(bool enabled); int xkb_opcode; unsigned int features; unsigned int requestedFeatures; bool _systemBell, _artsBell, _visibleBell, _visibleBellInvert; QColor _visibleBellColor; int _visibleBellPause; bool _gestures, _gestureConfirmation; bool _kNotifyModifiers, _kNotifyAccessX; QWidget *overlay; Phonon::MediaObject *_player; QString _currentPlayerSource; WId _activeWindow; QDialog *dialog; QLabel *featuresLabel; KComboBox *showModeCombobox; int keys[8]; int state; QAction *toggleScreenReaderAction; bool m_error; }; class VisualBell : public QWidget { Q_OBJECT public: VisualBell(int pause) - : QWidget((QWidget*)0, Qt::X11BypassWindowManagerHint), _pause(pause) + : QWidget((QWidget*)nullptr, Qt::X11BypassWindowManagerHint), _pause(pause) {} protected: void paintEvent(QPaintEvent *) override; private: int _pause; }; #endif diff --git a/kcms/autostart/autostart.cpp b/kcms/autostart/autostart.cpp index 9fef0e20d..47b589c29 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"))); 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")); } AdvancedDialog *dlg = new AdvancedDialog( this,status ); if ( dlg->exec() ) { status = dlg->onlyInKde(); if ( lstEntry.contains( QStringLiteral("KDE") ) && !status ) { lstEntry.removeAll( QStringLiteral("KDE") ); grp.writeXdgListEntry( "OnlyShowIn", lstEntry ); } else if ( !lstEntry.contains( QStringLiteral("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() )!=0 ) ; + const bool hasItems = ( dynamic_cast( widget->listCMD->currentItem() )!=nullptr ) ; widget->btnRemove->setEnabled(hasItems); - const bool isDesktopItem = (dynamic_cast(widget->listCMD->currentItem() ) != 0) ; + 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/baloo/fileexcludefilters.cpp b/kcms/baloo/fileexcludefilters.cpp index 022eb4344..2ee0516b4 100644 --- a/kcms/baloo/fileexcludefilters.cpp +++ b/kcms/baloo/fileexcludefilters.cpp @@ -1,178 +1,178 @@ /* This file is part of the KDE Project Copyright (c) 2008-2010 Sebastian Trueg 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 "fileexcludefilters.h" namespace { const char* const s_defaultFileExcludeFilters[] = { // tmp files "*~", "*.part", // temporary build files "*.o", "*.la", "*.lo", "*.loT", "*.moc", "moc_*.cpp", "qrc_*.cpp", "ui_*.h", "cmake_install.cmake", "CMakeCache.txt", "CTestTestfile.cmake", "libtool", "config.status", "confdefs.h", "autom4te", "conftest", "confstat", "Makefile.am", // misc "*.csproj", "*.m4", "*.rej", "*.gmo", "*.pc", "*.omf", "*.aux", "*.tmp", "*.po", "*.vm*", "*.nvram", "*.rcore", "*.swap", "lzo", "litmain.sh", "*.orig", ".histfile.*", ".xsession-errors*", // Compiled files "*.class", // Java "*.pyc", // Python "*.elc", // Emacs Lisp // end of list - 0 + nullptr }; const int s_defaultFileExcludeFiltersVersion = 2; const char* const s_defaultFolderExcludeFilters[] = { "po", // VCS "CVS", ".svn", ".git", "_darcs", ".bzr", ".hg", // development "CMakeFiles", "CMakeTmp", "CMakeTmpQmake", ".moc", ".obj", ".pch", ".uic", //misc "core-dumps", "lost+found", // end of list - 0 + nullptr }; const int s_defaultFolderExcludeFiltersVersion = 1; const char* const s_sourceCodeMimeTypes[] = { "text/css", "text/x-c++src", "text/x-c++hdr", "text/x-csrc", "text/x-chdr", // c header files "text/x-python", "text/x-assembly", "text/x-java", "text/x-objsrc", "text/x-ruby", "text/x-scheme", "text/x-pascal", "text/x-yacc", "text/x-sed", "text/x-haskell", "text/asp", "application/x-awk", "application/x-cgi", "application/x-csh", "application/x-java", "application/x-javascript", "application/x-perl", "application/x-php", "application/x-python", "application/x-sh", "application/x-tex", // end of list - 0 + nullptr }; const int s_sourceCodeMimeTypesVersion = 1; } QStringList Baloo::defaultExcludeFilterList() { QStringList l; for (int i = 0; s_defaultFileExcludeFilters[i]; ++i) l << QLatin1String(s_defaultFileExcludeFilters[i]); for (int i = 0; s_defaultFolderExcludeFilters[i]; ++i) l << QLatin1String(s_defaultFolderExcludeFilters[i]); return l; } int Baloo::defaultExcludeFilterListVersion() { return qMax(s_defaultFileExcludeFiltersVersion, s_defaultFolderExcludeFiltersVersion); } QStringList Baloo::sourceCodeMimeTypes() { QStringList l; for (int i = 0; s_sourceCodeMimeTypes[i]; ++i) l << QLatin1String(s_sourceCodeMimeTypes[i]); return l; } QStringList Baloo::defaultExcludeMimetypes() { return sourceCodeMimeTypes(); } int Baloo::defaultExcludeMimetypesVersion() { // The +1 is the image, video and audio mimetypes return s_sourceCodeMimeTypesVersion + 1; } diff --git a/kcms/baloo/folderselectionwidget.cpp b/kcms/baloo/folderselectionwidget.cpp index e8a4c5ebd..441023818 100644 --- a/kcms/baloo/folderselectionwidget.cpp +++ b/kcms/baloo/folderselectionwidget.cpp @@ -1,355 +1,355 @@ /* * This file is part of the KDE Baloo Project * Copyright (C) 2014 Vishesh Handa * * 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) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "folderselectionwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include FolderSelectionWidget::FolderSelectionWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_listWidget = new QListWidget(this); m_listWidget->setAlternatingRowColors(true); m_messageWidget = new KMessageWidget(this); m_messageWidget->hide(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(m_messageWidget); layout->addWidget(m_listWidget); QHBoxLayout* hLayout = new QHBoxLayout; QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); hLayout->addItem(spacer); m_addButton = new QPushButton(this); m_addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); connect(m_addButton, &QPushButton::clicked, this, &FolderSelectionWidget::slotAddButtonClicked); m_removeButton = new QPushButton(this); m_removeButton->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); m_removeButton->setEnabled(false); connect(m_removeButton, &QPushButton::clicked, this, &FolderSelectionWidget::slotRemoveButtonClicked); connect(m_listWidget, &QListWidget::currentItemChanged, this, &FolderSelectionWidget::slotCurrentItemChanged); hLayout->addWidget(m_addButton); hLayout->addWidget(m_removeButton); layout->addItem(hLayout); } namespace { QStringList addTrailingSlashes(const QStringList& input) { QStringList output; Q_FOREACH (QString str, input) { if (!str.endsWith(QDir::separator())) str.append(QDir::separator()); output << str; } return output; } QString makeHomePretty(const QString& url) { if (url.startsWith(QDir::homePath())) return QString(url).replace(0, QDir::homePath().length(), QStringLiteral("~")); return url; } } void FolderSelectionWidget::setDirectoryList(QStringList includeDirs, QStringList exclude) { m_listWidget->clear(); m_mountPoints.clear(); QList devices = Solid::Device::listFromType(Solid::DeviceInterface::StorageAccess); Q_FOREACH (const Solid::Device& dev, devices) { const Solid::StorageAccess* sa = dev.as(); if (!sa->isAccessible()) continue; QString mountPath = sa->filePath(); if (!shouldShowMountPoint(mountPath)) continue; m_mountPoints << mountPath; } m_mountPoints << QDir::homePath(); m_mountPoints = addTrailingSlashes(m_mountPoints); includeDirs = addTrailingSlashes(includeDirs); exclude = addTrailingSlashes(exclude); QStringList excludeList = exclude; Q_FOREACH (const QString& mountPath, m_mountPoints) { if (includeDirs.contains(mountPath)) continue; if (exclude.contains(mountPath)) continue; if (!excludeList.contains(mountPath)) { excludeList << mountPath; } } Q_FOREACH (QString url, excludeList) { QListWidgetItem* item = new QListWidgetItem(m_listWidget); QString display = folderDisplayName(url); item->setData(Qt::DisplayRole, display); item->setData(Qt::WhatsThisRole, url); item->setData(UrlRole, url); item->setData(Qt::DecorationRole, QIcon::fromTheme(iconName(url))); item->setToolTip(makeHomePretty(url)); m_listWidget->addItem(item); } if (m_listWidget->count() == 0) { m_removeButton->setEnabled(false); } } QStringList FolderSelectionWidget::includeFolders() const { QStringList folders; Q_FOREACH (const QString& mountPath, m_mountPoints) { bool inExclude = false; for (int i=0; icount(); ++i) { QListWidgetItem* item = m_listWidget->item(i); QString url = item->data(UrlRole).toString(); if (mountPath == url) { inExclude = true; break; } } if (!inExclude && !folders.contains(mountPath)) { folders << mountPath; } } return folders; } QStringList FolderSelectionWidget::excludeFolders() const { QStringList folders; for (int i=0; icount(); ++i) { QListWidgetItem* item = m_listWidget->item(i); QString url = item->data(UrlRole).toString(); if (!folders.contains(url)) { folders << url; } } return folders; } QString FolderSelectionWidget::fetchMountPoint(const QString& url) const { QString mountPoint; Q_FOREACH (const QString& mount, m_mountPoints) { if (url.startsWith(mount) && mount.size() > mountPoint.size()) mountPoint = mount; } return mountPoint; } void FolderSelectionWidget::slotAddButtonClicked() { QString url = QFileDialog::getExistingDirectory(this, i18n("Select the folder which should be excluded")); if (url.isEmpty()) { return; } if (!url.endsWith(QDir::separator())) url.append(QDir::separator()); // We don't care about the root dir if (url == QLatin1String("/")) { showMessage(i18n("Not allowed to exclude root folder, please disable File Search if you do not want it")); return; } // Remove any existing folder with that name // Remove any folder which is a sub-folder QVector deleteList; for (int i=0; icount(); ++i) { QListWidgetItem* item = m_listWidget->item(i); QString existingUrl = item->data(UrlRole).toString(); if (existingUrl == url) { QString name = QUrl::fromLocalFile(url).fileName(); showMessage(i18n("Folder %1 is already excluded", name)); deleteList << item; continue; } QString existingMountPoint = fetchMountPoint(existingUrl); QString mountPoint = fetchMountPoint(url); if (existingMountPoint == mountPoint) { // existingUrl is not required since it comes under url if (existingUrl.startsWith(url)) { deleteList << item; } else if (url.startsWith(existingUrl)) { // No point adding ourselves since our parents exists // we just move the parent to the bottom url = existingUrl; deleteList << item; QString name = QUrl::fromLocalFile(url).adjusted(QUrl::StripTrailingSlash).fileName(); showMessage(i18n("Folder's parent %1 is already excluded", name)); } } } qDeleteAll(deleteList); QListWidgetItem* item = new QListWidgetItem(m_listWidget); QString displayName = folderDisplayName(url); item->setData(Qt::DisplayRole, displayName); item->setData(Qt::WhatsThisRole, url); item->setData(UrlRole, url); item->setData(Qt::DecorationRole, QIcon::fromTheme(iconName(url))); item->setToolTip(makeHomePretty(url)); m_listWidget->addItem(item); m_listWidget->setCurrentItem(item); Q_EMIT changed(); } void FolderSelectionWidget::slotRemoveButtonClicked() { QListWidgetItem* item = m_listWidget->currentItem(); delete item; Q_EMIT changed(); } void FolderSelectionWidget::slotCurrentItemChanged(QListWidgetItem* current, QListWidgetItem*) { - m_removeButton->setEnabled(current != 0); + m_removeButton->setEnabled(current != nullptr); } void FolderSelectionWidget::showMessage(const QString& message) { m_messageWidget->setText(message); m_messageWidget->setMessageType(KMessageWidget::Warning); m_messageWidget->animatedShow(); QTimer::singleShot(3000, m_messageWidget, &KMessageWidget::animatedHide); } QString FolderSelectionWidget::folderDisplayName(const QString& url) const { QString name = url; // Check Home Dir QString homePath = QDir::homePath() + QLatin1Char('/'); if (url == homePath) { return QDir(homePath).dirName(); } if (url.startsWith(homePath)) { name = url.mid(homePath.size()); } else { // Check Mount allMountPointsExcluded Q_FOREACH (QString mountPoint, m_mountPoints) { if (url.startsWith(mountPoint)) { name = QLatin1Char('[') + QDir(mountPoint).dirName() + QStringLiteral("]/") + url.mid(mountPoint.length()); break; } } } if (name.endsWith(QLatin1Char('/'))) { name = name.mid(0, name.size() - 1); } return name; } bool FolderSelectionWidget::shouldShowMountPoint(const QString& mountPoint) { if (mountPoint == QLatin1String("/")) return false; if (mountPoint.startsWith(QLatin1String("/boot"))) return false; if (mountPoint.startsWith(QLatin1String("/tmp"))) return false; // The user's home directory is forcibly added so we can ignore /home // if /home actually contains the home directory if (mountPoint.startsWith(QLatin1String("/home")) && QDir::homePath().startsWith(QLatin1String("/home"))) return false; return true; } QString FolderSelectionWidget::iconName(QString path) const { // Ensure paths end with / if (!path.endsWith(QDir::separator())) path.append(QDir::separator()); QString homePath = QDir::homePath(); if (!homePath.endsWith(QDir::separator())) homePath.append(QDir::separator()); if (path == homePath) return QStringLiteral("user-home"); if (m_mountPoints.contains(path)) return QStringLiteral("drive-harddisk"); return QStringLiteral("folder"); } diff --git a/kcms/baloo/folderselectionwidget.h b/kcms/baloo/folderselectionwidget.h index 24f00f114..3095e0638 100644 --- a/kcms/baloo/folderselectionwidget.h +++ b/kcms/baloo/folderselectionwidget.h @@ -1,90 +1,90 @@ /* * This file is part of the KDE Baloo project * Copyright (C) 2014 Vishesh Handa * * 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) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef FOLDERSELECTIONWIDGET_H #define FOLDERSELECTIONWIDGET_H #include #include #include #include class FolderSelectionWidget : public QWidget { Q_OBJECT public: - explicit FolderSelectionWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); + explicit FolderSelectionWidget(QWidget* parent = nullptr, Qt::WindowFlags f = nullptr); void setDirectoryList(QStringList includeDirs, QStringList exclude); QStringList includeFolders() const; QStringList excludeFolders() const; enum Roles { UrlRole = Qt::UserRole + 1 }; Q_SIGNALS: void changed(); private Q_SLOTS: void slotAddButtonClicked(); void slotRemoveButtonClicked(); void slotCurrentItemChanged(QListWidgetItem* current, QListWidgetItem*); private: QString folderDisplayName(const QString& url) const; bool shouldShowMountPoint(const QString& mountPoint); QString fetchMountPoint(const QString& url) const; void showMessage(const QString& message); /** * @brief Get the theme valid icon name for \p path. * * @param path Path to be analysed. * @return One of: "user-home", "drive-harddisk" or "folder" */ QString iconName(QString path) const; /** * @brief Widget with the list of directories. * */ QListWidget* m_listWidget; QStringList m_mountPoints; /** * @brief Button to add a directory to the list. * */ QPushButton* m_addButton; /** * @brief Button to remove the selected directory from the list. * */ QPushButton* m_removeButton; /** * @brief Information, warning or error message widget. * */ KMessageWidget* m_messageWidget; }; #endif // FOLDERSELECTIONWIDGET_H diff --git a/kcms/colors/scmeditorcolors.cpp b/kcms/colors/scmeditorcolors.cpp index 457602d63..fc94fec24 100644 --- a/kcms/colors/scmeditorcolors.cpp +++ b/kcms/colors/scmeditorcolors.cpp @@ -1,527 +1,527 @@ /* KDE Display color scheme setup module * Copyright (C) 2007 Matthew Woehlke * Copyright (C) 2007 Jeremy Whiting * * 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 "scmeditorcolors.h" #include #include #include //BEGIN WindecoColors SchemeEditorColors::WindecoColors::WindecoColors(const KSharedConfigPtr &config) { load(config); } void SchemeEditorColors::WindecoColors::load(const KSharedConfigPtr &config) { // NOTE: keep this in sync with kdelibs/kdeui/kernel/kglobalsettings.cpp KConfigGroup group(config, "WM"); m_colors[ActiveBackground] = group.readEntry("activeBackground", QColor(48, 174, 232)); m_colors[ActiveForeground] = group.readEntry("activeForeground", QColor(255, 255, 255)); m_colors[InactiveBackground] = group.readEntry("inactiveBackground", QColor(224, 223, 222)); m_colors[InactiveForeground] = group.readEntry("inactiveForeground", QColor(75, 71, 67)); m_colors[ActiveBlend] = group.readEntry("activeBlend", m_colors[ActiveForeground]); m_colors[InactiveBlend] = group.readEntry("inactiveBlend", m_colors[InactiveForeground]); } QColor SchemeEditorColors::WindecoColors::color(WindecoColors::Role role) const { return m_colors[role]; } //END WindecoColors SchemeEditorColors::SchemeEditorColors(KSharedConfigPtr config, QWidget *parent) : QWidget( parent ) , m_config( config ) { setupUi(this); setupColorTable(); connect(colorSet, static_cast(&QComboBox::currentIndexChanged), this, &SchemeEditorColors::updateColorTable); } void SchemeEditorColors::updateValues() { const int currentSet = colorSet->currentIndex() - 1; setPreview->setPalette(m_config, (KColorScheme::ColorSet)currentSet); colorPreview->setPalette(m_config); } void SchemeEditorColors::setupColorTable() { // first setup the common colors table commonColorTable->verticalHeader()->hide(); commonColorTable->horizontalHeader()->hide(); commonColorTable->setShowGrid(false); commonColorTable->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch); int minWidth = QPushButton(i18n("Varies")).minimumSizeHint().width(); commonColorTable->horizontalHeader()->setMinimumSectionSize(minWidth); commonColorTable->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents); for (int i = 0; i < 26; ++i) { KColorButton * button = new KColorButton(this); commonColorTable->setRowHeight(i, button->sizeHint().height()); button->setObjectName(QString::number(i)); connect(button, &KColorButton::changed, this, &SchemeEditorColors::colorChanged); m_commonColorButtons << button; if (i > 8 && i < 18) { // Inactive Text row through Positive Text role all need a varies button - QPushButton * variesButton = new QPushButton(NULL); + QPushButton * variesButton = new QPushButton(nullptr); variesButton->setText(i18n("Varies")); variesButton->setObjectName(QString::number(i)); connect(variesButton, &QPushButton::clicked, this, &SchemeEditorColors::variesClicked); QStackedWidget * widget = new QStackedWidget(this); widget->addWidget(button); widget->addWidget(variesButton); m_stackedWidgets.append(widget); commonColorTable->setCellWidget(i, 1, widget); } else { commonColorTable->setCellWidget(i, 1, button); } } // then the colorTable that the colorSets will use colorTable->verticalHeader()->hide(); colorTable->horizontalHeader()->hide(); colorTable->setShowGrid(false); colorTable->setRowCount(12); colorTable->horizontalHeader()->setMinimumSectionSize(minWidth); colorTable->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents); createColorEntry(i18n("Normal Background"), QStringLiteral("BackgroundNormal"), m_backgroundButtons, 0); createColorEntry(i18n("Alternate Background"), QStringLiteral("BackgroundAlternate"), m_backgroundButtons, 1); createColorEntry(i18n("Normal Text"), QStringLiteral("ForegroundNormal"), m_foregroundButtons, 2); createColorEntry(i18n("Inactive Text"), QStringLiteral("ForegroundInactive"), m_foregroundButtons, 3); createColorEntry(i18n("Active Text"), QStringLiteral("ForegroundActive"), m_foregroundButtons, 4); createColorEntry(i18n("Link Text"), QStringLiteral("ForegroundLink"), m_foregroundButtons, 5); createColorEntry(i18n("Visited Text"), QStringLiteral("ForegroundVisited"), m_foregroundButtons, 6); createColorEntry(i18n("Negative Text"), QStringLiteral("ForegroundNegative"), m_foregroundButtons, 7); createColorEntry(i18n("Neutral Text"), QStringLiteral("ForegroundNeutral"), m_foregroundButtons, 8); createColorEntry(i18n("Positive Text"), QStringLiteral("ForegroundPositive"), m_foregroundButtons, 9); createColorEntry(i18n("Focus Decoration"), QStringLiteral("DecorationFocus"), m_decorationButtons, 10); createColorEntry(i18n("Hover Decoration"), QStringLiteral("DecorationHover"), m_decorationButtons, 11); colorTable->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch); colorTable->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents); updateColorSchemes(); updateColorTable(); } void SchemeEditorColors::createColorEntry(const QString &text, const QString &key, QList &list, int index) { KColorButton *button = new KColorButton(this); button->setObjectName(QString::number(index)); connect(button, &KColorButton::changed, this, &SchemeEditorColors::colorChanged); list.append(button); m_colorKeys.insert(index, key); QTableWidgetItem *label = new QTableWidgetItem(text); colorTable->setItem(index, 0, label); colorTable->setCellWidget(index, 1, button); colorTable->setRowHeight(index, button->sizeHint().height()); } void SchemeEditorColors::variesClicked() { // find which button was changed const int row = sender()->objectName().toInt(); QColor color = QColorDialog::getColor(QColor(), this); if(color.isValid()) { changeColor(row, color); m_stackedWidgets[row - 9]->setCurrentIndex(0); } } void SchemeEditorColors::colorChanged( const QColor &newColor ) { // find which button was changed const int row = sender()->objectName().toInt(); changeColor(row, newColor); } void SchemeEditorColors::changeColor(int row, const QColor &newColor) { // update the m_colorSchemes for the selected colorSet const int currentSet = colorSet->currentIndex() - 1; if (currentSet == -1) { // common colors is selected switch (row) { case 0: // View Background button KConfigGroup(m_config, "Colors:View").writeEntry("BackgroundNormal", newColor); break; case 1: // View Text button KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundNormal", newColor); break; case 2: // Window Background Button KConfigGroup(m_config, "Colors:Window").writeEntry("BackgroundNormal", newColor); break; case 3: // Window Text Button KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundNormal", newColor); break; case 4: // Button Background button KConfigGroup(m_config, "Colors:Button").writeEntry("BackgroundNormal", newColor); break; case 5: // Button Text button KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundNormal", newColor); break; case 6: // Selection Background Button KConfigGroup(m_config, "Colors:Selection").writeEntry("BackgroundNormal", newColor); break; case 7: // Selection Text Button KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundNormal", newColor); break; case 8: // Selection Inactive Text Button KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundInactive", newColor); break; // buttons that could have varies in their place case 9: // Inactive Text Button (set all but Selection Inactive Text color) KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundInactive", newColor); KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundInactive", newColor); KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundInactive", newColor); KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundInactive", newColor); break; case 10: // Active Text Button (set all active text colors) KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundActive", newColor); KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundActive", newColor); KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundActive", newColor); KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundActive", newColor); KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundActive", newColor); break; case 11: // Link Text Button (set all link text colors) KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundLink", newColor); KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundLink", newColor); KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundLink", newColor); KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundLink", newColor); KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundLink", newColor); break; case 12: // Visited Text Button (set all visited text colors) KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundVisited", newColor); KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundVisited", newColor); KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundVisited", newColor); KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundVisited", newColor); KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundVisited", newColor); break; case 13: // Negative Text Button (set all negative text colors) KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundNegative", newColor); KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundNegative", newColor); KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundNegative", newColor); KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundNegative", newColor); KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundNegative", newColor); break; case 14: // Neutral Text Button (set all neutral text colors) KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundNeutral", newColor); KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundNeutral", newColor); KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundNeutral", newColor); KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundNeutral", newColor); KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundNeutral", newColor); break; case 15: // Positive Text Button (set all positive text colors) KConfigGroup(m_config, "Colors:View").writeEntry("ForegroundPositive", newColor); KConfigGroup(m_config, "Colors:Window").writeEntry("ForegroundPositive", newColor); KConfigGroup(m_config, "Colors:Selection").writeEntry("ForegroundPositive", newColor); KConfigGroup(m_config, "Colors:Button").writeEntry("ForegroundPositive", newColor); KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundPositive", newColor); break; case 16: // Focus Decoration Button (set all focus decoration colors) KConfigGroup(m_config, "Colors:View").writeEntry("DecorationFocus", newColor); KConfigGroup(m_config, "Colors:Window").writeEntry("DecorationFocus", newColor); KConfigGroup(m_config, "Colors:Selection").writeEntry("DecorationFocus", newColor); KConfigGroup(m_config, "Colors:Button").writeEntry("DecorationFocus", newColor); KConfigGroup(m_config, "Colors:Tooltip").writeEntry("DecorationFocus", newColor); break; case 17: // Hover Decoration Button (set all hover decoration colors) KConfigGroup(m_config, "Colors:View").writeEntry("DecorationHover", newColor); KConfigGroup(m_config, "Colors:Window").writeEntry("DecorationHover", newColor); KConfigGroup(m_config, "Colors:Selection").writeEntry("DecorationHover", newColor); KConfigGroup(m_config, "Colors:Button").writeEntry("DecorationHover", newColor); KConfigGroup(m_config, "Colors:Tooltip").writeEntry("DecorationHover", newColor); break; case 18: // Tooltip Background button KConfigGroup(m_config, "Colors:Tooltip").writeEntry("BackgroundNormal", newColor); break; case 19: // Tooltip Text button KConfigGroup(m_config, "Colors:Tooltip").writeEntry("ForegroundNormal", newColor); break; case 20: // Active Title Background KConfigGroup(m_config, "WM").writeEntry("activeBackground", newColor); break; case 21: // Active Title Text KConfigGroup(m_config, "WM").writeEntry("activeForeground", newColor); break; case 22: // Active Title Secondary KConfigGroup(m_config, "WM").writeEntry("activeBlend", newColor); break; case 23: // Inactive Title Background KConfigGroup(m_config, "WM").writeEntry("inactiveBackground", newColor); break; case 24: // Inactive Title Text KConfigGroup(m_config, "WM").writeEntry("inactiveForeground", newColor); break; case 25: // Inactive Title Secondary KConfigGroup(m_config, "WM").writeEntry("inactiveBlend", newColor); break; } m_commonColorButtons[row]->blockSignals(true); m_commonColorButtons[row]->setColor(newColor); m_commonColorButtons[row]->blockSignals(false); } else { QString group = colorSetGroupKey(currentSet); KConfigGroup(m_config, group).writeEntry(m_colorKeys[row], newColor); } updateColorSchemes(); emit changed(true); } QString SchemeEditorColors::colorSetGroupKey(int colorSet) { QString group; switch (colorSet) { case KColorScheme::Window: group = QStringLiteral("Colors:Window"); break; case KColorScheme::Button: group = QStringLiteral("Colors:Button"); break; case KColorScheme::Selection: group = QStringLiteral("Colors:Selection"); break; case KColorScheme::Tooltip: group = QStringLiteral("Colors:Tooltip"); break; case KColorScheme::Complementary: group = QStringLiteral("Colors:Complementary"); break; default: group = QStringLiteral("Colors:View"); } return group; } void SchemeEditorColors::updateColorSchemes() { m_colorSchemes.clear(); m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::View, m_config)); m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Window, m_config)); m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Button, m_config)); m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Selection, m_config)); m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Tooltip, m_config)); m_colorSchemes.append(KColorScheme(QPalette::Active, KColorScheme::Complementary, m_config)); m_wmColors.load(m_config); } void SchemeEditorColors::updateColorTable() { // subtract one here since the 0 item is "Common Colors" const int currentSet = colorSet->currentIndex() - 1; if (currentSet == -1) { // common colors is selected stackColors->setCurrentIndex(0); stackPreview->setCurrentIndex(0); KColorButton * button; foreach (button, m_commonColorButtons) { button->blockSignals(true); } m_commonColorButtons[0]->setColor(m_colorSchemes[KColorScheme::View].background(KColorScheme::NormalBackground).color()); m_commonColorButtons[1]->setColor(m_colorSchemes[KColorScheme::View].foreground(KColorScheme::NormalText).color()); m_commonColorButtons[2]->setColor(m_colorSchemes[KColorScheme::Window].background(KColorScheme::NormalBackground).color()); m_commonColorButtons[3]->setColor(m_colorSchemes[KColorScheme::Window].foreground(KColorScheme::NormalText).color()); m_commonColorButtons[4]->setColor(m_colorSchemes[KColorScheme::Button].background(KColorScheme::NormalBackground).color()); m_commonColorButtons[5]->setColor(m_colorSchemes[KColorScheme::Button].foreground(KColorScheme::NormalText).color()); m_commonColorButtons[6]->setColor(m_colorSchemes[KColorScheme::Selection].background(KColorScheme::NormalBackground).color()); m_commonColorButtons[7]->setColor(m_colorSchemes[KColorScheme::Selection].foreground(KColorScheme::NormalText).color()); m_commonColorButtons[8]->setColor(m_colorSchemes[KColorScheme::Selection].foreground(KColorScheme::InactiveText).color()); setCommonForeground(KColorScheme::InactiveText, 0, 9); setCommonForeground(KColorScheme::ActiveText, 1, 10); setCommonForeground(KColorScheme::LinkText, 2, 11); setCommonForeground(KColorScheme::VisitedText, 3, 12); setCommonForeground(KColorScheme::NegativeText, 4, 13); setCommonForeground(KColorScheme::NeutralText, 5, 14); setCommonForeground(KColorScheme::PositiveText, 6, 15); setCommonDecoration(KColorScheme::FocusColor, 7, 16); setCommonDecoration(KColorScheme::HoverColor, 8, 17); m_commonColorButtons[18]->setColor(m_colorSchemes[KColorScheme::Tooltip].background(KColorScheme::NormalBackground).color()); m_commonColorButtons[19]->setColor(m_colorSchemes[KColorScheme::Tooltip].foreground(KColorScheme::NormalText).color()); m_commonColorButtons[20]->setColor(m_wmColors.color(WindecoColors::ActiveBackground)); m_commonColorButtons[21]->setColor(m_wmColors.color(WindecoColors::ActiveForeground)); m_commonColorButtons[22]->setColor(m_wmColors.color(WindecoColors::ActiveBlend)); m_commonColorButtons[23]->setColor(m_wmColors.color(WindecoColors::InactiveBackground)); m_commonColorButtons[24]->setColor(m_wmColors.color(WindecoColors::InactiveForeground)); m_commonColorButtons[25]->setColor(m_wmColors.color(WindecoColors::InactiveBlend)); foreach (button, m_commonColorButtons) { button->blockSignals(false); } } else { // a real color set is selected setPreview->setPalette(m_config, (KColorScheme::ColorSet)currentSet); stackColors->setCurrentIndex(1); stackPreview->setCurrentIndex(1); for (int i = KColorScheme::NormalBackground; i <= KColorScheme::AlternateBackground; ++i) { m_backgroundButtons[i]->blockSignals(true); m_backgroundButtons[i]->setColor(m_colorSchemes[currentSet].background(KColorScheme::BackgroundRole(i)).color()); m_backgroundButtons[i]->blockSignals(false); } for (int i = KColorScheme::NormalText; i <= KColorScheme::PositiveText; ++i) { m_foregroundButtons[i]->blockSignals(true); m_foregroundButtons[i]->setColor(m_colorSchemes[currentSet].foreground(KColorScheme::ForegroundRole(i)).color()); m_foregroundButtons[i]->blockSignals(false); } for (int i = KColorScheme::FocusColor; i <= KColorScheme::HoverColor; ++i) { m_decorationButtons[i]->blockSignals(true); m_decorationButtons[i]->setColor(m_colorSchemes[currentSet].decoration(KColorScheme::DecorationRole(i)).color()); m_decorationButtons[i]->blockSignals(false); } } } void SchemeEditorColors::setCommonForeground(KColorScheme::ForegroundRole role, int stackIndex, int buttonIndex) { QColor color = m_colorSchemes[KColorScheme::View].foreground(role).color(); for (int i = KColorScheme::Window; i < KColorScheme::Tooltip; ++i) { if (i == KColorScheme::Selection && role == KColorScheme::InactiveText) break; if (m_colorSchemes[i].foreground(role).color() != color) { m_stackedWidgets[stackIndex]->setCurrentIndex(1); return; } } m_stackedWidgets[stackIndex]->setCurrentIndex(0); m_commonColorButtons[buttonIndex]->setColor(color); } void SchemeEditorColors::setCommonDecoration(KColorScheme::DecorationRole role, int stackIndex, int buttonIndex) { QColor color = m_colorSchemes[KColorScheme::View].decoration(role).color(); for (int i = KColorScheme::Window; i < KColorScheme::Tooltip; ++i) { if (m_colorSchemes[i].decoration(role).color() != color) { m_stackedWidgets[stackIndex]->setCurrentIndex(1); return; } } m_stackedWidgets[stackIndex]->setCurrentIndex(0); m_commonColorButtons[buttonIndex]->setColor(color); } void SchemeEditorColors::updateFromColorSchemes() { for (int i = KColorScheme::View; i <= KColorScheme::Tooltip; ++i) { KConfigGroup group(m_config, colorSetGroupKey(i)); group.writeEntry("BackgroundNormal", m_colorSchemes[i].background(KColorScheme::NormalBackground).color()); group.writeEntry("BackgroundAlternate", m_colorSchemes[i].background(KColorScheme::AlternateBackground).color()); group.writeEntry("ForegroundNormal", m_colorSchemes[i].foreground(KColorScheme::NormalText).color()); group.writeEntry("ForegroundInactive", m_colorSchemes[i].foreground(KColorScheme::InactiveText).color()); group.writeEntry("ForegroundActive", m_colorSchemes[i].foreground(KColorScheme::ActiveText).color()); group.writeEntry("ForegroundLink", m_colorSchemes[i].foreground(KColorScheme::LinkText).color()); group.writeEntry("ForegroundVisited", m_colorSchemes[i].foreground(KColorScheme::VisitedText).color()); group.writeEntry("ForegroundNegative", m_colorSchemes[i].foreground(KColorScheme::NegativeText).color()); group.writeEntry("ForegroundNeutral", m_colorSchemes[i].foreground(KColorScheme::NeutralText).color()); group.writeEntry("ForegroundPositive", m_colorSchemes[i].foreground(KColorScheme::PositiveText).color()); group.writeEntry("DecorationFocus", m_colorSchemes[i].decoration(KColorScheme::FocusColor).color()); group.writeEntry("DecorationHover", m_colorSchemes[i].decoration(KColorScheme::HoverColor).color()); } KConfigGroup WMGroup(m_config, "WM"); WMGroup.writeEntry("activeBackground", m_wmColors.color(WindecoColors::ActiveBackground)); WMGroup.writeEntry("activeForeground", m_wmColors.color(WindecoColors::ActiveForeground)); WMGroup.writeEntry("inactiveBackground", m_wmColors.color(WindecoColors::InactiveBackground)); WMGroup.writeEntry("inactiveForeground", m_wmColors.color(WindecoColors::InactiveForeground)); WMGroup.writeEntry("activeBlend", m_wmColors.color(WindecoColors::ActiveBlend)); WMGroup.writeEntry("inactiveBlend", m_wmColors.color(WindecoColors::InactiveBlend)); } diff --git a/kcms/componentchooser/componentchooser.cpp b/kcms/componentchooser/componentchooser.cpp index 55dd83acb..65fa9eeff 100644 --- a/kcms/componentchooser/componentchooser.cpp +++ b/kcms/componentchooser/componentchooser.cpp @@ -1,280 +1,280 @@ /*************************************************************************** componentchooser.cpp - description ------------------- copyright : (C) 2002 by Joseph Wenninger email : jowenn@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License verstion 2 as * * published by the Free Software Foundation * * * ***************************************************************************/ #include "componentchooser.h" #include "componentchooserbrowser.h" #include "componentchooseremail.h" #include "componentchooserfilemanager.h" #ifdef Q_OS_UNIX #include "componentchooserterminal.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include //BEGIN General kpart based Component selection CfgComponent::CfgComponent(QWidget *parent) : QWidget(parent), Ui::ComponentConfig_UI(), CfgPlugin() { setupUi( this ); connect(ComponentSelector,SIGNAL(activated(const QString&)),this,SLOT(slotComponentChanged(const QString&))); } CfgComponent::~CfgComponent() { } void CfgComponent::slotComponentChanged(const QString&) { emit changed(true); } void CfgComponent::save(KConfig *cfg) { // yes, this can happen if there are NO KTrader offers for this component if (!m_lookupDict.contains(ComponentSelector->currentText())) return; KConfigGroup mainGroup = cfg->group(QByteArray()); QString serviceTypeToConfigure=mainGroup.readEntry("ServiceTypeToConfigure"); KConfig store(mainGroup.readPathEntry("storeInFile", QStringLiteral("null"))); KConfigGroup cg(&store, mainGroup.readEntry("valueSection")); cg.writePathEntry(mainGroup.readEntry("valueName", "kcm_componenchooser_null"), m_lookupDict.value(ComponentSelector->currentText())); store.sync(); emit changed(false); } void CfgComponent::load(KConfig *cfg) { ComponentSelector->clear(); m_lookupDict.clear(); m_revLookupDict.clear(); const KConfigGroup mainGroup = cfg->group(QByteArray()); const QString serviceTypeToConfigure = mainGroup.readEntry("ServiceTypeToConfigure"); const KService::List offers = KServiceTypeTrader::self()->query(serviceTypeToConfigure); for (KService::List::const_iterator tit = offers.begin(); tit != offers.end(); ++tit) { ComponentSelector->addItem((*tit)->name()); m_lookupDict.insert((*tit)->name(), (*tit)->desktopEntryName()); m_revLookupDict.insert((*tit)->desktopEntryName(), (*tit)->name()); } KConfig store(mainGroup.readPathEntry("storeInFile",QStringLiteral("null"))); const KConfigGroup group(&store, mainGroup.readEntry("valueSection")); QString setting = group.readEntry(mainGroup.readEntry("valueName","kcm_componenchooser_null"), QString()); if (setting.isEmpty()) setting = mainGroup.readEntry("defaultImplementation", QString()); QString tmp = m_revLookupDict.value(setting); if (!tmp.isEmpty()) { for (int i=0;icount();i++) if (tmp==ComponentSelector->itemText(i)) { ComponentSelector->setCurrentIndex(i); break; } } emit changed(false); } void CfgComponent::defaults() { //todo } //END General kpart based Component selection ComponentChooser::ComponentChooser(QWidget *parent): - QWidget(parent), Ui::ComponentChooser_UI(), somethingChanged(false), configWidget(0) + QWidget(parent), Ui::ComponentChooser_UI(), somethingChanged(false), configWidget(nullptr) { setupUi(this); static_cast(layout())->setRowStretch(1, 1); const QStringList services=KGlobal::dirs()->findAllResources( "data",QStringLiteral("kcm_componentchooser/*.desktop"), KStandardDirs::NoDuplicates); for (QStringList::const_iterator it=services.constBegin(); it!=services.constEnd(); ++it) { KConfig cfg(*it, KConfig::SimpleConfig); KConfigGroup cg = cfg.group(QByteArray()); QListWidgetItem *item = new QListWidgetItem( QIcon::fromTheme(cg.readEntry("Icon",QStringLiteral("preferences-desktop-default-applications"))), cg.readEntry("Name",i18n("Unknown"))); item->setData(Qt::UserRole, (*it)); ServiceChooser->addItem(item); } ServiceChooser->setFixedWidth(ServiceChooser->sizeHintForColumn(0) + 20); ServiceChooser->sortItems(); connect(ServiceChooser,&QListWidget::currentItemChanged,this,&ComponentChooser::slotServiceSelected); ServiceChooser->setCurrentRow(0); slotServiceSelected(ServiceChooser->item(0)); } void ComponentChooser::slotServiceSelected(QListWidgetItem* it) { if (!it) return; if (somethingChanged) { if (KMessageBox::questionYesNo(this,i18n("You changed the default component of your choice, do want to save that change now ?"),QString(),KStandardGuiItem::save(),KStandardGuiItem::discard())==KMessageBox::Yes) save(); } KConfig cfg(it->data(Qt::UserRole).toString(), KConfig::SimpleConfig); ComponentDescription->setText(cfg.group(QByteArray()).readEntry("Comment",i18n("No description available"))); ComponentDescription->setMinimumSize(ComponentDescription->sizeHint()); QString cfgType=cfg.group(QByteArray()).readEntry("configurationType"); - QWidget *newConfigWidget = 0; + QWidget *newConfigWidget = nullptr; if (cfgType.isEmpty() || (cfgType==QLatin1String("component"))) { if (!(configWidget && qobject_cast(configWidget))) { CfgComponent* cfgcomp = new CfgComponent(configContainer); cfgcomp->ChooserDocu->setText(i18n("Choose from the list below which component should be used by default for the %1 service.", it->text())); newConfigWidget = cfgcomp; } else { static_cast(configWidget)->ChooserDocu->setText(i18n("Choose from the list below which component should be used by default for the %1 service.", it->text())); } } else if (cfgType==QLatin1String("internal_email")) { if (!(configWidget && qobject_cast(configWidget))) { newConfigWidget = new CfgEmailClient(configContainer); } } #ifdef Q_OS_UNIX else if (cfgType==QLatin1String("internal_terminal")) { if (!(configWidget && qobject_cast(configWidget))) { newConfigWidget = new CfgTerminalEmulator(configContainer); } } #endif else if (cfgType==QLatin1String("internal_filemanager")) { if (!(configWidget && qobject_cast(configWidget))) { newConfigWidget = new CfgFileManager(configContainer); } } else if (cfgType==QLatin1String("internal_browser")) { if (!(configWidget && qobject_cast(configWidget))) { newConfigWidget = new CfgBrowser(configContainer); } } if (newConfigWidget) { configContainer->addWidget(newConfigWidget); configContainer->setCurrentWidget (newConfigWidget); configContainer->removeWidget(configWidget); delete configWidget; configWidget=newConfigWidget; connect(configWidget,SIGNAL(changed(bool)),this,SLOT(emitChanged(bool))); configContainer->setMinimumSize(configWidget->sizeHint()); } if (configWidget) dynamic_cast(configWidget)->load(&cfg); emitChanged(false); latestEditedService=it->data(Qt::UserRole).toString(); } void ComponentChooser::emitChanged(bool val) { somethingChanged=val; emit changed(val); } ComponentChooser::~ComponentChooser() { delete configWidget; } void ComponentChooser::load() { if( configWidget ) { CfgPlugin * plugin = dynamic_cast( configWidget ); if( plugin ) { KConfig cfg(latestEditedService, KConfig::SimpleConfig); plugin->load( &cfg ); } } } void ComponentChooser::save() { if( configWidget ) { CfgPlugin* plugin = dynamic_cast( configWidget ); if( plugin ) { KConfig cfg(latestEditedService, KConfig::SimpleConfig); plugin->save( &cfg ); } } } void ComponentChooser::restoreDefault() { if (configWidget) { dynamic_cast(configWidget)->defaults(); emitChanged(true); } /* txtEMailClient->setText("kmail"); chkRunTerminal->setChecked(false); // Check if -e is needed, I do not think so terminalLE->setText("xterm"); //No need for i18n terminalCB->setChecked(true); emitChanged(false); */ } // vim: sw=4 ts=4 noet diff --git a/kcms/componentchooser/componentchooser.h b/kcms/componentchooser/componentchooser.h index 6647a6e3c..5b45e6cdd 100644 --- a/kcms/componentchooser/componentchooser.h +++ b/kcms/componentchooser/componentchooser.h @@ -1,90 +1,90 @@ /*************************************************************************** componentchooser.h - description ------------------- copyright : (C) 2002 by Joseph Wenninger email : jowenn@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 as * * published by the Free Software Foundationi * * * ***************************************************************************/ #ifndef _COMPONENTCHOOSER_H_ #define _COMPONENTCHOOSER_H_ #include "ui_componentchooser_ui.h" #include "ui_componentconfig_ui.h" #include //Added by qt3to4: #include #include class QListWidgetItem; class KConfig; /* The CfgPlugin class is an exception. It is LGPL. It will be parted of the plugin interface which I plan for KDE 3.2. */ class CfgPlugin { public: CfgPlugin(){} virtual ~CfgPlugin(){} virtual void load(KConfig *cfg)=0; virtual void save(KConfig *cfg)=0; virtual void defaults()=0; }; class CfgComponent: public QWidget, public Ui::ComponentConfig_UI, public CfgPlugin { Q_OBJECT public: CfgComponent(QWidget *parent); ~CfgComponent() override; void load(KConfig *cfg) override; void save(KConfig *cfg) override; void defaults() override; protected: QHash m_lookupDict,m_revLookupDict; protected Q_SLOTS: void slotComponentChanged(const QString&); Q_SIGNALS: void changed(bool); }; class ComponentChooser : public QWidget, public Ui::ComponentChooser_UI { Q_OBJECT public: - ComponentChooser(QWidget *parent=0); + ComponentChooser(QWidget *parent=nullptr); ~ComponentChooser() override; void load(); void save(); void restoreDefault(); private: QString latestEditedService; bool somethingChanged; QWidget *configWidget; QVBoxLayout *myLayout; protected Q_SLOTS: void emitChanged(bool); void slotServiceSelected(QListWidgetItem *); Q_SIGNALS: void changed(bool); }; #endif diff --git a/kcms/componentchooser/componentchooserbrowser.cpp b/kcms/componentchooser/componentchooserbrowser.cpp index 878480d21..e8c170ec6 100644 --- a/kcms/componentchooser/componentchooserbrowser.cpp +++ b/kcms/componentchooser/componentchooserbrowser.cpp @@ -1,167 +1,167 @@ /*************************************************************************** componentchooserbrowser.cpp ------------------- copyright : (C) 2002 by Joseph Wenninger email : jowenn@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 as * * published by the Free Software Foundationi * * * ***************************************************************************/ #include "componentchooserbrowser.h" #include #include #include #include #include #include #include "../migrationlib/kdelibs4config.h" #include CfgBrowser::CfgBrowser(QWidget *parent) : QWidget(parent), Ui::BrowserConfig_UI(),CfgPlugin() { setupUi(this); connect(lineExec, &KLineEdit::textChanged, this, &CfgBrowser::configChanged); connect(radioKIO, &QRadioButton::toggled, this, &CfgBrowser::configChanged); connect(radioService, &QRadioButton::toggled, this, &CfgBrowser::configChanged); connect(browserCombo, static_cast(&QComboBox::activated), this, [this](int index) { const QString &storageId = browserCombo->itemData(index).toString(); m_browserService = KService::serviceByStorageId(storageId); m_browserExec.clear(); emit configChanged(); }); connect(radioExec, &QRadioButton::toggled, this, &CfgBrowser::configChanged); connect(btnSelectApplication, &QToolButton::clicked, this, &CfgBrowser::selectBrowser); } CfgBrowser::~CfgBrowser() { } void CfgBrowser::configChanged() { emit changed(true); } void CfgBrowser::defaults() { - load(0); + load(nullptr); } void CfgBrowser::load(KConfig *) { const KConfigGroup config(KSharedConfig::openConfig(QStringLiteral("kdeglobals")), QStringLiteral("General") ); const QString exec = config.readPathEntry( QStringLiteral("BrowserApplication"), QString() ); if (exec.isEmpty()) { radioKIO->setChecked(true); m_browserExec = exec; - m_browserService = 0; + m_browserService = nullptr; } else { radioExec->setChecked(true); if (exec.startsWith('!')) { m_browserExec = exec.mid(1); - m_browserService = 0; + m_browserService = nullptr; } else { m_browserService = KService::serviceByStorageId( exec ); if (m_browserService) { m_browserExec = m_browserService->desktopEntryName(); } else { m_browserExec.clear(); } } } lineExec->setText(m_browserExec); browserCombo->clear(); const auto &browsers = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("'WebBrowser' in Categories")); for (const auto &service : browsers) { browserCombo->addItem(QIcon::fromTheme(service->icon()), service->name(), service->storageId()); if ((m_browserService && m_browserService->storageId() == service->storageId()) || service->exec() == m_browserExec) { browserCombo->setCurrentIndex(browserCombo->count() - 1); radioService->setChecked(true); } } emit changed(false); } void CfgBrowser::save(KConfig *) { KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("kdeglobals")); KConfigGroup config(profile, QStringLiteral("General")); QString exec; if (radioService->isChecked()) { if (m_browserService) { exec = m_browserService->storageId(); } } else if (radioExec->isChecked()) { exec = lineExec->text(); if (m_browserService && (exec == m_browserExec)) { exec = m_browserService->storageId(); // Use service } else if (!exec.isEmpty()) { exec = '!' + exec; // Literal command } } config.writePathEntry( QStringLiteral("BrowserApplication"), exec); // KConfig::Normal|KConfig::Global config.sync(); // Save the default browser as scheme handler for http(s) in mimeapps.list KSharedConfig::Ptr mimeAppList = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); if (mimeAppList->isConfigWritable(true /*warn user if not writable*/)) { KConfigGroup defaultApp(mimeAppList, "Default Applications"); if (m_browserService) { defaultApp.writeXdgListEntry(QStringLiteral("x-scheme-handler/http"), QStringList(m_browserService->storageId())); defaultApp.writeXdgListEntry(QStringLiteral("x-scheme-handler/https"), QStringList(m_browserService->storageId())); } else { defaultApp.deleteEntry(QStringLiteral("x-scheme-handler/http")); defaultApp.deleteEntry(QStringLiteral("x-scheme-handler/https")); } mimeAppList->sync(); KBuildSycocaProgressDialog::rebuildKSycoca(this); } Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("General"), "kdeglobals"); KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged); emit changed(false); } void CfgBrowser::selectBrowser() { QList urlList; KOpenWithDialog dlg(urlList, i18n("Select preferred Web browser application:"), QString(), this); if (dlg.exec() != QDialog::Accepted) return; m_browserService = dlg.service(); if (m_browserService) { // check if we have listed it in the browser combo, if so, put it there instead const int index = browserCombo->findData(m_browserService->storageId()); if (index > -1) { browserCombo->setCurrentIndex(index); radioService->setChecked(true); } else { m_browserExec = m_browserService->desktopEntryName(); if (m_browserExec.isEmpty()) { m_browserExec = m_browserService->exec(); } } } else { m_browserExec = dlg.text(); } lineExec->setText(m_browserExec); } diff --git a/kcms/componentchooser/componentchooseremail.cpp b/kcms/componentchooser/componentchooseremail.cpp index 3064b2167..f9bc92b55 100644 --- a/kcms/componentchooser/componentchooseremail.cpp +++ b/kcms/componentchooser/componentchooseremail.cpp @@ -1,146 +1,146 @@ /*************************************************************************** componentchooseremail.cpp ------------------- copyright : (C) 2002 by Joseph Wenninger email : jowenn@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License verstion 2 as * * published by the Free Software Foundation * * * ***************************************************************************/ #include "componentchooseremail.h" #include #include #include #include #include #include #include #include #include #include #include // for chmod: #include #include #include CfgEmailClient::CfgEmailClient(QWidget *parent) : QWidget(parent), Ui::EmailClientConfig_UI(), CfgPlugin() { setupUi( this ); pSettings = new KEMailSettings(); connect(kmailCB, &QRadioButton::toggled, this, &CfgEmailClient::configChanged); connect(txtEMailClient, &KLineEdit::textChanged, this, &CfgEmailClient::configChanged); #ifdef Q_OS_UNIX connect(chkRunTerminal, &QCheckBox::clicked, this, &CfgEmailClient::configChanged); #else chkRunTerminal->hide(); #endif connect(btnSelectEmail, &QToolButton::clicked, this, &CfgEmailClient::selectEmailClient); } CfgEmailClient::~CfgEmailClient() { delete pSettings; } void CfgEmailClient::defaults() { - load(0); + load(nullptr); } void CfgEmailClient::load(KConfig *) { QString emailClient = pSettings->getSetting(KEMailSettings::ClientProgram); bool useKMail = (emailClient.isEmpty()); kmailCB->setChecked(useKMail); otherCB->setChecked(!useKMail); txtEMailClient->setText(emailClient); txtEMailClient->setFixedHeight(txtEMailClient->sizeHint().height()); chkRunTerminal->setChecked((pSettings->getSetting(KEMailSettings::ClientTerminal) == QLatin1String("true"))); emit changed(false); } void CfgEmailClient::configChanged() { emit changed(true); } void CfgEmailClient::selectEmailClient() { QList urlList; KOpenWithDialog dlg(urlList, i18n("Select preferred email client:"), QString(), this); // hide "Do not &close when command exits" here, we don't need it for a mail client dlg.hideNoCloseOnExit(); if (dlg.exec() != QDialog::Accepted) return; QString client = dlg.text(); m_emailClientService = dlg.service(); // get the preferred Terminal Application KConfigGroup confGroup( KSharedConfig::openConfig(), QStringLiteral("General") ); QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QStringLiteral("konsole")); preferredTerminal += QLatin1String(" -e "); int len = preferredTerminal.length(); bool b = client.left(len) == preferredTerminal; if (b) client = client.mid(len); if (!client.isEmpty()) { chkRunTerminal->setChecked(b); txtEMailClient->setText(client); } } void CfgEmailClient::save(KConfig *) { if (kmailCB->isChecked()) { pSettings->setSetting(KEMailSettings::ClientProgram, QString()); pSettings->setSetting(KEMailSettings::ClientTerminal, QStringLiteral("false")); } else { pSettings->setSetting(KEMailSettings::ClientProgram, txtEMailClient->text()); pSettings->setSetting(KEMailSettings::ClientTerminal, (chkRunTerminal->isChecked()) ? "true" : "false"); } // Save the default email client in mimeapps.list into the group [Default Applications] KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); if (profile->isConfigWritable(true)) { KConfigGroup defaultApp(profile, "Default Applications"); if (kmailCB->isChecked()) { QString kmailDesktop = QStringLiteral("org.kde.kmail.desktop"); if (KService::serviceByDesktopName(QStringLiteral("org.kde.kmail2"))) { kmailDesktop = QStringLiteral("org.kde.kmail2.desktop"); } defaultApp.writeXdgListEntry("x-scheme-handler/mailto", QStringList(kmailDesktop)); } else if (m_emailClientService) { defaultApp.writeXdgListEntry("x-scheme-handler/mailto", QStringList(m_emailClientService->storageId())); } profile->sync(); } // insure proper permissions -- contains sensitive data QString cfgName(QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("emails"))); if (!cfgName.isEmpty()) ::chmod(QFile::encodeName(cfgName), 0600); QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/Component"), QStringLiteral("org.kde.Kcontrol"), QStringLiteral("KDE_emailSettingsChanged") ); QDBusConnection::sessionBus().send(message); emit changed(false); } diff --git a/kcms/componentchooser/componentchooserfilemanager.cpp b/kcms/componentchooser/componentchooserfilemanager.cpp index 0991e8dd5..0a9f39031 100644 --- a/kcms/componentchooser/componentchooserfilemanager.cpp +++ b/kcms/componentchooser/componentchooserfilemanager.cpp @@ -1,142 +1,142 @@ /* This file is part of the KDE project Copyright (C) 2008 David Faure 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, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), 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 "componentchooserfilemanager.h" #include #include #include #include #include #include #include #include #include "../migrationlib/kdelibs4config.h" CfgFileManager::CfgFileManager(QWidget *parent) : QWidget(parent), Ui::FileManagerConfig_UI(),CfgPlugin() { setupUi(this); connect(btnSelectFileManager, &QToolButton::clicked, this, &CfgFileManager::slotAddFileManager); } CfgFileManager::~CfgFileManager() { } void CfgFileManager::configChanged() { emit changed(true); } void CfgFileManager::defaults() { - load(0); + load(nullptr); } static KService::List appOffers() { return KMimeTypeTrader::self()->query(QStringLiteral("inode/directory"), QStringLiteral("Application")); } void CfgFileManager::load(KConfig *) { qDeleteAll(mDynamicWidgets); mDynamicWidgets.clear(); const KService::List apps = appOffers(); bool first = true; Q_FOREACH(const KService::Ptr& service, apps) { QRadioButton* button = new QRadioButton(service->name(), this); connect(button, &QRadioButton::toggled, this, &CfgFileManager::configChanged); button->setProperty("storageId", service->storageId()); radioLayout->addWidget(button); if (first) { button->setChecked(true); first = false; } mDynamicWidgets << button; } emit changed(false); } static const char s_DefaultApplications[] = "Default Applications"; static const char s_AddedAssociations[] = "Added Associations"; static const char s_RemovedAssociations[] = "Removed Associations"; void CfgFileManager::save(KConfig *) { QString storageId; Q_FOREACH(QRadioButton* button, qFindChildren(this)) { if (button->isChecked()) { storageId = button->property("storageId").toString(); } } qDebug() << storageId; if (!storageId.isEmpty()) { // This is taken from filetypes/mimetypedata.cpp KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); if (!profile->isConfigWritable(true)) // warn user if mimeapps.list is root-owned (#155126/#94504) return; const QString mime = QStringLiteral("inode/directory"); KConfigGroup addedApps(profile, s_AddedAssociations); QStringList userApps = addedApps.readXdgListEntry(mime); userApps.removeAll(storageId); // remove if present, to make it first in the list userApps.prepend(storageId); addedApps.writeXdgListEntry(mime, userApps); // Save the default file manager as per mime-apps spec 1.0.1 KConfigGroup defaultApp(profile, s_DefaultApplications); defaultApp.writeXdgListEntry(mime, QStringList(storageId)); Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("Added Associations"), QStringLiteral("mimeapps.list")); profile->sync(); // Clean out any kde-mimeapps.list which would take precedence any cancel our changes. // (also taken from filetypes/mimetypedata.cpp) const QString desktops = QString::fromLocal8Bit(qgetenv("XDG_CURRENT_DESKTOP")); foreach (const QString &desktop, desktops.split(":", QString::SkipEmptyParts)) { const QString file = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + desktop.toLower() + QLatin1String("-mimeapps.list"); if (QFileInfo::exists(file)) { qDebug() << "Cleaning up" << file; KConfig conf(file, KConfig::NoGlobals); KConfigGroup(&conf, s_DefaultApplications).deleteEntry(mime); KConfigGroup(&conf, s_AddedAssociations).deleteEntry(mime); KConfigGroup(&conf, s_RemovedAssociations).deleteEntry(mime); } } KBuildSycocaProgressDialog::rebuildKSycoca(this); } emit changed(false); } void CfgFileManager::slotAddFileManager() { KProcess proc; proc << QStringLiteral("keditfiletype5"); proc << QStringLiteral("inode/directory"); if (proc.execute() == 0) { - load(0); + load(nullptr); } } diff --git a/kcms/componentchooser/componentchooserterminal.cpp b/kcms/componentchooser/componentchooserterminal.cpp index ab7256e3e..12582e943 100644 --- a/kcms/componentchooser/componentchooserterminal.cpp +++ b/kcms/componentchooser/componentchooserterminal.cpp @@ -1,115 +1,115 @@ /*************************************************************************** componentchooser.cpp - description ------------------- copyright : (C) 2002 by Joseph Wenninger email : jowenn@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License verstion 2 as * * published by the Free Software Foundation * * * ***************************************************************************/ #include "componentchooserterminal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../migrationlib/kdelibs4config.h" CfgTerminalEmulator::CfgTerminalEmulator(QWidget *parent) : QWidget(parent), Ui::TerminalEmulatorConfig_UI(), CfgPlugin() { setupUi(this); connect(terminalLE, &QLineEdit::textChanged, this, &CfgTerminalEmulator::configChanged); connect(terminalCB, &QRadioButton::toggled, this, &CfgTerminalEmulator::configChanged); connect(otherCB, &QRadioButton::toggled, this, &CfgTerminalEmulator::configChanged); connect(btnSelectTerminal, &QToolButton::clicked, this, &CfgTerminalEmulator::selectTerminalApp); } CfgTerminalEmulator::~CfgTerminalEmulator() { } void CfgTerminalEmulator::configChanged() { emit changed(true); } void CfgTerminalEmulator::defaults() { - load(0); + load(nullptr); } void CfgTerminalEmulator::load(KConfig *) { KConfigGroup config(KSharedConfig::openConfig(QStringLiteral("kdeglobals")), "General"); QString terminal = config.readPathEntry("TerminalApplication",QStringLiteral("konsole")); if (terminal == QLatin1String("konsole")) { terminalLE->setText(QStringLiteral("xterm")); terminalCB->setChecked(true); } else { terminalLE->setText(terminal); otherCB->setChecked(true); } emit changed(false); } void CfgTerminalEmulator::save(KConfig *) { KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("kdeglobals")); KConfigGroup config(profile, QStringLiteral("General")); const QString terminal = terminalCB->isChecked() ? QStringLiteral("konsole") : terminalLE->text(); config.writePathEntry("TerminalApplication", terminal); // KConfig::Normal|KConfig::Global); config.sync(); Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("General"), "kdeglobals"); KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged); QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.klauncher5"), QStringLiteral("/KLauncher"), QStringLiteral("org.kde.KLauncher"), QStringLiteral("reparseConfiguration")); QDBusConnection::sessionBus().send(message); emit changed(false); } void CfgTerminalEmulator::selectTerminalApp() { QList urlList; KOpenWithDialog dlg(urlList, i18n("Select preferred terminal application:"), QString(), this); // hide "Run in &terminal" here, we don't need it for a Terminal Application dlg.hideRunInTerminal(); if (dlg.exec() != QDialog::Accepted) return; QString client = dlg.text(); if (!client.isEmpty()) { terminalLE->setText(client); } } // vim: sw=4 ts=4 noet diff --git a/kcms/componentchooser/ktimerdialog.h b/kcms/componentchooser/ktimerdialog.h index 2977c4a40..23acda2ec 100644 --- a/kcms/componentchooser/ktimerdialog.h +++ b/kcms/componentchooser/ktimerdialog.h @@ -1,172 +1,172 @@ /* * This file is part of the KDE Libraries * Copyright (C) 2002 Hamish Rodda * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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. * */ #ifndef _KTIMERDIALOG_H_ #define _KTIMERDIALOG_H_ #include #include #include class QTimer; class KHBox; class QProgressBar; class QLabel; /** * Provides a dialog that is only available for a specified amount * of time, and reports the time remaining to the user. * * The timer is capable of counting up or down, for any number of milliseconds. * * The button which is activated upon timeout can be specified, as can the * update interval for the dialog box. * * In addition, this class retains all of the functionality of @see KDialog. * * @short A dialog with a time limit and corresponding UI features. * @author Hamish Rodda */ class KTimerDialog : public KDialog { Q_OBJECT public: /** * @li @p CountDown - The timer counts downwards from the seconds given. * @li @p CountUp - The timer counts up to the number of seconds given. * @li @p Manual - The timer is not invoked; the caller must update the * progress. */ enum TimerStyle { CountDown, CountUp, Manual }; /** * Constructor for the standard mode where you must specify the main * widget with @ref setMainWidget() . See @see KDialog for further details. * * For the rest of the arguments, See @see KDialog . */ - explicit KTimerDialog( int msec, TimerStyle style=CountDown, QWidget *parent=0, + explicit KTimerDialog( int msec, TimerStyle style=CountDown, QWidget *parent=nullptr, const QString &caption=QString(), int buttonMask=Ok|Apply|Cancel, ButtonCode defaultButton=Ok, bool separator=false, const KGuiItem &user1=KGuiItem(), const KGuiItem &user2=KGuiItem(), const KGuiItem &user3=KGuiItem() ); /** * Destructor. */ ~KTimerDialog() override; /** * Execute the dialog modelessly - see @see QDialog . */ void setVisible( bool visible ) override; /** * Set the refresh interval for the timer progress. Defaults to one second. */ void setRefreshInterval( int msec ); /** * Retrieves the @ref ButtonCode which will be activated once the timer * times out. @see setTimeoutButton */ int timeoutButton() const; /** * Sets the @ref ButtonCode to determine which button will be activated * once the timer times out. @see timeoutButton */ void setTimeoutButton( ButtonCode newButton ); /** * Retrieves the current @ref TimerStyle. @see setTimerStyle */ int timerStyle() const; /** * Sets the @ref TimerStyle. @see timerStyle */ void setTimerStyle( TimerStyle newStyle ); /** * Overridden function which is used to set the main widget of the dialog. * @see KDialog::setMainWidget. */ void setMainWidget( QWidget *widget ); Q_SIGNALS: /** * Signal which is emitted once the timer has timed out. */ void timerTimeout(); public Q_SLOTS: /** * Execute the dialog modally - see @see QDialog . */ int exec() override; private Q_SLOTS: /** * Updates the dialog with the current progress levels. */ void slotUpdateTime( bool update = true ); /** * The internal */ void slotInternalTimeout(); private: /** * Prepares the layout that manages the widgets of the dialog */ void setupLayout(); QTimer *totalTimer; QTimer *updateTimer; int msecRemaining, updateInterval, msecTotal; ButtonCode buttonOnTimeout; TimerStyle tStyle; KHBox *timerWidget; QProgressBar *timerProgress; QLabel *timerLabel; KVBox *mainWidget; class KTimerDialogPrivate; KTimerDialogPrivate *d; }; #endif diff --git a/kcms/cursortheme/kcmcursortheme.cpp b/kcms/cursortheme/kcmcursortheme.cpp index 2c5e0aac6..d29810d7f 100644 --- a/kcms/cursortheme/kcmcursortheme.cpp +++ b/kcms/cursortheme/kcmcursortheme.cpp @@ -1,601 +1,601 @@ /* * Copyright © 2003-2007 Fredrik Höglund * * 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 "kcmcursortheme.h" #include "xcursor/thememodel.h" #include "xcursor/sortproxymodel.h" #include "xcursor/cursortheme.h" #include "xcursor/previewwidget.h" #include "../krdb/krdb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_XFIXES # include #endif K_PLUGIN_FACTORY_WITH_JSON(CursorThemeConfigFactory, "kcm_cursortheme.json", registerPlugin();) CursorThemeConfig::CursorThemeConfig(QObject *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args), m_appliedSize(0), m_preferredSize(0), m_selectedThemeRow(-1), m_originalSelectedThemeRow(-1), m_canInstall(true), m_canResize(true), m_canConfigure(true) { qmlRegisterType("org.kde.private.kcm_cursortheme", 1, 0, "PreviewWidget"); qmlRegisterType(); KAboutData* aboutData = new KAboutData(QStringLiteral("kcm_cursortheme"), i18n("Cursor Theme"), QStringLiteral("1.0"), QString(i18n("Mouse Cursor Theme settings")), KAboutLicense::GPL, i18n("(c) 2003-2007 Fredrik Höglund")); aboutData->addAuthor(i18n("Fredrik Höglund")); aboutData->addAuthor(i18n("Marco Martin")); setAboutData(aboutData); m_model = new CursorThemeModel(this); m_proxyModel = new SortProxyModel(this); m_proxyModel->setSourceModel(m_model); m_proxyModel->setFilterCaseSensitivity(Qt::CaseSensitive); m_proxyModel->sort(NameColumn, Qt::AscendingOrder); m_sizesModel = new QStandardItemModel(this); // Disable the install button if we can't install new themes to ~/.icons, // or Xcursor isn't set up to look for cursor themes there. if (!m_model->searchPaths().contains(QDir::homePath() + "/.icons") || !iconsIsWritable()) { setCanInstall(false); } } CursorThemeConfig::~CursorThemeConfig() { /* */ } void CursorThemeConfig::setCanInstall(bool can) { if (m_canInstall == can) { return; } m_canInstall = can; emit canInstallChanged(); } bool CursorThemeConfig::canInstall() const { return m_canInstall; } void CursorThemeConfig::setCanResize(bool can) { if (m_canResize == can) { return; } m_canResize = can; emit canResizeChanged(); } bool CursorThemeConfig::canResize() const { return m_canResize; } void CursorThemeConfig::setCanConfigure(bool can) { if (m_canConfigure == can) { return; } m_canConfigure = can; emit canConfigureChanged(); } bool CursorThemeConfig::canConfigure() const { return m_canConfigure; } void CursorThemeConfig::setSelectedThemeRow(int row) { if (m_selectedThemeRow == row) { return; } m_selectedThemeRow = row; emit selectedThemeRowChanged(); updateSizeComboBox(); QModelIndex selected = selectedIndex(); if (selected.isValid()) { const CursorTheme *theme = m_proxyModel->theme(selected); } setNeedsSave(m_originalSelectedThemeRow != m_selectedThemeRow || m_originalPreferredSize != m_preferredSize); } int CursorThemeConfig::selectedThemeRow() const { return m_selectedThemeRow; } void CursorThemeConfig::setPreferredSize(int size) { if (m_preferredSize == size) { return; } m_preferredSize = size; emit preferredSizeChanged(); setNeedsSave(m_originalSelectedThemeRow != m_selectedThemeRow || m_originalPreferredSize != m_preferredSize); } int CursorThemeConfig::preferredSize() const { return m_preferredSize; } QAbstractItemModel *CursorThemeConfig::cursorsModel() { return m_proxyModel; } QAbstractItemModel *CursorThemeConfig::sizesModel() { return m_sizesModel; } bool CursorThemeConfig::iconsIsWritable() const { const QFileInfo icons = QFileInfo(QDir::homePath() + "/.icons"); const QFileInfo home = QFileInfo(QDir::homePath()); return ((icons.exists() && icons.isDir() && icons.isWritable()) || (!icons.exists() && home.isWritable())); } void CursorThemeConfig::updateSizeComboBox() { // clear the combo box m_sizesModel->clear(); // refill the combo box and adopt its icon size QModelIndex selected = selectedIndex(); int maxIconWidth = 0; int maxIconHeight = 0; if (selected.isValid()) { const CursorTheme *theme = m_proxyModel->theme(selected); const QList sizes = theme->availableSizes(); QIcon m_icon; // only refill the combobox if there is more that 1 size if (sizes.size() > 1) { int i; QList comboBoxList; QPixmap m_pixmap; // insert the items m_pixmap = theme->createIcon(0); if (m_pixmap.width() > maxIconWidth) { maxIconWidth = m_pixmap.width(); } if (m_pixmap.height() > maxIconHeight) { maxIconHeight = m_pixmap.height(); } QStandardItem *item = new QStandardItem(QIcon(m_pixmap), i18nc("@item:inlistbox size", "Resolution dependent")); item->setData(0); m_sizesModel->appendRow(item); comboBoxList << 0; foreach (i, sizes) { m_pixmap = theme->createIcon(i); if (m_pixmap.width() > maxIconWidth) { maxIconWidth = m_pixmap.width(); } if (m_pixmap.height() > maxIconHeight) { maxIconHeight = m_pixmap.height(); } QStandardItem *item = new QStandardItem(QIcon(m_pixmap), QString::number(i)); item->setData(i); m_sizesModel->appendRow(item); comboBoxList << i; }; // select an item int selectItem = comboBoxList.indexOf(m_preferredSize); // m_preferredSize not available for this theme if (selectItem < 0) { /* Search the value next to m_preferredSize. The first entry (0) is ignored. (If m_preferredSize would have been 0, then we would had found it yet. As m_preferredSize is not 0, we won't default to "automatic size".)*/ int j; int distance; int smallestDistance; selectItem = 1; j = comboBoxList.value(selectItem); smallestDistance = j < m_preferredSize ? m_preferredSize - j : j - m_preferredSize; for (int i = 2; i < comboBoxList.size(); ++i) { j = comboBoxList.value(i); distance = j < m_preferredSize ? m_preferredSize - j : j - m_preferredSize; if (distance < smallestDistance || (distance == smallestDistance && j > m_preferredSize)) { smallestDistance = distance; selectItem = i; }; } }; setPreferredSize(selectItem); }; }; // enable or disable the combobox KConfig c("kcminputrc"); KConfigGroup cg(&c, "Mouse"); if (cg.isEntryImmutable("cursorSize")) { setCanResize(false); } else { setCanResize(m_sizesModel->rowCount() > 0); }; } bool CursorThemeConfig::applyTheme(const CursorTheme *theme, const int size) { // Require the Xcursor version that shipped with X11R6.9 or greater, since // in previous versions the Xfixes code wasn't enabled due to a bug in the // build system (freedesktop bug #975). #if HAVE_XFIXES && XFIXES_MAJOR >= 2 && XCURSOR_LIB_VERSION >= 10105 if (!theme) { return false; } if (!CursorTheme::haveXfixes()) { return false; } QByteArray themeName = QFile::encodeName(theme->name()); // Set up the proper launch environment for newly started apps OrgKdeKLauncherInterface klauncher(QStringLiteral("org.kde.klauncher5"), QStringLiteral("/KLauncher"), QDBusConnection::sessionBus()); klauncher.setLaunchEnv(QStringLiteral("XCURSOR_THEME"), themeName); // Update the Xcursor X resources runRdb(0); // Notify all applications that the cursor theme has changed KGlobalSettings::self()->emitChange(KGlobalSettings::CursorChanged); // Reload the standard cursors QStringList names; // Qt cursors names << "left_ptr" << "up_arrow" << "cross" << "wait" << "left_ptr_watch" << "ibeam" << "size_ver" << "size_hor" << "size_bdiag" << "size_fdiag" << "size_all" << "split_v" << "split_h" << "pointing_hand" << "openhand" << "closedhand" << "forbidden" << "whats_this" << "copy" << "move" << "link"; // X core cursors names << "X_cursor" << "right_ptr" << "hand1" << "hand2" << "watch" << "xterm" << "crosshair" << "left_ptr_watch" << "center_ptr" << "sb_h_double_arrow" << "sb_v_double_arrow" << "fleur" << "top_left_corner" << "top_side" << "top_right_corner" << "right_side" << "bottom_right_corner" << "bottom_side" << "bottom_left_corner" << "left_side" << "question_arrow" << "pirate"; foreach (const QString &name, names) { XFixesChangeCursorByName(QX11Info::display(), theme->loadCursor(name, size), QFile::encodeName(name)); } return true; #else Q_UNUSED(theme) return false; #endif } void CursorThemeConfig::save() { - const CursorTheme *theme = selectedIndex().isValid() ? m_proxyModel->theme(selectedIndex()) : NULL; + const CursorTheme *theme = selectedIndex().isValid() ? m_proxyModel->theme(selectedIndex()) : nullptr; KConfig config("kcminputrc"); KConfigGroup c(&config, "Mouse"); if (theme) { c.writeEntry("cursorTheme", theme->name()); }; c.writeEntry("cursorSize", m_preferredSize); c.sync(); if (!applyTheme(theme, m_preferredSize)) { emit showInfoMessage(i18n("You have to restart the Plasma session for these changes to take effect.")); } m_appliedIndex = selectedIndex(); m_appliedSize = m_preferredSize; m_originalSelectedThemeRow = m_selectedThemeRow; m_originalPreferredSize = m_preferredSize; setNeedsSave(false); } void CursorThemeConfig::load() { // Get the name of the theme libXcursor currently uses QString currentTheme; if (QX11Info::isPlatformX11()) { currentTheme = XcursorGetTheme(QX11Info::display()); } // Get the name of the theme KDE is configured to use KConfig c("kcminputrc"); KConfigGroup cg(&c, "Mouse"); currentTheme = cg.readEntry("cursorTheme", currentTheme); // Find the theme in the listview if (!currentTheme.isEmpty()) { m_appliedIndex = m_proxyModel->findIndex(currentTheme); } else { m_appliedIndex = m_proxyModel->defaultIndex(); } // Disable the listview and the buttons if we're in kiosk mode if (cg.isEntryImmutable("cursorTheme")) { setCanConfigure(false); setCanInstall(false); } // Load cursor size int size = cg.readEntry("cursorSize", 0); if (size <= 0) { m_preferredSize = 0; } else { m_preferredSize = size; } updateSizeComboBox(); // This handles also the kiosk mode m_appliedSize = size; const CursorTheme *theme = m_proxyModel->theme(m_appliedIndex); setSelectedThemeRow(m_appliedIndex.row()); m_originalSelectedThemeRow = m_selectedThemeRow; m_originalPreferredSize = m_preferredSize; setNeedsSave(false); } void CursorThemeConfig::defaults() { QModelIndex defaultIndex = m_proxyModel->findIndex("breeze_cursors"); setSelectedThemeRow(defaultIndex.row()); m_preferredSize = 0; updateSizeComboBox(); setNeedsSave(m_originalSelectedThemeRow != m_selectedThemeRow || m_originalPreferredSize != m_preferredSize); } void CursorThemeConfig::selectionChanged() { updateSizeComboBox(); setNeedsSave(m_originalSelectedThemeRow != m_selectedThemeRow || m_originalPreferredSize != m_preferredSize); //setNeedsSave(m_appliedIndex != selectedIndex()); } QModelIndex CursorThemeConfig::selectedIndex() const { return m_proxyModel->index(m_selectedThemeRow, 0); } void CursorThemeConfig::getNewClicked() { - KNS3::DownloadDialog dialog("xcursor.knsrc", 0); + KNS3::DownloadDialog dialog("xcursor.knsrc", nullptr); if (dialog.exec()) { KNS3::Entry::List list = dialog.changedEntries(); if (list.count() > 0) { m_model->refreshList(); } } } void CursorThemeConfig::installThemeFromFile(const QUrl &url) { if (url.isLocalFile()) { installThemeFile(url.toLocalFile()); return; } m_tempInstallFile.reset(new QTemporaryFile()); if (!m_tempInstallFile->open()) { emit showErrorMessage(i18n("Unable to create a temporary file.")); m_tempInstallFile.reset(); return; } KIO::FileCopyJob *job = KIO::file_copy(url,QUrl::fromLocalFile(m_tempInstallFile->fileName()), -1, KIO::Overwrite); job->uiDelegate()->setAutoErrorHandlingEnabled(true); connect(job, &KIO::FileCopyJob::result, this, [this, url](KJob *job) { if (job->error() != KJob::NoError) { emit showErrorMessage(i18n("Unable to download the icon theme archive: %1", job->errorText())); return; } installThemeFile(m_tempInstallFile->fileName()); m_tempInstallFile.reset(); }); } void CursorThemeConfig::installThemeFile(const QString &path) { KTar archive(path); archive.open(QIODevice::ReadOnly); const KArchiveDirectory *archiveDir = archive.directory(); QStringList themeDirs; // Extract the dir names of the cursor themes in the archive, and // append them to themeDirs foreach(const QString &name, archiveDir->entries()) { const KArchiveEntry *entry = archiveDir->entry(name); if (entry->isDirectory() && entry->name().toLower() != "default") { const KArchiveDirectory *dir = static_cast(entry); if (dir->entry("index.theme") && dir->entry("cursors")) { themeDirs << dir->name(); } } } if (themeDirs.isEmpty()) { emit showErrorMessage(i18n("The file is not a valid icon theme archive.")); return; } // The directory we'll install the themes to QString destDir = QDir::homePath() + "/.icons/"; if (!QDir().mkpath(destDir)) { emit showErrorMessage(i18n("Failed to create 'icons' folder.")); return; }; // Process each cursor theme in the archive foreach (const QString &dirName, themeDirs) { QDir dest(destDir + dirName); if (dest.exists()) { QString question = i18n("A theme named %1 already exists in your icon " "theme folder. Do you want replace it with this one?", dirName); - int answer = KMessageBox::warningContinueCancel(0, question, + int answer = KMessageBox::warningContinueCancel(nullptr, question, i18n("Overwrite Theme?"), KStandardGuiItem::overwrite()); if (answer != KMessageBox::Continue) { continue; } // ### If the theme that's being replaced is the current theme, it // will cause cursor inconsistencies in newly started apps. } // ### Should we check if a theme with the same name exists in a global theme dir? // If that's the case it will effectively replace it, even though the global theme // won't be deleted. Checking for this situation is easy, since the global theme // will be in the listview. Maybe this should never be allowed since it might // result in strange side effects (from the average users point of view). OTOH // a user might want to do this 'upgrade' a global theme. const KArchiveDirectory *dir = static_cast (archiveDir->entry(dirName)); dir->copyTo(dest.path()); m_model->addTheme(dest); } archive.close(); emit showSuccessMessage(i18n("Theme installed successfully.")); m_model->refreshList(); } void CursorThemeConfig::removeTheme(int row) { QModelIndex idx = m_proxyModel->index(row, 0); if (!idx.isValid()) { return; } const CursorTheme *theme = m_proxyModel->theme(idx); // Don't let the user delete the currently configured theme if (idx == m_appliedIndex) { - KMessageBox::sorry(0, i18n("You cannot delete the theme you are currently " + KMessageBox::sorry(nullptr, i18n("You cannot delete the theme you are currently " "using.
You have to switch to another theme first.
")); return; } // Get confirmation from the user QString question = i18n("Are you sure you want to remove the " "%1 cursor theme?
" "This will delete all the files installed by this theme.
", theme->title()); - int answer = KMessageBox::warningContinueCancel(0, question, + int answer = KMessageBox::warningContinueCancel(nullptr, question, i18n("Confirmation"), KStandardGuiItem::del()); if (answer != KMessageBox::Continue) { return; } // Delete the theme from the harddrive KIO::del(QUrl::fromLocalFile(theme->path())); // async // Remove the theme from the model m_proxyModel->removeTheme(idx); // TODO: // Since it's possible to substitute cursors in a system theme by adding a local // theme with the same name, we shouldn't remove the theme from the list if it's // still available elsewhere. We could add a // bool CursorThemeModel::tryAddTheme(const QString &name), and call that, but // since KIO::del() is an asynchronos operation, the theme we're deleting will be // readded to the list again before KIO has removed it. } #include "kcmcursortheme.moc" diff --git a/kcms/cursortheme/xcursor/previewwidget.cpp b/kcms/cursortheme/xcursor/previewwidget.cpp index 3e00e4f18..acebd57dc 100644 --- a/kcms/cursortheme/xcursor/previewwidget.cpp +++ b/kcms/cursortheme/xcursor/previewwidget.cpp @@ -1,316 +1,316 @@ /* * Copyright © 2003-2007 Fredrik Höglund * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include "previewwidget.h" #include #include #include #include #include "cursortheme.h" namespace { // Preview cursors const char * const cursor_names[] = { "left_ptr", "left_ptr_watch", "wait", "pointing_hand", "whats_this", "ibeam", "size_all", "size_fdiag", "cross", "split_h", "size_ver", "size_hor", "size_bdiag", "split_v", }; const int numCursors = 9; // The number of cursors from the above list to be previewed const int cursorSpacing = 20; // Spacing between preview cursors const qreal widgetMinWidth = 10; // The minimum width of the preview widget const qreal widgetMinHeight = 48; // The minimum height of the preview widget } class PreviewCursor { public: PreviewCursor( const CursorTheme *theme, const QString &name, int size ); ~PreviewCursor(); const QPixmap &pixmap() const { return m_pixmap; } int width() const { return m_pixmap.width(); } int height() const { return m_pixmap.height(); } int boundingSize() const { return m_boundingSize; } inline QRect rect() const; void setPosition( const QPoint &p ) { m_pos = p; } void setPosition( int x, int y ) { m_pos = QPoint(x, y); } QPoint position() const { return m_pos; } operator const uint32_t () const { return m_cursor; } operator const QPixmap& () const { return pixmap(); } private: int m_boundingSize; QPixmap m_pixmap; uint32_t m_cursor; QPoint m_pos; }; PreviewCursor::PreviewCursor(const CursorTheme *theme, const QString &name, int size) : m_boundingSize(size > 0 ? size : theme->defaultCursorSize()) { // Create the preview pixmap QImage image = theme->loadImage(name, size); if (image.isNull()) return; m_pixmap = QPixmap::fromImage(image); // Load the cursor m_cursor = theme->loadCursor(name, size); // ### perhaps we should tag the cursor so it doesn't get // replaced when a new theme is applied } PreviewCursor::~PreviewCursor() { if (QX11Info::isPlatformX11() && m_cursor != XCB_CURSOR_NONE) { xcb_free_cursor(QX11Info::connection(), m_cursor); } } QRect PreviewCursor::rect() const { return QRect(m_pos, m_pixmap.size()) .adjusted(-(cursorSpacing / 2), -(cursorSpacing / 2), cursorSpacing / 2, cursorSpacing / 2); } // ------------------------------------------------------------------------------ PreviewWidget::PreviewWidget(QQuickItem *parent) : QQuickPaintedItem(parent), m_currentIndex(-1), m_currentSize(0) { setAcceptHoverEvents(true); - current = NULL; + current = nullptr; } PreviewWidget::~PreviewWidget() { qDeleteAll(list); list.clear(); } void PreviewWidget::setThemeModel(SortProxyModel *themeModel) { if (m_themeModel == themeModel) { return; } m_themeModel = themeModel; emit themeModelChanged(); } SortProxyModel *PreviewWidget::themeModel() { return m_themeModel; } void PreviewWidget::setCurrentIndex(int idx) { if (m_currentIndex == idx) { return; } m_currentIndex = idx; emit currentIndexChanged(); if (!m_themeModel) { return; } const CursorTheme *theme = m_themeModel->theme(m_themeModel->index(idx, 0)); setTheme(theme, m_currentSize); } int PreviewWidget::currentIndex() const { return m_currentIndex; } void PreviewWidget::setCurrentSize(int size) { if (m_currentSize == size) { return; } m_currentSize = size; emit currentSizeChanged(); if (!m_themeModel) { return; } const CursorTheme *theme = m_themeModel->theme(m_themeModel->index(m_currentIndex, 0)); setTheme(theme, size); } int PreviewWidget::currentSize() const { return m_currentSize; } void PreviewWidget::updateImplicitSize() { qreal totalWidth = 0; qreal maxHeight = 0; foreach (const PreviewCursor *c, list) { totalWidth += c->width(); maxHeight = qMax(c->height(), (int)maxHeight); } totalWidth += (list.count() - 1) * cursorSpacing; maxHeight = qMax(maxHeight, widgetMinHeight); setImplicitWidth(qMax(totalWidth, widgetMinWidth)); setImplicitHeight(qMax(height(), maxHeight)); } void PreviewWidget::layoutItems() { if (!list.isEmpty()) { const int spacing = 12; int nextX = spacing; int nextY = spacing; foreach (PreviewCursor *c, list) { c->setPosition(nextX, nextY); nextX += c->boundingSize() + spacing; if (nextX + c->boundingSize() > width()) { nextX = spacing; nextY += c->boundingSize() + spacing; } } } needLayout = false; } void PreviewWidget::setTheme(const CursorTheme *theme, const int size) { qDeleteAll(list); list.clear(); if (theme) { for (int i = 0; i < numCursors; i++) list << new PreviewCursor(theme, cursor_names[i], size); needLayout = true; updateImplicitSize(); } - current = NULL; + current = nullptr; update(); } void PreviewWidget::paint(QPainter *painter) { if (needLayout) layoutItems(); foreach(const PreviewCursor *c, list) { if (c->pixmap().isNull()) continue; painter->drawPixmap(c->position(), *c); } } void PreviewWidget::hoverMoveEvent(QHoverEvent *e) { if (needLayout) layoutItems(); //FIXME: we can't find an handle to the actual window //in the case we are in a QQuickWidget, so we can't do the live preview /* foreach (const PreviewCursor *c, list) { if (c->rect().contains(e->pos())) { if (c != current) { const uint32_t cursor = *c; if (QX11Info::isPlatformX11() && (cursor != XCB_CURSOR_NONE) && window()) { xcb_change_window_attributes(QX11Info::connection(), window()->winId(), XCB_CW_CURSOR, &cursor); } current = c; } return; } } setCursor(Qt::ArrowCursor); current = NULL; */ } void PreviewWidget::hoverLeaveEvent(QHoverEvent *e) { if (window()) { window()->unsetCursor(); } } void PreviewWidget::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { Q_UNUSED(newGeometry) Q_UNUSED(oldGeometry) if (!list.isEmpty()) { needLayout = true; } } diff --git a/kcms/cursortheme/xcursor/thememodel.cpp b/kcms/cursortheme/xcursor/thememodel.cpp index 83714023e..57236ffa0 100644 --- a/kcms/cursortheme/xcursor/thememodel.cpp +++ b/kcms/cursortheme/xcursor/thememodel.cpp @@ -1,426 +1,426 @@ /* * Copyright © 2005-2007 Fredrik Höglund * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. 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 "thememodel.h" #include "xcursortheme.h" #include #include // Check for older version #if !defined(XCURSOR_LIB_MAJOR) && defined(XCURSOR_MAJOR) # define XCURSOR_LIB_MAJOR XCURSOR_MAJOR # define XCURSOR_LIB_MINOR XCURSOR_MINOR #endif CursorThemeModel::CursorThemeModel(QObject *parent) : QAbstractTableModel(parent) { insertThemes(); } CursorThemeModel::~CursorThemeModel() { qDeleteAll(list); list.clear(); } QHash CursorThemeModel::roleNames() const { QHash roleNames = QAbstractTableModel::roleNames(); roleNames[CursorTheme::DisplayDetailRole] = "description"; roleNames[CursorTheme::IsWritableRole] = "isWritable"; return roleNames; } void CursorThemeModel::refreshList() { beginResetModel(); qDeleteAll(list); list.clear(); endResetModel(); insertThemes(); } QVariant CursorThemeModel::headerData(int section, Qt::Orientation orientation, int role) const { // Only provide text for the headers if (role != Qt::DisplayRole) return QVariant(); // Horizontal header labels if (orientation == Qt::Horizontal) { switch (section) { case NameColumn: return i18n("Name"); case DescColumn: return i18n("Description"); default: return QVariant(); } } // Numbered vertical header lables return QString(section); } QVariant CursorThemeModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() < 0 || index.row() >= list.count()) return QVariant(); const CursorTheme *theme = list.at(index.row()); // Text label if (role == Qt::DisplayRole) { switch (index.column()) { case NameColumn: return theme->title(); case DescColumn: return theme->description(); default: return QVariant(); } } // Description for the first name column if (role == CursorTheme::DisplayDetailRole && index.column() == NameColumn) return theme->description(); // Icon for the name column if (role == Qt::DecorationRole && index.column() == NameColumn) return theme->icon(); if (role == CursorTheme::IsWritableRole) { return theme->isWritable(); } return QVariant(); } void CursorThemeModel::sort(int column, Qt::SortOrder order) { Q_UNUSED(column); Q_UNUSED(order); // Sorting of the model isn't implemented, as the KCM currently uses // a sorting proxy model. } const CursorTheme *CursorThemeModel::theme(const QModelIndex &index) { if (!index.isValid()) - return NULL; + return nullptr; if (index.row() < 0 || index.row() >= list.count()) - return NULL; + return nullptr; return list.at(index.row()); } QModelIndex CursorThemeModel::findIndex(const QString &name) { uint hash = qHash(name); for (int i = 0; i < list.count(); i++) { const CursorTheme *theme = list.at(i); if (theme->hash() == hash) return index(i, 0); } return QModelIndex(); } QModelIndex CursorThemeModel::defaultIndex() { return findIndex(defaultName); } const QStringList CursorThemeModel::searchPaths() { if (!baseDirs.isEmpty()) return baseDirs; #if XCURSOR_LIB_MAJOR == 1 && XCURSOR_LIB_MINOR < 1 // These are the default paths Xcursor will scan for cursor themes QString path("~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons"); // If XCURSOR_PATH is set, use that instead of the default path char *xcursorPath = std::getenv("XCURSOR_PATH"); if (xcursorPath) path = xcursorPath; #else // Get the search path from Xcursor QString path = XcursorLibraryPath(); #endif // Separate the paths baseDirs = path.split(':', QString::SkipEmptyParts); // Remove duplicates QMutableStringListIterator i(baseDirs); while (i.hasNext()) { const QString path = i.next(); QMutableStringListIterator j(i); while (j.hasNext()) if (j.next() == path) j.remove(); } // Expand all occurrences of ~/ to the home dir baseDirs.replaceInStrings(QRegExp("^~\\/"), QDir::home().path() + '/'); return baseDirs; } bool CursorThemeModel::hasTheme(const QString &name) const { const uint hash = qHash(name); foreach (const CursorTheme *theme, list) if (theme->hash() == hash) return true; return false; } bool CursorThemeModel::isCursorTheme(const QString &theme, const int depth) { // Prevent infinite recursion if (depth > 10) return false; // Search each icon theme directory for 'theme' foreach (const QString &baseDir, searchPaths()) { QDir dir(baseDir); if (!dir.exists() || !dir.cd(theme)) continue; // If there's a cursors subdir, we'll assume this is a cursor theme if (dir.exists(QStringLiteral("cursors"))) return true; // If the theme doesn't have an index.theme file, it can't inherit any themes. if (!dir.exists(QStringLiteral("index.theme"))) continue; // Open the index.theme file, so we can get the list of inherited themes KConfig config(dir.path() + "/index.theme", KConfig::NoGlobals); KConfigGroup cg(&config, "Icon Theme"); // Recurse through the list of inherited themes, to check if one of them // is a cursor theme. QStringList inherits = cg.readEntry("Inherits", QStringList()); foreach (const QString &inherit, inherits) { // Avoid possible DoS if (inherit == theme) continue; if (isCursorTheme(inherit, depth + 1)) return true; } } return false; } bool CursorThemeModel::handleDefault(const QDir &themeDir) { QFileInfo info(themeDir.path()); // If "default" is a symlink if (info.isSymLink()) { QFileInfo target(info.symLinkTarget()); if (target.exists() && (target.isDir() || target.isSymLink())) defaultName = target.fileName(); return true; } // If there's no cursors subdir, or if it's empty if (!themeDir.exists(QStringLiteral("cursors")) || QDir(themeDir.path() + "/cursors") .entryList(QDir::Files | QDir::NoDotAndDotDot ).isEmpty()) { if (themeDir.exists(QStringLiteral("index.theme"))) { XCursorTheme theme(themeDir); if (!theme.inherits().isEmpty()) defaultName = theme.inherits().at(0); } return true; } defaultName = QStringLiteral("default"); return false; } void CursorThemeModel::processThemeDir(const QDir &themeDir) { bool haveCursors = themeDir.exists(QStringLiteral("cursors")); // Special case handling of "default", since it's usually either a // symlink to another theme, or an empty theme that inherits another // theme. if (defaultName.isNull() && themeDir.dirName() == QLatin1String("default")) { if (handleDefault(themeDir)) return; } // If the directory doesn't have a cursors subdir and lacks an // index.theme file it can't be a cursor theme. if (!themeDir.exists(QStringLiteral("index.theme")) && !haveCursors) return; // Create a cursor theme object for the theme dir XCursorTheme *theme = new XCursorTheme(themeDir); // Skip this theme if it's hidden. if (theme->isHidden()) { delete theme; return; } // If there's no cursors subdirectory we'll do a recursive scan // to check if the theme inherits a theme with one. if (!haveCursors) { bool foundCursorTheme = false; foreach (const QString &name, theme->inherits()) if ((foundCursorTheme = isCursorTheme(name))) break; if (!foundCursorTheme) { delete theme; return; } } // Append the theme to the list beginInsertRows(QModelIndex(), list.size(), list.size()); list.append(theme); endInsertRows(); } void CursorThemeModel::insertThemes() { // Scan each base dir for Xcursor themes and add them to the list. foreach (const QString &baseDir, searchPaths()) { QDir dir(baseDir); if (!dir.exists()) continue; // Process each subdir in the directory foreach (const QString &name, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { // Don't process the theme if a theme with the same name already exists // in the list. Xcursor will pick the first one it finds in that case, // and since we use the same search order, the one Xcursor picks should // be the one already in the list. if (hasTheme(name) || !dir.cd(name)) continue; processThemeDir(dir); dir.cdUp(); // Return to the base dir } } // The theme Xcursor will end up using if no theme is configured if (defaultName.isNull() || !hasTheme(defaultName)) defaultName = QStringLiteral("KDE_Classic"); } bool CursorThemeModel::addTheme(const QDir &dir) { XCursorTheme *theme = new XCursorTheme(dir); // Don't add the theme to the list if it's hidden if (theme->isHidden()) { delete theme; return false; } // ### If the theme is hidden, the user will probably find it strange that it // doesn't appear in the list view. There also won't be a way for the user // to delete the theme using the KCM. Perhaps a warning about this should // be issued, and the user be given a chance to undo the installation. // If an item with the same name already exists in the list, // we'll remove it before inserting the new one. for (int i = 0; i < list.count(); i++) { if (list.at(i)->hash() == theme->hash()) { removeTheme(index(i, 0)); break; } } // Append the theme to the list beginInsertRows(QModelIndex(), rowCount(), rowCount()); list.append(theme); endInsertRows(); return true; } void CursorThemeModel::removeTheme(const QModelIndex &index) { if (!index.isValid()) return; beginRemoveRows(QModelIndex(), index.row(), index.row()); delete list.takeAt(index.row()); endRemoveRows(); } diff --git a/kcms/dateandtime/dtime.h b/kcms/dateandtime/dtime.h index ac4321667..ce8bccd0e 100644 --- a/kcms/dateandtime/dtime.h +++ b/kcms/dateandtime/dtime.h @@ -1,126 +1,126 @@ /* * dtime.h * * Copyright (C) 1998 Luca Montecchiani * * 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. * */ #ifndef dtime_included #define dtime_included #include "ui_dateandtime.h" #include #include #include #include #include //Added by qt3to4: #include #include #include class Kclock; class QTimeEdit; namespace Plasma { class Svg; } class Dtime : public QWidget, public Ui::DateAndTime { Q_OBJECT public: Dtime( QWidget *parent, bool haveTimedated); void processHelperErrors( int code ); void load(); QString selectedTimeZone() const; QStringList ntpServers() const; bool ntpEnabled() const; QDateTime userTime() const; QString quickHelp() const; Q_SIGNALS: void timeChanged(bool); private Q_SLOTS: void configChanged(); void serverTimeCheck(); void timeout(); void set_time(); void changeDate(const QDate&); private: void currentZone(); void findNTPutility(); QString ntpUtility; QTimeEdit *timeEdit; Kclock *kclock; QTime time; QDate date; QTimer internalTimer; QString timeServer; int BufI; bool refresh; bool ontimeout; bool m_haveTimedated; }; class Kclock : public QWidget { Q_OBJECT public: - Kclock( QWidget *parent=0 ); + Kclock( QWidget *parent=nullptr ); ~Kclock() override; void setTime(const QTime&); protected: void paintEvent( QPaintEvent *event ) override; void showEvent( QShowEvent *event ) override; void resizeEvent( QResizeEvent *event ) override; private: void setClockSize(const QSize &size); void drawHand(QPainter *p, const QRect &rect, const qreal verticalTranslation, const qreal rotation, const QString &handName); void paintInterface(QPainter *p, const QRect &rect); private: QTime time; Plasma::Svg *m_theme; enum RepaintCache { RepaintNone, RepaintAll, RepaintHands }; RepaintCache m_repaintCache; QPixmap m_faceCache; QPixmap m_handsCache; QPixmap m_glassCache; qreal m_verticalTranslation; }; #endif // dtime_included diff --git a/kcms/dateandtime/helper.cpp b/kcms/dateandtime/helper.cpp index 76f8727a5..7f19b9014 100644 --- a/kcms/dateandtime/helper.cpp +++ b/kcms/dateandtime/helper.cpp @@ -1,265 +1,265 @@ /* * tzone.cpp * * Copyright (C) 1998 Luca Montecchiani * * 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. * */ /* A helper that's run using KAuth and does the system modifications. */ #include "helper.h" #include #include #include #include #include #include #include #include #include #include #include #if defined(USE_SOLARIS) #include #include #include #include #endif // We cannot rely on the $PATH environment variable, because D-Bus activation // clears it. So we have to use a reasonable default. static const QString exePath = QStringLiteral("/usr/sbin:/usr/bin:/sbin:/bin"); int ClockHelper::ntp( const QStringList& ntpServers, bool ntpEnabled ) { int ret = 0; // write to the system config file QFile config_file(KDE_CONFDIR "/kcmclockrc"); if(!config_file.exists()) { config_file.open(QIODevice::WriteOnly); config_file.close(); config_file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther); } KConfig _config(config_file.fileName(), KConfig::SimpleConfig); KConfigGroup config(&_config, "NTP"); config.writeEntry("servers", ntpServers ); config.writeEntry("enabled", ntpEnabled ); QString ntpUtility = QStandardPaths::findExecutable(QStringLiteral("ntpdate")); if (ntpUtility.isEmpty()) { ntpUtility = QStandardPaths::findExecutable(QStringLiteral("rdate")); } if ( ntpEnabled && !ntpUtility.isEmpty() ) { // NTP Time setting QString timeServer = ntpServers.first(); if( timeServer.indexOf( QRegExp(QStringLiteral(".*\\(.*\\)$")) ) != -1 ) { timeServer.remove( QRegExp(QStringLiteral(".*\\("))); timeServer.remove( QRegExp(QStringLiteral("\\).*"))); // Would this be better?: s/^.*\(([^)]*)\).*$/\1/ } KProcess proc; proc << ntpUtility << timeServer; if ( proc.execute() != 0 ) { ret |= NTPError; } else { toHwclock(); } } else if( ntpEnabled ) { ret |= NTPError; } return ret; } int ClockHelper::date( const QString& newdate, const QString& olddate ) { struct timeval tv; - tv.tv_sec = newdate.toULong() - olddate.toULong() + time(0); + tv.tv_sec = newdate.toULong() - olddate.toULong() + time(nullptr); tv.tv_usec = 0; - if (settimeofday(&tv, 0)) { + if (settimeofday(&tv, nullptr)) { return DateError; } toHwclock(); return 0; } // on non-Solaris systems which do not use /etc/timezone? int ClockHelper::tz( const QString& selectedzone ) { int ret = 0; //only allow letters, numbers hyphen underscore plus and forward slash //allowed pattern taken from time-util.c in systemd if (!QRegExp(QStringLiteral("[a-zA-Z0-9-_+/]*")).exactMatch(selectedzone)) { return ret; } QString val; #if defined(USE_SOLARIS) // MARCO KTemporaryFile tf; tf.setPrefix("kde-tzone"); tf.open(); QTextStream ts(&tf); QFile fTimezoneFile(INITFILE); bool updatedFile = false; if (fTimezoneFile.open(QIODevice::ReadOnly)) { bool found = false; QTextStream is(&fTimezoneFile); for (QString line = is.readLine(); !line.isNull(); line = is.readLine()) { if (line.find("TZ=") == 0) { ts << "TZ=" << selectedzone << endl; found = true; } else { ts << line << endl; } } if (!found) { ts << "TZ=" << selectedzone << endl; } updatedFile = true; fTimezoneFile.close(); } if (updatedFile) { ts.device()->reset(); fTimezoneFile.remove(); if (fTimezoneFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream os(&fTimezoneFile); for (QString line = ts->readLine(); !line.isNull(); line = ts->readLine()) { os << line << endl; } fchmod(fTimezoneFile.handle(), S_IXUSR | S_IRUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); fTimezoneFile.close(); } } val = selectedzone; #else QString tz = "/usr/share/zoneinfo/" + selectedzone; if (QFile::exists(tz)) { // make sure the new TZ really exists QFile::remove(QStringLiteral("/etc/localtime")); } else { return TimezoneError; } if (!QFile::link(tz, QStringLiteral("/etc/localtime"))) { // fail if we can't setup the new timezone return TimezoneError; } QFile fTimezoneFile(QStringLiteral("/etc/timezone")); if (fTimezoneFile.exists() && fTimezoneFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream t(&fTimezoneFile); t << selectedzone; fTimezoneFile.close(); } #endif // !USE_SOLARIS val = ':' + selectedzone; setenv("TZ", val.toLocal8Bit().constData(), 1); tzset(); return ret; } int ClockHelper::tzreset() { #if !defined(USE_SOLARIS) // Do not update the System! unlink( "/etc/timezone" ); unlink( "/etc/localtime" ); setenv("TZ", "", 1); tzset(); #endif // !USE SOLARIS return 0; } void ClockHelper::toHwclock() { QString hwclock = KStandardDirs::findExe(QStringLiteral("hwclock"), exePath); if (!hwclock.isEmpty()) { KProcess::execute(hwclock, QStringList() << QStringLiteral("--systohc")); } } ActionReply ClockHelper::save(const QVariantMap &args) { bool _ntp = args.value(QStringLiteral("ntp")).toBool(); bool _date = args.value(QStringLiteral("date")).toBool(); bool _tz = args.value(QStringLiteral("tz")).toBool(); bool _tzreset = args.value(QStringLiteral("tzreset")).toBool(); KComponentData data( "kcmdatetimehelper" ); int ret = 0; // error code // The order here is important if( _ntp ) ret |= ntp( args.value(QStringLiteral("ntpServers")).toStringList(), args.value(QStringLiteral("ntpEnabled")).toBool()); if( _date ) ret |= date( args.value(QStringLiteral("newdate")).toString(), args.value(QStringLiteral("olddate")).toString() ); if( _tz ) ret |= tz( args.value(QStringLiteral("tzone")).toString() ); if( _tzreset ) ret |= tzreset(); if (ret == 0) { return ActionReply::SuccessReply(); } else { ActionReply reply(ActionReply::HelperErrorReply()); reply.setErrorCode(static_cast(ret)); return reply; } } KAUTH_HELPER_MAIN("org.kde.kcontrol.kcmclock", ClockHelper) diff --git a/kcms/dateandtime/main.cpp b/kcms/dateandtime/main.cpp index 10cfab1fa..162450a48 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"))) { 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->setMargin(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(0)); + 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/fonts/fonts.cpp b/kcms/fonts/fonts.cpp index b8695858e..3ce9cdac0 100644 --- a/kcms/fonts/fonts.cpp +++ b/kcms/fonts/fonts.cpp @@ -1,711 +1,711 @@ /* Copyright 1997 Mark Donohoe Copyright 1999 Lars Knoll Copyright 2000 Rik Hemsley Copyright 2015 Antonis Tsiapaliokas Copyright 2017 Marco Martin Ported to kcontrol2 by Geert Jansen. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This 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 "fonts.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../krdb/krdb.h" #include "previewimageprovider.h" /**** DLL Interface ****/ K_PLUGIN_FACTORY_WITH_JSON(KFontsFactory, "kcm_fonts.json", registerPlugin();) //from KFontRequester // Determine if the font with given properties is available on the system, // otherwise find and return the best fitting combination. static QFont nearestExistingFont(const QFont &font) { QFontDatabase dbase; // Initialize font data according to given font object. QString family = font.family(); QString style = dbase.styleString(font); qreal size = font.pointSizeF(); // Check if the family exists. const QStringList families = dbase.families(); if (!families.contains(family)) { // Chose another family. family = QFontInfo(font).family(); // the nearest match if (!families.contains(family)) { family = families.count() ? families.at(0) : QStringLiteral("fixed"); } } // Check if the family has the requested style. // Easiest by piping it through font selection in the database. QString retStyle = dbase.styleString(dbase.font(family, style, 10)); style = retStyle; // Check if the family has the requested size. // Only for bitmap fonts. if (!dbase.isSmoothlyScalable(family, style)) { QList sizes = dbase.smoothSizes(family, style); if (!sizes.contains(size)) { // Find nearest available size. int mindiff = 1000; int refsize = size; Q_FOREACH (int lsize, sizes) { int diff = qAbs(refsize - lsize); if (mindiff > diff) { mindiff = diff; size = lsize; } } } } // Select the font with confirmed properties. QFont result = dbase.font(family, style, int(size)); if (dbase.isSmoothlyScalable(family, style) && result.pointSize() == floor(size)) { result.setPointSizeF(size); } return result; } /**** FontAASettings ****/ #if defined(HAVE_FONTCONFIG) && defined (HAVE_X11) FontAASettings::FontAASettings(QObject *parent) : QObject(parent) , m_subPixelOptionsModel(new QStandardItemModel(this)) , m_hintingOptionsModel(new QStandardItemModel(this)) { for (int t = KXftConfig::SubPixel::NotSet; t <= KXftConfig::SubPixel::Vbgr; ++t) { QStandardItem *item = new QStandardItem(KXftConfig::description((KXftConfig::SubPixel::Type)t)); m_subPixelOptionsModel->appendRow(item); } for (int s = KXftConfig::Hint::NotSet; s <= KXftConfig::Hint::Full; ++s) { QStandardItem * item = new QStandardItem(KXftConfig::description((KXftConfig::Hint::Style)s)); m_hintingOptionsModel->appendRow(item); } } void FontAASettings::load() { double from, to; KXftConfig xft; if (xft.getExcludeRange(from, to)) { m_excludeFrom = from; m_excludeTo = to; setExclude(true); } else { m_excludeFrom = 8; m_excludeTo = 15; setExclude(false); } m_excludeFromOriginal = m_excludeFrom; m_excludeToOriginal = m_excludeTo; excludeToChanged(); excludeFromChanged(); KXftConfig::SubPixel::Type spType; xft.getSubPixelType(spType); setSubPixelCurrentIndex(spType); m_subPixelCurrentIndexOriginal = spType; KXftConfig::Hint::Style hStyle; if (!xft.getHintStyle(hStyle) || KXftConfig::Hint::NotSet == hStyle) { KConfig kglobals("kdeglobals", KConfig::NoGlobals); hStyle = KXftConfig::Hint::NotSet; xft.setHintStyle(hStyle); KConfigGroup(&kglobals, "General").writeEntry("XftHintStyle", KXftConfig::toStr(hStyle)); kglobals.sync(); runRdb(KRdbExportXftSettings | KRdbExportGtkTheme); } setHintingCurrentIndex(hStyle); m_hintingCurrentIndexOriginal = hStyle; KConfig _cfgfonts("kcmfonts"); KConfigGroup cfgfonts(&_cfgfonts, "General"); int dpicfg; if (KWindowSystem::isPlatformWayland()) { dpicfg = cfgfonts.readEntry("forceFontDPIWayland", 0); } else { dpicfg = cfgfonts.readEntry("forceFontDPI", 0); } if (dpicfg <= 0) { m_dpiOriginal = 0; } else { m_dpiOriginal = dpicfg; }; setDpi(dpicfg); KSharedConfig::Ptr config = KSharedConfig::openConfig("kdeglobals"); KConfigGroup cg(config, "General"); if (cfgfonts.readEntry("dontChangeAASettings", true)) { setAntiAliasing(1); //AASystem } else if (cg.readEntry("XftAntialias", true)) { setAntiAliasing(0); //AAEnabled } else { setAntiAliasing(2); //AADisabled } m_antiAliasingOriginal = m_antiAliasing; } bool FontAASettings::save(KXftConfig::AntiAliasing::State aaState) { KXftConfig xft; KConfig kglobals("kdeglobals", KConfig::NoGlobals); KConfigGroup grp(&kglobals, "General"); xft.setAntiAliasing(aaState); if (m_exclude) { xft.setExcludeRange(m_excludeFrom, m_excludeTo); } else { xft.setExcludeRange(0, 0); } KXftConfig::SubPixel::Type spType = (KXftConfig::SubPixel::Type)m_subPixelCurrentIndex; xft.setSubPixelType(spType); grp.writeEntry("XftSubPixel", KXftConfig::toStr(spType)); if (aaState == KXftConfig::AntiAliasing::NotSet) { grp.revertToDefault("XftAntialias"); } else { grp.writeEntry("XftAntialias", aaState == KXftConfig::AntiAliasing::Enabled); } bool mod = false; KXftConfig::Hint::Style hStyle = (KXftConfig::Hint::Style)m_hintingCurrentIndex; xft.setHintStyle(hStyle); QString hs(KXftConfig::toStr(hStyle)); if (hs != grp.readEntry("XftHintStyle")) { if (KXftConfig::Hint::NotSet == hStyle) { grp.revertToDefault("XftHintStyle"); } else { grp.writeEntry("XftHintStyle", hs); } } mod = true; kglobals.sync(); if (!mod) { mod = xft.changed(); } xft.apply(); KConfig _cfgfonts("kcmfonts"); KConfigGroup cfgfonts(&_cfgfonts, "General"); if (KWindowSystem::isPlatformWayland()) { cfgfonts.writeEntry("forceFontDPIWayland", m_dpi); } else { cfgfonts.writeEntry("forceFontDPI", m_dpi); } cfgfonts.sync(); #if HAVE_X11 // if the setting is reset in the module, remove the dpi value, // otherwise don't explicitly remove it and leave any possible system-wide value if (m_dpi == 0 && m_dpiOriginal != 0 && !KWindowSystem::isPlatformWayland()) { QProcess proc; proc.setProcessChannelMode(QProcess::ForwardedChannels); proc.start("xrdb", QStringList() << "-quiet" << "-remove" << "-nocpp"); if (proc.waitForStarted()) { proc.write(QByteArray("Xft.dpi\n")); proc.closeWriteChannel(); proc.waitForFinished(); } } #endif QApplication::processEvents(); // Process font change ourselves // Don't overwrite global settings unless explicitly asked for - e.g. the system // fontconfig setup may be much more complex than this module can provide. // TODO: With AASystem the changes already made by this module should be reverted somehow. #if defined(HAVE_FONTCONFIG) && defined (HAVE_X11) if (mod || (m_antiAliasing != m_antiAliasingOriginal) || m_dpi != m_dpiOriginal) { - KMessageBox::information(0, + KMessageBox::information(nullptr, i18n( "

Some changes such as anti-aliasing or DPI will only affect newly started applications.

" ), i18n("Font Settings Changed"), "FontSettingsChanged"); m_antiAliasingOriginal = m_antiAliasing; m_dpiOriginal = m_dpi; } #else #if HAVE_X11 if (m_dpi != m_dpiOriginal) { KMessageBox::information(0, i18n( "

Some changes such as DPI will only affect newly started applications.

" ), i18n("Font Settings Changed"), "FontSettingsChanged"); m_dpiOriginal = m_dpi; } #endif #endif m_excludeToOriginal = m_excludeTo; m_excludeFromOriginal = m_excludeFrom; m_subPixelCurrentIndexOriginal = m_subPixelCurrentIndex; m_hintingCurrentIndexOriginal = m_hintingCurrentIndex; return mod; } void FontAASettings::defaults() { setExcludeTo(15); setExcludeFrom(8); setAntiAliasing(1); m_antiAliasingOriginal = m_antiAliasing; setDpi(0); setSubPixelCurrentIndex(KXftConfig::SubPixel::NotSet); setHintingCurrentIndex(KXftConfig::Hint::NotSet); } #endif void FontAASettings::setExclude(bool exclude) { if (exclude == m_exclude) { return; } m_exclude = exclude; emit excludeChanged(); } bool FontAASettings::exclude() const { return m_exclude; } void FontAASettings::setExcludeTo(const int &excludeTo) { if (m_excludeTo == excludeTo) { return; } m_excludeTo = excludeTo; emit excludeToChanged(); } int FontAASettings::excludeTo() const { return m_excludeTo; } void FontAASettings::setExcludeFrom(const int &excludeTo) { if (m_excludeFrom == excludeTo) { return; } m_excludeFrom = excludeTo; emit excludeToChanged(); } int FontAASettings::excludeFrom() const { return m_excludeFrom; } void FontAASettings::setAntiAliasing(const int &antiAliasing) { if (m_antiAliasing == antiAliasing) { return; } m_antiAliasing = antiAliasing; emit aliasingChanged(); } int FontAASettings::antiAliasing() const { return m_antiAliasing; } void FontAASettings::setDpi(const int &dpi) { if (m_dpi == dpi) { return; } m_dpi = dpi; emit dpiChanged(); } int FontAASettings::dpi() const { return m_dpi; } void FontAASettings::setSubPixelCurrentIndex(int idx) { if (m_subPixelCurrentIndex == idx) { return; } m_subPixelCurrentIndex = idx; emit subPixelCurrentIndexChanged(); } int FontAASettings::subPixelCurrentIndex() { return m_subPixelCurrentIndex; } void FontAASettings::setHintingCurrentIndex(int idx) { if (m_hintingCurrentIndex == idx) { return; } m_hintingCurrentIndex = idx; emit hintingCurrentIndexChanged(); } int FontAASettings::hintingCurrentIndex() { return m_hintingCurrentIndex; } bool FontAASettings::needsSave() const { return m_excludeTo != m_excludeToOriginal || m_excludeFrom != m_excludeFromOriginal || m_antiAliasing != m_antiAliasingOriginal || m_dpi != m_dpiOriginal || m_subPixelCurrentIndex != m_subPixelCurrentIndexOriginal || m_hintingCurrentIndex != m_hintingCurrentIndexOriginal; } /**** KFonts ****/ KFonts::KFonts(QObject *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args) , m_fontAASettings(new FontAASettings(this)) { qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); KAboutData* about = new KAboutData("kcm_fonts", i18n("Configure Fonts"), "0.1", QString(), KAboutLicense::LGPL); about->addAuthor(i18n("Antonis Tsiapaliokas"), QString(), "antonis.tsiapaliokas@kde.org"); setAboutData(about); qmlRegisterType(); setButtons(Apply | Default); auto updateState = [this]() { setNeedsSave(m_fontAASettings->needsSave()); }; connect(m_fontAASettings, &FontAASettings::subPixelCurrentIndexChanged, this, updateState); connect(m_fontAASettings, &FontAASettings::hintingCurrentIndexChanged, this, updateState); connect(m_fontAASettings, &FontAASettings::excludeToChanged, this, updateState); connect(m_fontAASettings, &FontAASettings::antiAliasingChanged, this, updateState); connect(m_fontAASettings, &FontAASettings::aliasingChanged, this, updateState); connect(m_fontAASettings, &FontAASettings::dpiChanged, this, updateState); } KFonts::~KFonts() { } void KFonts::defaults() { #ifdef Q_OS_MAC setGeneralFont(QFont("Lucida Grande", 13)); setMenuFont(QFont("Lucida Grande", 13)); setFixedWidthFont(QFont("Monaco", 10)); setToolbarFont(QFont("Lucida Grande", 11)); setSmallFont(QFont("Lucida Grande", 9)); setWindowTitleFont(QFont("Lucida Grande", 14)); #else setGeneralFont(QFont("Noto Sans", 10)); setMenuFont(QFont("Noto Sans", 10)); setFixedWidthFont(QFont("Hack", 9)); setToolbarFont(QFont("Noto Sans", 10)); setSmallFont(QFont("Noto Sans", 8)); setWindowTitleFont(QFont("Noto Sans", 10)); #endif m_fontAASettings->defaults(); } void KFonts::load() { KSharedConfig::Ptr config = KSharedConfig::openConfig("kdeglobals"); KConfigGroup cg(config, "General"); m_generalFont = m_generalFontOriginal = nearestExistingFont(cg.readEntry("font", m_defaultFont)); m_fixedWidthFont = m_fixedWidthFontOriginal = nearestExistingFont(cg.readEntry("fixed", QFont("Hack", 9))); m_smallFont = m_smallFontOriginal = nearestExistingFont(cg.readEntry("smallestReadableFont", m_defaultFont)); m_toolbarFont = m_toolbarFontOriginal = nearestExistingFont(cg.readEntry("toolBarFont", m_defaultFont)); m_menuFont = m_menuFontOriginal = nearestExistingFont(cg.readEntry("menuFont", m_defaultFont)); cg = KConfigGroup(config, "WM"); m_windowTitleFont = m_windowTitleFontOriginal = nearestExistingFont(cg.readEntry("activeFont", m_defaultFont)); engine()->addImageProvider("preview", new PreviewImageProvider(generalFont())); emit generalFontChanged(); emit fixedWidthFontChanged(); emit smallFontChanged(); emit toolbarFontChanged(); emit menuFontChanged(); emit windowTitleFontChanged(); m_fontAASettings->load(); setNeedsSave(false); } void KFonts::save() { KSharedConfig::Ptr config = KSharedConfig::openConfig("kdeglobals"); KConfigGroup cg(config, "General"); cg.writeEntry("font", m_generalFont.toString()); cg.writeEntry("fixed", m_fixedWidthFont.toString()); cg.writeEntry("smallestReadableFont", m_smallFont.toString()); cg.writeEntry("toolBarFont", m_toolbarFont.toString()); cg.writeEntry("menuFont", m_menuFont.toString()); cg.sync(); cg = KConfigGroup(config, "WM"); cg.writeEntry("activeFont", m_windowTitleFont.toString()); cg.sync(); m_defaultFontOriginal = m_defaultFont; m_generalFontOriginal = m_generalFont; m_fixedWidthFontOriginal = m_fixedWidthFont; m_smallFontOriginal = m_smallFont; m_toolbarFontOriginal = m_toolbarFont; m_menuFontOriginal = m_menuFont; m_windowTitleFontOriginal = m_windowTitleFont; KConfig _cfgfonts("kcmfonts"); KConfigGroup cfgfonts(&_cfgfonts, "General"); FontAASettings::AASetting aaSetting = (FontAASettings::AASetting)m_fontAASettings->antiAliasing(); cfgfonts.writeEntry("dontChangeAASettings", aaSetting == FontAASettings::AASystem); if (aaSetting == FontAASettings::AAEnabled) { m_fontAASettings->save(KXftConfig::AntiAliasing::Enabled); } else if (aaSetting == FontAASettings::AADisabled) { m_fontAASettings->save(KXftConfig::AntiAliasing::Disabled); } else { m_fontAASettings->save(KXftConfig::AntiAliasing::NotSet); } KGlobalSettings::self()->emitChange(KGlobalSettings::FontChanged); runRdb(KRdbExportXftSettings | KRdbExportGtkTheme); emit fontsHaveChanged(); setNeedsSave(false); } void KFonts::updateNeedsSave() { setNeedsSave(m_defaultFontOriginal != m_defaultFont || m_generalFontOriginal != m_generalFont || m_fixedWidthFontOriginal != m_fixedWidthFont || m_smallFontOriginal != m_smallFont || m_toolbarFontOriginal != m_toolbarFont || m_menuFontOriginal != m_menuFont || m_windowTitleFontOriginal != m_windowTitleFont || m_fontAASettings->needsSave()); } void KFonts::setGeneralFont(const QFont &font) { if (m_generalFont == font) { return; } m_generalFont = font; emit generalFontChanged(); updateNeedsSave(); } QFont KFonts::generalFont() const { return m_generalFont; } void KFonts::setFixedWidthFont(const QFont &font) { if (m_fixedWidthFont == font) { return; } m_fixedWidthFont = font; emit fixedWidthFontChanged(); updateNeedsSave(); } QFont KFonts::fixedWidthFont() const { return m_fixedWidthFont; } void KFonts::setSmallFont(const QFont &font) { if (m_smallFont == font) { return; } m_smallFont = font; emit smallFontChanged(); updateNeedsSave(); } QFont KFonts::smallFont() const { return m_smallFont; } void KFonts::setToolbarFont(const QFont &font) { if (m_toolbarFont == font) { return; } m_toolbarFont = font; emit toolbarFontChanged(); updateNeedsSave(); } QFont KFonts::toolbarFont() const { return m_toolbarFont; } void KFonts::setMenuFont(const QFont &font) { if (m_menuFont == font) { return; } m_menuFont = font; emit menuFontChanged(); updateNeedsSave(); } QFont KFonts::menuFont() const { return m_menuFont; } void KFonts::setWindowTitleFont(const QFont &font) { if (m_windowTitleFont == font) { return; } m_windowTitleFont = font; emit windowTitleFontChanged(); updateNeedsSave(); } QFont KFonts::windowTitleFont() const { return m_windowTitleFont; } void KFonts::adjustAllFonts() { QFont font = m_generalFont; - KFontChooser::FontDiffFlags fontDiffFlags = 0; + KFontChooser::FontDiffFlags fontDiffFlags = nullptr; int ret = KFontDialog::getFontDiff(font, fontDiffFlags, KFontChooser::NoDisplayFlags); if (ret == KDialog::Accepted && fontDiffFlags) { setGeneralFont(applyFontDiff(m_generalFont, font, fontDiffFlags)); setMenuFont(applyFontDiff(m_menuFont, font, fontDiffFlags)); { const QFont adjustedFont = applyFontDiff(m_fixedWidthFont, font, fontDiffFlags); if (QFontInfo(adjustedFont).fixedPitch()) { setFixedWidthFont(adjustedFont); } } setToolbarFont(applyFontDiff(m_toolbarFont, font, fontDiffFlags)); setSmallFont(applyFontDiff(m_smallFont, font, fontDiffFlags)); setWindowTitleFont(applyFontDiff(m_windowTitleFont, font, fontDiffFlags)); } } QFont KFonts::applyFontDiff(const QFont &fnt, const QFont &newFont, int fontDiffFlags) { QFont font(fnt); if (fontDiffFlags & KFontChooser::FontDiffSize) { font.setPointSizeF(newFont.pointSizeF()); } if ((fontDiffFlags & KFontChooser::FontDiffFamily)) { font.setFamily(newFont.family()); } if (fontDiffFlags & KFontChooser::FontDiffStyle) { font.setWeight(newFont.weight()); font.setStyle(newFont.style()); font.setUnderline(newFont.underline()); font.setStyleName(newFont.styleName()); } return font; } #include "fonts.moc" diff --git a/kcms/fonts/kxftconfig.cpp b/kcms/fonts/kxftconfig.cpp index ffe6819a7..b79b882dc 100644 --- a/kcms/fonts/kxftconfig.cpp +++ b/kcms/fonts/kxftconfig.cpp @@ -1,837 +1,837 @@ /* Copyright (c) 2002 Craig Drummond This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This 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 "kxftconfig.h" #ifdef HAVE_FONTCONFIG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static int point2Pixel(double point) { return (int)(((point * QX11Info::appDpiY()) / 72.0) + 0.5); } static int pixel2Point(double pixel) { return (int)(((pixel * 72.0) / (double)QX11Info::appDpiY()) + 0.5); } static bool equal(double d1, double d2) { return (fabs(d1 - d2) < 0.0001); } static QString dirSyntax(const QString &d) { if (!d.isNull()) { QString ds(d); ds.replace("//", "/"); int slashPos = ds.lastIndexOf('/'); if (slashPos != (((int)ds.length()) - 1)) { ds.append('/'); } return ds; } return d; } static bool check(const QString &path, unsigned int fmt, bool checkW = false) { KDE_struct_stat info; QByteArray pathC(QFile::encodeName(path)); return 0 == KDE_lstat(pathC, &info) && (info.st_mode & S_IFMT) == fmt && (!checkW || 0 ==::access(pathC, W_OK)); } inline bool fExists(const QString &p) { return check(p, S_IFREG, false); } inline bool dWritable(const QString &p) { return check(p, S_IFDIR, true); } static QString getDir(const QString &f) { QString d(f); int slashPos = d.lastIndexOf('/'); if (-1 != slashPos) { d.remove(slashPos + 1, d.length()); } return dirSyntax(d); } static time_t getTimeStamp(const QString &item) { KDE_struct_stat info; return !item.isNull() && 0 == KDE_lstat(QFile::encodeName(item), &info) ? info.st_mtime : 0; } // // Obtain location of config file to use. QString getConfigFile() { FcStrList *list = FcConfigGetConfigFiles(FcConfigGetCurrent()); QStringList files; FcChar8 *file; QString home(dirSyntax(QDir::homePath())); while ((file = FcStrListNext(list))) { QString f((const char *)file); if (fExists(f) && 0 == f.indexOf(home)) { files.append(f); } } FcStrListDone(list); // // Go through list of files, looking for the preferred one... if (files.count()) { QStringList::const_iterator it(files.begin()), end(files.end()); for (; it != end; ++it) if (-1 != (*it).indexOf(QRegExp("/\\.?fonts\\.conf$"))) { return *it; } return files.front(); // Just return the 1st one... } else { // Hmmm... no known files? if (FcGetVersion() >= 21000) { QString targetPath(KGlobal::dirs()->localxdgconfdir() + "fontconfig"); QDir target(targetPath); if (!target.exists()) { target.mkpath(targetPath); } return targetPath + "/fonts.conf"; } else { return home + "/.fonts.conf"; } } } static QString getEntry(QDomElement element, const char *type, unsigned int numAttributes, ...) { if (numAttributes == element.attributes().length()) { va_list args; unsigned int arg; bool ok = true; va_start(args, numAttributes); for (arg = 0; arg < numAttributes && ok; ++arg) { const char *attr = va_arg(args, const char *); const char *val = va_arg(args, const char *); if (!attr || !val || val != element.attribute(attr)) { ok = false; } } va_end(args); if (ok) { QDomNode n = element.firstChild(); if (!n.isNull()) { QDomElement e = n.toElement(); if (!e.isNull() && type == e.tagName()) { return e.text(); } } } } return QString(); } static KXftConfig::SubPixel::Type strToType(const char *str) { if (0 == strcmp(str, "rgb")) { return KXftConfig::SubPixel::Rgb; } else if (0 == strcmp(str, "bgr")) { return KXftConfig::SubPixel::Bgr; } else if (0 == strcmp(str, "vrgb")) { return KXftConfig::SubPixel::Vrgb; } else if (0 == strcmp(str, "vbgr")) { return KXftConfig::SubPixel::Vbgr; } else if (0 == strcmp(str, "none")) { return KXftConfig::SubPixel::None; } else { return KXftConfig::SubPixel::NotSet; } } static KXftConfig::Hint::Style strToStyle(const char *str) { if (0 == strcmp(str, "hintslight")) { return KXftConfig::Hint::Slight; } else if (0 == strcmp(str, "hintmedium")) { return KXftConfig::Hint::Medium; } else if (0 == strcmp(str, "hintfull")) { return KXftConfig::Hint::Full; } else { return KXftConfig::Hint::None; } } KXftConfig::KXftConfig() : m_doc("fontconfig") , m_file(getConfigFile()) { qDebug() << "Using fontconfig file:" << m_file; reset(); } KXftConfig::~KXftConfig() { } bool KXftConfig::reset() { bool ok = false; m_madeChanges = false; m_hint.reset(); m_hinting.reset(); m_excludeRange.reset(); m_excludePixelRange.reset(); m_subPixel.reset(); m_antiAliasing.reset(); QFile f(m_file); if (f.open(QIODevice::ReadOnly)) { m_time = getTimeStamp(m_file); ok = true; m_doc.clear(); if (m_doc.setContent(&f)) { readContents(); } f.close(); } else { ok = !fExists(m_file) && dWritable(getDir(m_file)); } if (m_doc.documentElement().isNull()) { m_doc.appendChild(m_doc.createElement("fontconfig")); } if (ok) { // // Check exclude range values - i.e. size and pixel size... // If "size" range is set, ensure "pixelsize" matches... if (!equal(0, m_excludeRange.from) || !equal(0, m_excludeRange.to)) { double pFrom = (double)point2Pixel(m_excludeRange.from), pTo = (double)point2Pixel(m_excludeRange.to); if (!equal(pFrom, m_excludePixelRange.from) || !equal(pTo, m_excludePixelRange.to)) { m_excludePixelRange.from = pFrom; m_excludePixelRange.to = pTo; m_madeChanges = true; } } else if (!equal(0, m_excludePixelRange.from) || !equal(0, m_excludePixelRange.to)) { // "pixelsize" set, but not "size" !!! m_excludeRange.from = (int)pixel2Point(m_excludePixelRange.from); m_excludeRange.to = (int)pixel2Point(m_excludePixelRange.to); m_madeChanges = true; } } return ok; } bool KXftConfig::apply() { bool ok = true; if (m_madeChanges) { // // Check if file has been written since we last read it. If it has, then re-read and add any // of our changes... if (fExists(m_file) && getTimeStamp(m_file) != m_time) { KXftConfig newConfig; newConfig.setExcludeRange(m_excludeRange.from, m_excludeRange.to); newConfig.setSubPixelType(m_subPixel.type); newConfig.setHintStyle(m_hint.style); newConfig.setAntiAliasing(m_antiAliasing.state); ok = newConfig.changed() ? newConfig.apply() : true; if (ok) { reset(); } else { m_time = getTimeStamp(m_file); } } else { // Ensure these are always equal... m_excludePixelRange.from = (int)point2Pixel(m_excludeRange.from); m_excludePixelRange.to = (int)point2Pixel(m_excludeRange.to); FcAtomic *atomic = FcAtomicCreate((const unsigned char *)(QFile::encodeName(m_file).data())); ok = false; if (atomic) { if (FcAtomicLock(atomic)) { FILE *f = fopen((char *)FcAtomicNewFile(atomic), "w"); if (f) { applySubPixelType(); applyHintStyle(); applyAntiAliasing(); applyExcludeRange(false); applyExcludeRange(true); // // Check document syntax... static const char qtXmlHeader[] = ""; static const char xmlHeader[] = ""; static const char qtDocTypeLine[] = ""; static const char docTypeLine[] = ""; QString str(m_doc.toString()); int idx; if (0 != str.indexOf("= 0 || to >= 0) && foundFalse) { m_excludeRange.from = from < to ? from : to; m_excludeRange.to = from < to ? to : from; m_excludeRange.node = n; } else if ((pixelFrom >= 0 || pixelTo >= 0) && foundFalse) { m_excludePixelRange.from = pixelFrom < pixelTo ? pixelFrom : pixelTo; m_excludePixelRange.to = pixelFrom < pixelTo ? pixelTo : pixelFrom; m_excludePixelRange.node = n; } } break; default: break; } } } n = n.nextSibling(); } } void KXftConfig::applySubPixelType() { if (SubPixel::NotSet == m_subPixel.type) { if (!m_subPixel.node.isNull()) { m_doc.documentElement().removeChild(m_subPixel.node); m_subPixel.node.clear(); } } else { QDomElement matchNode = m_doc.createElement("match"); QDomElement typeNode = m_doc.createElement("const"); QDomElement editNode = m_doc.createElement("edit"); QDomText typeText = m_doc.createTextNode(toStr(m_subPixel.type)); matchNode.setAttribute("target", "font"); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "rgba"); editNode.appendChild(typeNode); typeNode.appendChild(typeText); matchNode.appendChild(editNode); if (m_subPixel.node.isNull()) { m_doc.documentElement().appendChild(matchNode); } else { m_doc.documentElement().replaceChild(matchNode, m_subPixel.node); } m_subPixel.node = matchNode; } } void KXftConfig::applyHintStyle() { applyHinting(); if (Hint::NotSet == m_hint.style) { if (!m_hint.node.isNull()) { m_doc.documentElement().removeChild(m_hint.node); m_hint.node.clear(); } if (!m_hinting.node.isNull()) { m_doc.documentElement().removeChild(m_hinting.node); m_hinting.node.clear(); } } else { QDomElement matchNode = m_doc.createElement("match"), typeNode = m_doc.createElement("const"), editNode = m_doc.createElement("edit"); QDomText typeText = m_doc.createTextNode(toStr(m_hint.style)); matchNode.setAttribute("target", "font"); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "hintstyle"); editNode.appendChild(typeNode); typeNode.appendChild(typeText); matchNode.appendChild(editNode); if (m_hint.node.isNull()) { m_doc.documentElement().appendChild(matchNode); } else { m_doc.documentElement().replaceChild(matchNode, m_hint.node); } m_hint.node = matchNode; } } void KXftConfig::applyHinting() { QDomElement matchNode = m_doc.createElement("match"), typeNode = m_doc.createElement("bool"), editNode = m_doc.createElement("edit"); QDomText typeText = m_doc.createTextNode(m_hinting.set ? "true" : "false"); matchNode.setAttribute("target", "font"); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "hinting"); editNode.appendChild(typeNode); typeNode.appendChild(typeText); matchNode.appendChild(editNode); if (m_hinting.node.isNull()) { m_doc.documentElement().appendChild(matchNode); } else { m_doc.documentElement().replaceChild(matchNode, m_hinting.node); } m_hinting.node = matchNode; } void KXftConfig::applyExcludeRange(bool pixel) { Exclude &range = pixel ? m_excludePixelRange : m_excludeRange; if (equal(range.from, 0) && equal(range.to, 0)) { if (!range.node.isNull()) { m_doc.documentElement().removeChild(range.node); range.node.clear(); } } else { QString fromString, toString; fromString.setNum(range.from); toString.setNum(range.to); QDomElement matchNode = m_doc.createElement("match"), fromTestNode = m_doc.createElement("test"), fromNode = m_doc.createElement("double"), toTestNode = m_doc.createElement("test"), toNode = m_doc.createElement("double"), editNode = m_doc.createElement("edit"), boolNode = m_doc.createElement("bool"); QDomText fromText = m_doc.createTextNode(fromString), toText = m_doc.createTextNode(toString), boolText = m_doc.createTextNode("false"); matchNode.setAttribute("target", "font"); // CPD: Is target "font" or "pattern" ???? fromTestNode.setAttribute("qual", "any"); fromTestNode.setAttribute("name", pixel ? "pixelsize" : "size"); fromTestNode.setAttribute("compare", "more_eq"); fromTestNode.appendChild(fromNode); fromNode.appendChild(fromText); toTestNode.setAttribute("qual", "any"); toTestNode.setAttribute("name", pixel ? "pixelsize" : "size"); toTestNode.setAttribute("compare", "less_eq"); toTestNode.appendChild(toNode); toNode.appendChild(toText); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "antialias"); editNode.appendChild(boolNode); boolNode.appendChild(boolText); matchNode.appendChild(fromTestNode); matchNode.appendChild(toTestNode); matchNode.appendChild(editNode); if (!m_antiAliasing.node.isNull()) { m_doc.documentElement().removeChild(range.node); } m_doc.documentElement().appendChild(matchNode); range.node = matchNode; } } KXftConfig::AntiAliasing::State KXftConfig::getAntiAliasing() const { return m_antiAliasing.state; } void KXftConfig::setAntiAliasing(AntiAliasing::State state) { if (state != m_antiAliasing.state) { m_antiAliasing.state = state; m_madeChanges = true; } } void KXftConfig::applyAntiAliasing() { if (AntiAliasing::NotSet == m_antiAliasing.state) { if (!m_antiAliasing.node.isNull()) { m_doc.documentElement().removeChild(m_antiAliasing.node); m_antiAliasing.node.clear(); } } else { QDomElement matchNode = m_doc.createElement("match"); QDomElement typeNode = m_doc.createElement("bool"); QDomElement editNode = m_doc.createElement("edit"); QDomText typeText = m_doc.createTextNode(m_antiAliasing.state == AntiAliasing::Enabled ? "true" : "false"); matchNode.setAttribute("target", "font"); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "antialias"); editNode.appendChild(typeNode); typeNode.appendChild(typeText); matchNode.appendChild(editNode); if (!m_antiAliasing.node.isNull()) { m_doc.documentElement().removeChild(m_antiAliasing.node); } m_doc.documentElement().appendChild(matchNode); m_antiAliasing.node = matchNode; } } // KXftConfig only parses one config file, user's .fonts.conf usually. // If that one doesn't exist, then KXftConfig doesn't know if antialiasing // is enabled or not. So try to find out the default value from the default font. // Maybe there's a better way *shrug*. bool KXftConfig::aliasingEnabled() { FcPattern *pattern = FcPatternCreate(); - FcConfigSubstitute(0, pattern, FcMatchPattern); + FcConfigSubstitute(nullptr, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; - FcPattern *f = FcFontMatch(0, pattern, &result); + FcPattern *f = FcFontMatch(nullptr, pattern, &result); FcBool antialiased = FcTrue; FcPatternGetBool(f, FC_ANTIALIAS, 0, &antialiased); FcPatternDestroy(f); FcPatternDestroy(pattern); return antialiased == FcTrue; } #endif diff --git a/kcms/hardware/joystick/joydevice.cpp b/kcms/hardware/joystick/joydevice.cpp index 17a964cd0..a60ca74fa 100644 --- a/kcms/hardware/joystick/joydevice.cpp +++ b/kcms/hardware/joystick/joydevice.cpp @@ -1,407 +1,407 @@ /*************************************************************************** * Copyright (C) 2003 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 "joydevice.h" #include #include #include #include #include #include #include #include #include #include #include #include //-------------------------------------------------------------- JoyDevice::JoyDevice(const QString &devicefile) : devName(devicefile), joyFd(-1), buttons(0), axes(0), - amin(0), amax(0), corr(0), origCorr(0) + amin(nullptr), amax(nullptr), corr(nullptr), origCorr(nullptr) { } //-------------------------------------------------------------- QString JoyDevice::errText(ErrorCode code) const { switch ( code ) { case SUCCESS: return QLatin1String(""); case OPEN_FAILED: { return i18n("The given device %1 could not be opened: %2", devName, strerror(errno)); } case NO_JOYSTICK: { return i18n("The given device %1 is not a joystick.", devName); } case ERR_GET_VERSION: { return i18n("Could not get kernel driver version for joystick device %1: %2", devName, strerror(errno)); } case WRONG_VERSION: { int version = 0; int fd = ::open(devName.toLatin1(), O_RDONLY); if ( fd != -1 ) { ::ioctl(fd, JSIOCGVERSION, &version); ::close(fd); } KLocalizedString loc = ki18n("The current running kernel driver version (%1.%2.%3) is not the one this module was compiled for (%4.%5.%6)."); loc = loc.subs(version >> 16); loc = loc.subs((version >> 8) & 0xFF); loc = loc.subs(version & 0xFF); loc = loc.subs(JS_VERSION >> 16); loc = loc.subs((JS_VERSION >> 8) & 0xFF); loc = loc.subs(JS_VERSION & 0xFF); return loc.toString(); } case ERR_GET_BUTTONS: { return i18n("Could not get number of buttons for joystick device %1: %2", devName, strerror(errno)); } case ERR_GET_AXES: { return i18n("Could not get number of axes for joystick device %1: %2", devName, strerror(errno)); } case ERR_GET_CORR: { return i18n("Could not get calibration values for joystick device %1: %2", devName, strerror(errno)); } case ERR_RESTORE_CORR: { return i18n("Could not restore calibration values for joystick device %1: %2", devName, strerror(errno)); } case ERR_INIT_CAL: { return i18n("Could not initialize calibration values for joystick device %1: %2", devName, strerror(errno)); } case ERR_APPLY_CAL: { return i18n("Could not apply calibration values for joystick device %1: %2", devName, strerror(errno)); } default: return i18n("internal error - code %1 unknown", int(code)); } } //-------------------------------------------------------------- JoyDevice::ErrorCode JoyDevice::open() { if ( joyFd != -1 ) return JoyDevice::SUCCESS; // already open int fd = ::open(devName.toLatin1(), O_RDONLY); if ( fd == -1 ) return JoyDevice::OPEN_FAILED; // we could open the devicefile, now check if a joystick is attached char name[128]; if ( ::ioctl(fd, JSIOCGNAME(sizeof(name)), &name) == -1 ) { ::close(fd); return JoyDevice::NO_JOYSTICK; } // check the kernel driver version int version; if ( ::ioctl(fd, JSIOCGVERSION, &version) == -1 ) { ::close(fd); return JoyDevice::ERR_GET_VERSION; } if ( version != JS_VERSION ) { ::close(fd); return JoyDevice::WRONG_VERSION; } char bt = 0, ax = 0; if ( ::ioctl(fd, JSIOCGBUTTONS, &bt) == -1 ) { ::close(fd); return JoyDevice::ERR_GET_BUTTONS; } if ( ::ioctl(fd, JSIOCGAXES, &ax) == -1 ) { ::close(fd); return JoyDevice::ERR_GET_AXES; } struct js_corr *oldCorr = new struct js_corr[ax]; if ( ::ioctl(fd, JSIOCGCORR, oldCorr) == -1 ) { ::close(fd); delete [] oldCorr; return JoyDevice::ERR_GET_CORR; } if (bt < 0) { return JoyDevice::ERR_GET_BUTTONS; } descr = name; joyFd = fd; axes = ax; buttons = bt; origCorr = oldCorr; corr = new struct js_corr[axes]; amin = new int[axes]; amax = new int[axes]; int i; for (i = 0; i < axes; i++) resetMinMax(i); return JoyDevice::SUCCESS; } //-------------------------------------------------------------- void JoyDevice::close() { if ( joyFd == -1 ) return; ::close(joyFd); joyFd = -1; descr = QLatin1String(""); delete [] amin; delete [] amax; - amin = 0; - amax = 0; + amin = nullptr; + amax = nullptr; delete [] corr; - corr = 0; + corr = nullptr; delete [] origCorr; - origCorr = 0; + origCorr = nullptr; } //-------------------------------------------------------------- int JoyDevice::axisMin(int axis) const { if ( (axis < 0) || (axis >= axes) ) return 0; return amin[axis]; } //-------------------------------------------------------------- int JoyDevice::axisMax(int axis) const { if ( (axis < 0) || (axis >= axes) ) return 0; return amax[axis]; } //-------------------------------------------------------------- JoyDevice::ErrorCode JoyDevice::initCalibration() { if ( joyFd == -1 ) return JoyDevice::ERR_INIT_CAL; int i; // Reset all current correction values for (i = 0; i < axes; i++) { corr[i].type = JS_CORR_NONE; corr[i].prec = 0; } if ( ::ioctl(joyFd, JSIOCSCORR, corr) == -1 ) return JoyDevice::ERR_INIT_CAL; for (i = 0; i < axes; i++) corr[i].type = JS_CORR_BROKEN; return JoyDevice::SUCCESS; } //-------------------------------------------------------------- JoyDevice::ErrorCode JoyDevice::applyCalibration() { if ( joyFd == -1 ) return JoyDevice::ERR_APPLY_CAL; if ( ::ioctl(joyFd, JSIOCSCORR, corr) == -1 ) return JoyDevice::ERR_APPLY_CAL; return JoyDevice::SUCCESS; } //-------------------------------------------------------------- void JoyDevice::resetMinMax(int axis, int value) { amin[axis] = value; amax[axis] = value; } //-------------------------------------------------------------- void JoyDevice::calcPrecision() { if ( !corr ) return; int i; for (i = 0; i < axes; i++) { corr[i].prec = amax[i] - amin[i]; qDebug() << "Precision for axis: " << i << ": " << corr[i].prec; } } //-------------------------------------------------------------- JoyDevice::ErrorCode JoyDevice::restoreCorr() { if ( joyFd == -1 ) return JoyDevice::SUCCESS; if ( ::ioctl(joyFd, JSIOCSCORR, origCorr) == -1 ) return JoyDevice::ERR_RESTORE_CORR; else return JoyDevice::SUCCESS; } //-------------------------------------------------------------- JoyDevice::~JoyDevice() { close(); } //-------------------------------------------------------------- bool JoyDevice::getEvent(JoyDevice::EventType &type, int &number, int &value) { number = value = 0; int ret; fd_set readSet; FD_ZERO(&readSet); FD_SET(joyFd, &readSet); struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 10000; - ret = ::select(joyFd + 1, &readSet, 0, 0, &timeout); + ret = ::select(joyFd + 1, &readSet, nullptr, nullptr, &timeout); if ( ret == 1 ) // got an event from the joystick { struct js_event e; if ( ::read(joyFd, &e, sizeof(struct js_event)) == sizeof(struct js_event) ) { if ( e.type & JS_EVENT_BUTTON ) { type = JoyDevice::BUTTON; value = e.value; number = e.number; return true; } if ( e.type & JS_EVENT_AXIS ) { type = JoyDevice::AXIS; value = e.value; number = e.number; // store min, max values if ( e.value < amin[number] ) amin[number] = e.value; if ( e.value > amax[number] ) amax[number] = e.value; return true; } } } return false; // no event } //-------------------------------------------------------------- void JoyDevice::calcCorrection(int axis, int *min, int *center, int *max) { const int MIN = 0; const int MAX = 1; double a, b, c, d; a = center[MIN]; // inputs.cmin[1]; b = center[MAX]; // inputs.cmax[1]; c = 32767.0 / (center[MIN] - min[MAX]); // (inputs.cmin[1] - inputs.cmax[0]); d = 32767.0 / (max[MIN] - center[MAX]); // (inputs.cmin[2] - inputs.cmax[1]); corr[axis].coef[0] = (int)rint(a); corr[axis].coef[1] = (int)rint(b); corr[axis].coef[2] = (int)rint(c*16384.0); corr[axis].coef[3] = (int)rint(d*16384.0); qDebug() << "min min: " << min[0] << " max: " << min[1] ; qDebug() << "max min: " << max[0] << " max: " << max[1] ; qDebug() << "Correction values for axis: " << axis << ": " << corr[axis].coef[0] << ", " << corr[axis].coef[1] << ", " << corr[axis].coef[2] << ", " << corr[axis].coef[3] << endl; } //-------------------------------------------------------------- diff --git a/kcms/hardware/joystick/joywidget.cpp b/kcms/hardware/joystick/joywidget.cpp index 6b1beb2d3..dabccd6ca 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(0), joydev(0) + : QWidget(parent), idle(nullptr), joydev(nullptr) { QVBoxLayout *mainVbox = new QVBoxLayout(this); mainVbox->setSpacing(KDialog::spacingHint()); mainVbox->setMargin(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()->setClickable(false); buttonTbl->horizontalHeader()->setResizeMode(QHeaderView::Stretch); buttonTbl->horizontalHeader()->resizeSection(0, colWidth); buttonTbl->verticalHeader()->setClickable(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()->setClickable(false); axesTbl->horizontalHeader()->setResizeMode(QHeaderView::Stretch); axesTbl->horizontalHeader()->resizeSection(0, colWidth); axesTbl->verticalHeader()->setClickable(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 ) { 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 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/kded/kcmkded.cpp b/kcms/kded/kcmkded.cpp index aa6f08b31..3bc2b9f62 100644 --- a/kcms/kded/kcmkded.cpp +++ b/kcms/kded/kcmkded.cpp @@ -1,505 +1,505 @@ // vim: noexpandtab shiftwidth=4 tabstop=4 /* This file is part of the KDE project Copyright (C) 2002 Daniel Molkentin 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 "kcmkded.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(KDEDFactory, registerPlugin(); ) K_EXPORT_PLUGIN(KDEDFactory("kcmkded")) Q_LOGGING_CATEGORY(KCM_KDED, "kcm_kded") enum OnDemandColumns { OnDemandService = 0, OnDemandStatus = 1, OnDemandDescription = 2 }; enum StartupColumns { StartupUse = 0, StartupService = 1, StartupStatus = 2, StartupDescription = 3 }; static const int LibraryRole = Qt::UserRole + 1; KDEDConfig::KDEDConfig(QWidget* parent, const QVariantList &) : KCModule( parent ) { KAboutData *about = new KAboutData( I18N_NOOP( "kcmkded" ), i18n( "KDE Service Manager" ), QStringLiteral("1.0"), QString(), KAboutLicense::GPL, i18n( "(c) 2002 Daniel Molkentin" ) ); about->addAuthor(i18n("Daniel Molkentin"), QString(),QStringLiteral("molkentin@kde.org")); setAboutData( about ); setButtons(Apply|Default|Help); setQuickHelp( i18n("

Service Manager

This module allows you to have an overview of all plugins of the " "KDE Daemon, also referred to as KDE Services. Generally, there are two types of service:

" "
  • Services invoked at startup
  • Services called on demand
" "

The latter are only listed for convenience. The startup services can be started and stopped. " "In Administrator mode, you can also define whether services should be loaded at startup.

" "

Use this with care: some services are vital for Plasma; do not deactivate services if you" " do not know what you are doing.

")); RUNNING = i18n("Running")+' '; NOT_RUNNING = i18n("Not running")+' '; QVBoxLayout *lay = new QVBoxLayout( this ); lay->setMargin( 0 ); QGroupBox *gb = new QGroupBox( i18n("Load-on-Demand Services"), this ); gb->setWhatsThis( i18n("This is a list of available KDE services which will " "be started on demand. They are only listed for convenience, as you " "cannot manipulate these services.")); lay->addWidget( gb ); QVBoxLayout *gblay = new QVBoxLayout( gb ); _lvLoD = new QTreeWidget( gb ); QStringList cols; cols.append( i18n("Service") ); cols.append( i18n("Status") ); cols.append( i18n("Description") ); _lvLoD->setHeaderLabels( cols ); _lvLoD->setAllColumnsShowFocus(true); _lvLoD->setRootIsDecorated( false ); _lvLoD->setSortingEnabled(true); _lvLoD->sortByColumn(OnDemandService, Qt::AscendingOrder); _lvLoD->header()->setStretchLastSection(true); gblay->addWidget( _lvLoD ); gb = new QGroupBox( i18n("Startup Services"), this ); gb->setWhatsThis( i18n("This shows all KDE services that can be loaded " "on Plasma startup. Checked services will be invoked on next startup. " "Be careful with deactivation of unknown services.")); lay->addWidget( gb ); gblay = new QVBoxLayout( gb ); _lvStartup = new QTreeWidget( gb ); cols.clear(); cols.append( i18n("Use") ); cols.append( i18n("Service") ); cols.append( i18n("Status") ); cols.append( i18n("Description") ); _lvStartup->setHeaderLabels( cols ); _lvStartup->setAllColumnsShowFocus(true); _lvStartup->setRootIsDecorated( false ); _lvStartup->setSortingEnabled(true); _lvStartup->sortByColumn(StartupService, Qt::AscendingOrder); _lvStartup->header()->setStretchLastSection(true); gblay->addWidget( _lvStartup ); QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal, gb); _pbStart = buttonBox->addButton( i18n("Start") , QDialogButtonBox::ActionRole ); _pbStop = buttonBox->addButton( i18n("Stop") , QDialogButtonBox::ActionRole ); gblay->addWidget( buttonBox ); _pbStart->setEnabled( false ); _pbStop->setEnabled( false ); connect(_pbStart, &QPushButton::clicked, this, &KDEDConfig::slotStartService); connect(_pbStop, &QPushButton::clicked, this, &KDEDConfig::slotStopService); connect(_lvLoD, &QTreeWidget::itemSelectionChanged, this, &KDEDConfig::slotLodItemSelected); connect(_lvStartup, &QTreeWidget::itemSelectionChanged, this, &KDEDConfig::slotStartupItemSelected); connect(_lvStartup, &QTreeWidget::itemChanged, this, &KDEDConfig::slotItemChecked); } QString setModuleGroup(const KPluginMetaData &module) { return QStringLiteral("Module-%1").arg(module.pluginId()); } bool KDEDConfig::autoloadEnabled(KConfig *config, const KPluginMetaData &module) { KConfigGroup cg(config, setModuleGroup(module)); return cg.readEntry("autoload", true); } void KDEDConfig::setAutoloadEnabled(KConfig *config, const KPluginMetaData &module, bool b) { KConfigGroup cg(config, setModuleGroup(module)); return cg.writeEntry("autoload", b); } // This code was copied from kded.cpp // TODO: move this KCM to the KDED framework and share the code? static QVector availableModules() { QVector plugins = KPluginLoader::findPlugins(QStringLiteral("kf5/kded")); QSet moduleIds; foreach (const KPluginMetaData &md, plugins) { moduleIds.insert(md.pluginId()); } // also search for old .desktop based kded modules KPluginInfo::List oldStylePlugins = KPluginInfo::fromServices(KServiceTypeTrader::self()->query(QStringLiteral("KDEDModule"))); foreach (const KPluginInfo &info, oldStylePlugins) { if (moduleIds.contains(info.pluginName())) { qCWarning(KCM_KDED).nospace() << "kded module " << info.pluginName() << " has already been found using " "JSON metadata, please don't install the now unneeded .desktop file (" << info.entryPath() << ")."; } else { qCDebug(KCM_KDED).nospace() << "kded module " << info.pluginName() << " still uses .desktop files (" << info.entryPath() << "). Please port it to JSON metadata."; plugins.append(info.toMetaData()); } } return plugins; } // this code was copied from kded.cpp static bool isModuleLoadedOnDemand(const KPluginMetaData &module) { bool loadOnDemand = true; // use toVariant() since it could be string or bool in the json and QJsonObject does not convert QVariant p = module.rawData().value(QStringLiteral("X-KDE-Kded-load-on-demand")).toVariant(); if (p.isValid() && p.canConvert() && (p.toBool() == false)) { loadOnDemand = false; } return loadOnDemand; } void KDEDConfig::load() { KConfig kdedrc(QStringLiteral("kded5rc"), KConfig::NoGlobals); _lvStartup->clear(); _lvLoD->clear(); - QTreeWidgetItem* treeitem = 0L; + QTreeWidgetItem* treeitem = nullptr; const auto modules = availableModules(); for (const KPluginMetaData &mod : modules) { QString servicePath = mod.metaDataFileName(); // autoload defaults to false if it is not found const bool autoload = mod.rawData().value(QStringLiteral("X-KDE-Kded-autoload")).toVariant().toBool(); // keep estimating dbusModuleName in sync with KDEDModule (kdbusaddons) and kded (kded) // currently (KF5) the module name in the D-Bus object path is set by the pluginId const QString dbusModuleName = mod.pluginId(); qCDebug(KCM_KDED) << "reading kded info from" << servicePath << "autoload =" << autoload << "dbus module name =" << dbusModuleName; // The logic has to be identical to Kded::initModules. // They interpret X-KDE-Kded-autoload as false if not specified // X-KDE-Kded-load-on-demand as true if not specified if (autoload) { treeitem = new QTreeWidgetItem(); treeitem->setCheckState(StartupUse, autoloadEnabled(&kdedrc, mod) ? Qt::Checked : Qt::Unchecked); treeitem->setText(StartupService, mod.name()); treeitem->setText(StartupDescription, mod.description()); treeitem->setText(StartupStatus, NOT_RUNNING); treeitem->setData(StartupService, LibraryRole, dbusModuleName); _lvStartup->addTopLevelItem(treeitem); } else if (isModuleLoadedOnDemand(mod)) { treeitem = new QTreeWidgetItem(); treeitem->setText(OnDemandService, mod.name() ); treeitem->setText(OnDemandDescription, mod.description()); treeitem->setText(OnDemandStatus, NOT_RUNNING); treeitem->setData(OnDemandService, LibraryRole, dbusModuleName); _lvLoD->addTopLevelItem(treeitem); } else { qCWarning(KCM_KDED) << "kcmkded: Module " << mod.name() << "from file" << mod.metaDataFileName() << " not loaded on demand or startup! Skipping."; } } _lvStartup->resizeColumnToContents(StartupUse); _lvStartup->resizeColumnToContents(StartupService); _lvStartup->resizeColumnToContents(StartupStatus); _lvLoD->resizeColumnToContents(OnDemandService); _lvLoD->resizeColumnToContents(OnDemandStatus); getServiceStatus(); emit changed(false); } void KDEDConfig::save() { KConfig kdedrc(QStringLiteral("kded5rc"), KConfig::NoGlobals); const auto modules = availableModules(); for (const KPluginMetaData &mod : modules) { qCDebug(KCM_KDED) << "saving settings for kded module" << mod.pluginId(); // autoload defaults to false if it is not found const bool autoload = mod.rawData().value(QStringLiteral("X-KDE-Kded-autoload")).toVariant().toBool(); if (autoload) { const QString libraryName = mod.pluginId(); int count = _lvStartup->topLevelItemCount(); for(int i = 0; i < count; ++i) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem(i); if ( treeitem->data(StartupService, LibraryRole ).toString() == libraryName) { // we found a match, now compare and see what changed setAutoloadEnabled(&kdedrc, mod, treeitem->checkState( StartupUse ) == Qt::Checked); break; } } } } kdedrc.sync(); emit changed(false); QDBusInterface kdedInterface(QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QStringLiteral("org.kde.kded5")); kdedInterface.call(QStringLiteral("reconfigure")); QTimer::singleShot(0, this, &KDEDConfig::slotServiceRunningToggled); } void KDEDConfig::defaults() { int count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { _lvStartup->topLevelItem( i )->setCheckState( StartupUse, Qt::Checked ); } getServiceStatus(); emit changed(true); } void KDEDConfig::getServiceStatus() { QStringList modules; QDBusInterface kdedInterface( QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QStringLiteral("org.kde.kded5") ); QDBusReply reply = kdedInterface.call( QStringLiteral("loadedModules") ); if ( reply.isValid() ) { modules = reply.value(); } else { _lvLoD->setEnabled( false ); _lvStartup->setEnabled( false ); KMessageBox::error(this, i18n("Unable to contact KDED.")); return; } qCDebug(KCM_KDED) << "Loaded kded modules:" << modules; // Initialize int count = _lvLoD->topLevelItemCount(); for( int i = 0; i < count; ++i ) _lvLoD->topLevelItem( i )->setText( OnDemandStatus, NOT_RUNNING ); count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) _lvStartup->topLevelItem( i )->setText( StartupStatus, NOT_RUNNING ); // Fill foreach( const QString& module, modules ) { bool found = false; count = _lvLoD->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvLoD->topLevelItem( i ); if ( treeitem->data( OnDemandService, LibraryRole ).toString() == module ) { treeitem->setText( OnDemandStatus, RUNNING ); found = true; break; } } count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); if ( treeitem->data( StartupService, LibraryRole ).toString() == module ) { treeitem->setText( StartupStatus, RUNNING ); found = true; break; } } if (!found) { qCDebug(KCM_KDED) << "Could not relate module " << module; #ifndef NDEBUG qCDebug(KCM_KDED) << "Candidates were:"; count = _lvLoD->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvLoD->topLevelItem( i ); qCDebug(KCM_KDED) << treeitem->data( OnDemandService, LibraryRole ).toString(); } count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); qCDebug(KCM_KDED) << treeitem->data( StartupService, LibraryRole ).toString(); } #endif } } } void KDEDConfig::slotReload() { QString current; if ( !_lvStartup->selectedItems().isEmpty() ) current = _lvStartup->selectedItems().at(0)->data( StartupService, LibraryRole ).toString(); load(); if ( !current.isEmpty() ) { int count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); if ( treeitem->data( StartupService, LibraryRole ).toString() == current ) { _lvStartup->setCurrentItem( treeitem, 0, QItemSelectionModel::ClearAndSelect ); break; } } } } void KDEDConfig::slotStartupItemSelected() { if ( _lvStartup->selectedItems().isEmpty() ) { // Disable the buttons _pbStart->setEnabled( false ); _pbStop->setEnabled( false ); return; } // Deselect a currently selected element in the "load on demand" treeview - _lvLoD->setCurrentItem(NULL, 0, QItemSelectionModel::Clear); + _lvLoD->setCurrentItem(nullptr, 0, QItemSelectionModel::Clear); QTreeWidgetItem *item = _lvStartup->selectedItems().at(0); if ( item->text(StartupStatus) == RUNNING ) { _pbStart->setEnabled( false ); _pbStop->setEnabled( true ); } else if ( item->text(StartupStatus) == NOT_RUNNING ) { _pbStart->setEnabled( true ); _pbStop->setEnabled( false ); } else // Error handling, better do nothing { _pbStart->setEnabled( false ); _pbStop->setEnabled( false ); } getServiceStatus(); } void KDEDConfig::slotLodItemSelected() { if ( _lvLoD->selectedItems().isEmpty() ) return; // Deselect a currently selected element in the "load on startup" treeview - _lvStartup->setCurrentItem(NULL, 0, QItemSelectionModel::Clear); + _lvStartup->setCurrentItem(nullptr, 0, QItemSelectionModel::Clear); } void KDEDConfig::slotServiceRunningToggled() { getServiceStatus(); slotStartupItemSelected(); } void KDEDConfig::slotStartService() { QString service = _lvStartup->selectedItems().at(0)->data( StartupService, LibraryRole ).toString(); QDBusInterface kdedInterface( QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"),QStringLiteral("org.kde.kded5") ); QDBusReply reply = kdedInterface.call( QStringLiteral("loadModule"), service ); if ( reply.isValid() ) { if ( reply.value() ) slotServiceRunningToggled(); else KMessageBox::error(this, "" + i18n("Unable to start server %1.", service) + ""); } else { KMessageBox::error(this, "" + i18n("Unable to start service %1.

Error: %2", service, reply.error().message()) + "
" ); } } void KDEDConfig::slotStopService() { QString service = _lvStartup->selectedItems().at(0)->data( StartupService, LibraryRole ).toString(); qCDebug(KCM_KDED) << "Stopping: " << service; QDBusInterface kdedInterface( QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QStringLiteral("org.kde.kded5") ); QDBusReply reply = kdedInterface.call( QStringLiteral("unloadModule"), service ); if ( reply.isValid() ) { if ( reply.value() ) slotServiceRunningToggled(); else KMessageBox::error(this, "" + i18n("Unable to stop service %1.", service) + ""); } else { KMessageBox::error(this, "" + i18n("Unable to stop service %1.

Error: %2", service, reply.error().message()) + "
" ); } } void KDEDConfig::slotItemChecked(QTreeWidgetItem*, int column) { // We only listen to changes the user did. if (column==StartupUse) { emit changed(true); } } #include "kcmkded.moc" diff --git a/kcms/keyboard/flags.cpp b/kcms/keyboard/flags.cpp index e5443cfcc..7fc7eb70f 100644 --- a/kcms/keyboard/flags.cpp +++ b/kcms/keyboard/flags.cpp @@ -1,297 +1,297 @@ /* * 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 "flags.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "x11_helper.h" //for text handling #include "keyboard_config.h" #include "xkb_rules.h" static const int FLAG_MAX_SIZE = 22; static const char flagTemplate[] = "kf5/locale/countries/%1/flag.png"; int iconSize(int s) { if (s < 16) { return 16; } else if (s < 22) { return 22; } else if (s < 32) { return 32; } else if (s < 48) { return 48; } else if (s < 64) { return 64; } else { return 128; } } Flags::Flags(): - svg(NULL) + svg(nullptr) { transparentPixmap = new QPixmap(FLAG_MAX_SIZE, FLAG_MAX_SIZE); transparentPixmap->fill(Qt::transparent); } Flags::~Flags() { - if( svg != NULL ) { + if( svg != nullptr ) { disconnect(svg, &Plasma::Svg::repaintNeeded, this, &Flags::themeChanged); delete svg; } delete transparentPixmap; } const QIcon Flags::getIcon(const QString& layout) { if( ! iconMap.contains(layout) ) { iconMap[ layout ] = createIcon(layout); } return iconMap[ layout ]; } QIcon Flags::createIcon(const QString& layout) { QIcon icon; if( ! layout.isEmpty() ) { QString file; if( layout == QLatin1String("epo") ) { file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kcmkeyboard/pics/epo.png")); } else { QString countryCode = getCountryFromLayoutName( layout ); if( ! countryCode.isEmpty() ) { file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString(flagTemplate).arg(countryCode)); // qCDebug(KCM_KEYBOARD, ) << "Creating icon for" << layout << "with" << file; } } if (!file.isEmpty()) { QImage flagImg; flagImg.load(file); const int size = iconSize(qMax(flagImg.width(), flagImg.height())); QPixmap iconPix(size, size); iconPix.fill(Qt::transparent); QRect dest(flagImg.rect()); dest.moveCenter(iconPix.rect().center()); QPainter painter(&iconPix); painter.drawImage(dest, flagImg); painter.end(); icon.addPixmap(iconPix); } } return icon; } //static //const QStringList NON_COUNTRY_LAYOUTS = QString("ara,brai,epo,latam,mao").split(","); QString Flags::getCountryFromLayoutName(const QString& layout) const { QString countryCode = layout; if( countryCode == QLatin1String("nec_vndr/jp") ) return QStringLiteral("jp"); // if( NON_COUNTRY_LAYOUTS.contain(layout) ) if( countryCode.length() > 2 ) return QLatin1String(""); return countryCode; } //TODO: move this to some other class? QString Flags::getShortText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig) { if( layoutUnit.isEmpty() ) return QStringLiteral("--"); QString layoutText = layoutUnit.layout; foreach(const LayoutUnit& lu, keyboardConfig.layouts) { if( layoutUnit.layout == lu.layout && layoutUnit.variant == lu.variant ) { layoutText = lu.getDisplayName(); break; } } //TODO: good autolabel // if( layoutText == layoutUnit.layout && layoutUnit.getDisplayName() != layoutUnit.layout ) { // layoutText = layoutUnit.getDisplayName(); // } return layoutText; } QString Flags::getFullText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig, const Rules* rules) { QString shortText = Flags::getShortText(layoutUnit, keyboardConfig); QString longText = Flags::getLongText(layoutUnit, rules); return i18nc("short layout label - full layout name", "%1 - %2", shortText, longText); } static QString getDisplayText(const QString& layout, const QString& variant, const Rules* rules) { if( variant.isEmpty() ) return layout; - if( rules == NULL || rules->version == QLatin1String("1.0") ) + if( rules == nullptr || rules->version == QLatin1String("1.0") ) return i18nc("layout - variant", "%1 - %2", layout, variant); return variant; } QString Flags::getLongText(const LayoutUnit& layoutUnit, const Rules* rules) { - if( rules == NULL ) { + if( rules == nullptr ) { return getDisplayText(layoutUnit.layout, layoutUnit.variant, rules); } QString layoutText = layoutUnit.layout; const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout); - if( layoutInfo != NULL ) { + if( layoutInfo != nullptr ) { layoutText = layoutInfo->description; if( ! layoutUnit.variant.isEmpty() ) { const VariantInfo* variantInfo = layoutInfo->getVariantInfo(layoutUnit.variant); - QString variantText = variantInfo != NULL ? variantInfo->description : layoutUnit.variant; + QString variantText = variantInfo != nullptr ? variantInfo->description : layoutUnit.variant; layoutText = getDisplayText(layoutText, variantText, rules); } } return layoutText; } static QString getPixmapKey(const KeyboardConfig& keyboardConfig) { switch(keyboardConfig.indicatorType) { case KeyboardConfig::SHOW_FLAG: return QStringLiteral("_fl"); case KeyboardConfig::SHOW_LABEL_ON_FLAG: return QStringLiteral("_bt"); case KeyboardConfig::SHOW_LABEL: return QStringLiteral("_lb"); } return QStringLiteral("_"); // should not happen } void Flags::drawLabel(QPainter& painter, const QString& layoutText, bool flagShown) { QFont font = painter.font(); QRect rect = painter.window(); font.setPointSize(KFontUtils::adaptFontSize(painter, layoutText, rect.size(), rect.height())); // we init svg so that we get notification about theme change getSvg(); const QColor textColor = flagShown ? Qt::black : Plasma::Theme().color(Plasma::Theme::TextColor); painter.setPen(textColor); painter.setFont(font); painter.drawText(rect, Qt::AlignCenter, layoutText); } const QIcon Flags::getIconWithText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig) { const QString keySuffix(getPixmapKey(keyboardConfig)); const QString key(layoutUnit.toString() + keySuffix); if( iconOrTextMap.contains(key) ) { return iconOrTextMap[ key ]; } if( keyboardConfig.indicatorType == KeyboardConfig::SHOW_FLAG ) { QIcon icon = getIcon(layoutUnit.layout); if( ! icon.isNull() ) { iconOrTextMap[ key ] = icon; return icon; } } QString layoutText = Flags::getShortText(layoutUnit, keyboardConfig); const QSize TRAY_ICON_SIZE(128, 128); QPixmap pixmap = QPixmap(TRAY_ICON_SIZE); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHint(QPainter::SmoothPixmapTransform); // p.setRenderHint(QPainter::Antialiasing); if( keyboardConfig.indicatorType == KeyboardConfig::SHOW_LABEL_ON_FLAG ) { QIcon iconf = createIcon(layoutUnit.layout); painter.drawPixmap(pixmap.rect(), iconf.pixmap(TRAY_ICON_SIZE)); } drawLabel(painter, layoutText, keyboardConfig.isFlagShown()); painter.end(); QIcon icon(pixmap); iconOrTextMap[ key ] = icon; return icon; } Plasma::Svg* Flags::getSvg() { - if( svg == NULL ) { + if( svg == nullptr ) { svg = new Plasma::Svg; svg->setImagePath(QStringLiteral("widgets/labeltexture")); svg->setContainsMultipleImages(true); connect(svg, &Plasma::Svg::repaintNeeded, this, &Flags::themeChanged); } return svg; } void Flags::themeChanged() { // qCDebug(KCM_KEYBOARD, ) << "Theme changed, new text color" << Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); clearCache(); emit pixmapChanged(); } void Flags::clearCache() { // qCDebug(KCM_KEYBOARD, ) << "Clearing flag pixmap cache"; iconOrTextMap.clear(); } diff --git a/kcms/keyboard/iso_codes.cpp b/kcms/keyboard/iso_codes.cpp index f8aa2b9df..56e4b1b8d 100644 --- a/kcms/keyboard/iso_codes.cpp +++ b/kcms/keyboard/iso_codes.cpp @@ -1,138 +1,138 @@ /* * 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 "iso_codes.h" #include "debug.h" #include #include class IsoCodesPrivate { public: IsoCodesPrivate(const QString& isoCode_, const QString& isoCodesXmlDir_): isoCode(isoCode_), isoCodesXmlDir(isoCodesXmlDir_), loaded(false) {} void buildIsoEntryList(); const QString isoCode; const QString isoCodesXmlDir; QList isoEntryList; bool loaded; }; class XmlHandler : public QXmlDefaultHandler { public: XmlHandler(const QString& isoCode_, QList& isoEntryList_): isoCode(isoCode_), qName("iso_"+isoCode+"_entry"), isoEntryList(isoEntryList_) {} bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &attributes) override; // bool fatalError(const QXmlParseException &exception); // QString errorString() const; private: const QString isoCode; const QString qName; QList& isoEntryList; }; bool XmlHandler::startElement(const QString &/*namespaceURI*/, const QString &/*localName*/, const QString &qName, const QXmlAttributes &attributes) { if( qName == this->qName ) { IsoCodeEntry entry; for(int i=0; i IsoCodes::getEntryList() { if( ! d->loaded ) { d->buildIsoEntryList(); } return d->isoEntryList; } //const char* IsoCodes::iso_639="639"; const char IsoCodes::iso_639_3[]="639_3"; const char IsoCodes::attr_name[]="name"; //const char* IsoCodes::attr_iso_639_2B_code="iso_639_2B_code"; //const char* IsoCodes::attr_iso_639_2T_code="iso_639_2T_code"; //const char* IsoCodes::attr_iso_639_1_code="iso_639_1_code"; const char IsoCodes::attr_iso_639_3_id[]="id"; const IsoCodeEntry* IsoCodes::getEntry(const QString& attributeName, const QString& attributeValue) { if( ! d->loaded ) { d->buildIsoEntryList(); } for(QList::Iterator it = d->isoEntryList.begin(); it != d->isoEntryList.end(); ++it) { const IsoCodeEntry* isoCodeEntry = &(*it); if( isoCodeEntry->value(attributeName) == attributeValue ) return isoCodeEntry; } - return NULL; + return nullptr; } void IsoCodesPrivate::buildIsoEntryList() { loaded = true; QFile file(QStringLiteral("%1/iso_%2.xml").arg(isoCodesXmlDir, isoCode)); if( !file.open(QFile::ReadOnly | QFile::Text) ) { qCCritical(KCM_KEYBOARD) << "Can't open the xml file" << file.fileName(); return; } XmlHandler xmlHandler(isoCode, isoEntryList); QXmlSimpleReader reader; reader.setContentHandler(&xmlHandler); reader.setErrorHandler(&xmlHandler); QXmlInputSource xmlInputSource(&file); if( ! reader.parse(xmlInputSource) ) { qCCritical(KCM_KEYBOARD) << "Failed to parse the xml file" << file.fileName(); return; } qCDebug(KCM_KEYBOARD) << "Loaded" << isoEntryList.count() << ("iso entry definitions for iso"+isoCode) << "from" << file.fileName(); } diff --git a/kcms/keyboard/kcm_add_layout_dialog.cpp b/kcms/keyboard/kcm_add_layout_dialog.cpp index 24ca18d46..7549a391c 100644 --- a/kcms/keyboard/kcm_add_layout_dialog.cpp +++ b/kcms/keyboard/kcm_add_layout_dialog.cpp @@ -1,178 +1,178 @@ /* * 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 "kcm_add_layout_dialog.h" #include #include #include "xkb_rules.h" #include "flags.h" #include "iso_codes.h" #include "ui_kcm_add_layout_dialog.h" #include AddLayoutDialog::AddLayoutDialog(const Rules* rules_, Flags* flags_, const QString& model_, bool showLabel, QWidget* parent): QDialog(parent), rules(rules_), flags(flags_), model(model_), selectedLanguage(QStringLiteral("no_language")) { layoutDialogUi = new Ui_AddLayoutDialog(); layoutDialogUi->setupUi(this); QSet languages; foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { QSet langs = QSet::fromList(layoutInfo->languages); languages.unite( langs ); } IsoCodes isoCodes(IsoCodes::iso_639_3); foreach(const QString& lang, languages) { const IsoCodeEntry* isoCodeEntry = isoCodes.getEntry(IsoCodes::attr_iso_639_3_id, lang); // const IsoCodeEntry* isoCodeEntry = isoCodes.getEntry(IsoCodes::attr_iso_639_2B_code, lang); // if( isoCodeEntry == NULL ) { // isoCodeEntry = isoCodes.getEntry(IsoCodes::attr_iso_639_2T_code, lang); // } - QString name = isoCodeEntry != NULL ? i18n(isoCodeEntry->value(IsoCodes::attr_name).toUtf8()) : lang; + QString name = isoCodeEntry != nullptr ? i18n(isoCodeEntry->value(IsoCodes::attr_name).toUtf8()) : lang; layoutDialogUi->languageComboBox->addItem(name, lang); } layoutDialogUi->languageComboBox->model()->sort(0); layoutDialogUi->languageComboBox->insertItem(0, i18n("Any language"), ""); layoutDialogUi->languageComboBox->setCurrentIndex(0); if( showLabel ) { layoutDialogUi->labelEdit->setMaxLength(LayoutUnit::MAX_LABEL_LENGTH); } else { layoutDialogUi->labelLabel->setVisible(false); layoutDialogUi->labelEdit->setVisible(false); } languageChanged(0); connect(layoutDialogUi->languageComboBox, static_cast(&QComboBox::activated), this, &AddLayoutDialog::languageChanged); connect(layoutDialogUi->layoutComboBox, static_cast(&QComboBox::activated), this, &AddLayoutDialog::layoutChanged); #ifdef NEW_GEOMETRY connect(layoutDialogUi->prevbutton, &QPushButton::clicked, this, &AddLayoutDialog::preview); #else layoutDialogUi->prevbutton->setVisible(false); #endif } void AddLayoutDialog::languageChanged(int langIdx) { QString lang = layoutDialogUi->languageComboBox->itemData(langIdx).toString(); if( lang == selectedLanguage ) return; QPixmap emptyPixmap(layoutDialogUi->layoutComboBox->iconSize()); emptyPixmap.fill(Qt::transparent); layoutDialogUi->layoutComboBox->clear(); int defaultIndex = -1; int i = 0; foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { if( lang.isEmpty() || layoutInfo->isLanguageSupportedByLayout(lang) ) { if( flags ) { QIcon icon(flags->getIcon(layoutInfo->name)); if( icon.isNull() ) { icon = QIcon(emptyPixmap); // align text with no icons } layoutDialogUi->layoutComboBox->addItem(icon, layoutInfo->description, layoutInfo->name); } else { layoutDialogUi->layoutComboBox->addItem(layoutInfo->description, layoutInfo->name); } // try to guess best default layout selection for given language if( ! lang.isEmpty() && defaultIndex == -1 && layoutInfo->isLanguageSupportedByDefaultVariant(lang) ) { defaultIndex = i; } i++; } } if( defaultIndex == -1 ) { defaultIndex = 0; } layoutDialogUi->layoutComboBox->model()->sort(0); layoutDialogUi->layoutComboBox->setCurrentIndex(defaultIndex); layoutChanged(defaultIndex); selectedLanguage = lang; } void AddLayoutDialog::layoutChanged(int layoutIdx) { QString layoutName = layoutDialogUi->layoutComboBox->itemData(layoutIdx).toString(); if( layoutName == selectedLayout ) return; QString lang = layoutDialogUi->languageComboBox->itemData(layoutDialogUi->languageComboBox->currentIndex()).toString(); layoutDialogUi->variantComboBox->clear(); const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutName); foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { if( lang.isEmpty() || layoutInfo->isLanguageSupportedByVariant(variantInfo, lang) ) { layoutDialogUi->variantComboBox->addItem(variantInfo->description, variantInfo->name); } } layoutDialogUi->variantComboBox->model()->sort(0); if( lang.isEmpty() || layoutInfo->isLanguageSupportedByDefaultVariant(lang) ) { layoutDialogUi->variantComboBox->insertItem(0, i18nc("variant", "Default"), ""); } layoutDialogUi->variantComboBox->setCurrentIndex(0); layoutDialogUi->labelEdit->setText(layoutName); selectedLayout = layoutName; } void AddLayoutDialog::accept() { selectedLayoutUnit.layout = layoutDialogUi->layoutComboBox->itemData(layoutDialogUi->layoutComboBox->currentIndex()).toString(); selectedLayoutUnit.variant = layoutDialogUi->variantComboBox->itemData(layoutDialogUi->variantComboBox->currentIndex()).toString(); QString label = layoutDialogUi->labelEdit->text(); if( label == selectedLayoutUnit.layout ) { label = QLatin1String(""); } selectedLayoutUnit.setDisplayName( label ); selectedLayoutUnit.setShortcut(layoutDialogUi->kkeysequencewidget->keySequence()); QDialog::accept(); } #ifdef NEW_GEOMETRY void AddLayoutDialog::preview() { int index = layoutDialogUi->variantComboBox->currentIndex(); QString variant = layoutDialogUi->variantComboBox->itemData(index).toString(); KeyboardPainter* layoutPreview = new KeyboardPainter(); QString title = Flags::getLongText(LayoutUnit(selectedLayout, variant), rules); layoutPreview->generateKeyboardLayout(selectedLayout, variant, model, title); layoutPreview->setModal(true); layoutPreview->exec(); delete layoutPreview; } #endif diff --git a/kcms/keyboard/kcm_add_layout_dialog.h b/kcms/keyboard/kcm_add_layout_dialog.h index 974152965..5a7246607 100644 --- a/kcms/keyboard/kcm_add_layout_dialog.h +++ b/kcms/keyboard/kcm_add_layout_dialog.h @@ -1,63 +1,63 @@ /* * 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. */ #ifndef KCM_ADD_LAYOUT_DIALOG_H_ #define KCM_ADD_LAYOUT_DIALOG_H_ #include #include "keyboard_config.h" #include "preview/keyboardpainter.h" #include struct Rules; class Flags; class Ui_AddLayoutDialog; class AddLayoutDialog: public QDialog { Q_OBJECT public: - AddLayoutDialog(const Rules* rules, Flags* flags, const QString& model, bool showLabel, QWidget* parent=NULL); + AddLayoutDialog(const Rules* rules, Flags* flags, const QString& model, bool showLabel, QWidget* parent=nullptr); LayoutUnit getSelectedLayoutUnit() { return selectedLayoutUnit; } QString getvariant(QString variant); void accept() override; public Q_SLOTS: void languageChanged(int langIdx); void layoutChanged(int layoutIdx); #ifdef NEW_GEOMETRY void preview(); #endif private: const Rules* rules; Flags* flags; const QString& model; Ui_AddLayoutDialog* layoutDialogUi; QString selectedLanguage; QString selectedLayout; LayoutUnit selectedLayoutUnit; }; #endif /* KCM_ADD_LAYOUT_DIALOG_H_ */ diff --git a/kcms/keyboard/kcm_keyboard_widget.cpp b/kcms/keyboard/kcm_keyboard_widget.cpp index 83dff7602..7db3ffedd 100644 --- a/kcms/keyboard/kcm_keyboard_widget.cpp +++ b/kcms/keyboard/kcm_keyboard_widget.cpp @@ -1,708 +1,708 @@ /* * 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 "kcm_keyboard_widget.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "keyboard_config.h" #ifdef NEW_GEOMETRY #include "preview/keyboardpainter.h" #endif #include "xkb_rules.h" #include "flags.h" #include "x11_helper.h" #include "kcm_view_models.h" #include "kcm_add_layout_dialog.h" #include "bindings.h" #include "kcmmisc.h" #include "ui_kcm_add_layout_dialog.h" static const QString GROUP_SWITCH_GROUP_NAME(QStringLiteral("grp")); static const QString LV3_SWITCH_GROUP_NAME(QStringLiteral("lv3")); //static const QString RESET_XKB_OPTIONS("-option"); static const int TAB_HARDWARE = 0; static const int TAB_LAYOUTS = 1; static const int TAB_ADVANCED = 2; static const int MIN_LOOPING_COUNT = 2; KCMKeyboardWidget::KCMKeyboardWidget(Rules* rules_, KeyboardConfig* keyboardConfig_, const QVariantList &args, QWidget* /*parent*/): rules(rules_), - actionCollection(NULL), + actionCollection(nullptr), uiUpdating(false) { flags = new Flags(); keyboardConfig = keyboardConfig_; uiWidget = new Ui::TabWidget; uiWidget->setupUi(this); kcmMiscWidget = new KCMiscKeyboardWidget(uiWidget->lowerHardwareWidget); uiWidget->lowerHardwareWidget->layout()->addWidget( kcmMiscWidget ); connect(kcmMiscWidget, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); - if( rules != NULL ) { + if( rules != nullptr ) { initializeKeyboardModelUI(); initializeXkbOptionsUI(); initializeLayoutsUI(); } else { uiWidget->tabLayouts->setEnabled(false); uiWidget->tabAdvanced->setEnabled(false); uiWidget->keyboardModelComboBox->setEnabled(false); } handleParameters(args); } KCMKeyboardWidget::~KCMKeyboardWidget() { delete uiWidget; delete flags; } void KCMKeyboardWidget::handleParameters(const QVariantList &args) { // TODO: improve parameter handling setCurrentIndex(TAB_HARDWARE); foreach(const QVariant& arg, args) { if( arg.type() == QVariant::String ) { QString str = arg.toString(); if( str == QLatin1String("--tab=layouts") ) { setCurrentIndex(TAB_LAYOUTS); } else if( str == QLatin1String("--tab=advanced") ) { setCurrentIndex(TAB_ADVANCED); } } } } void KCMKeyboardWidget::save() { - if( rules == NULL ) + if( rules == nullptr ) return; - if( actionCollection != NULL ) { + if( actionCollection != nullptr ) { actionCollection->resetLayoutShortcuts(); actionCollection->clear(); delete actionCollection; } actionCollection = new KeyboardLayoutActionCollection(this, true); actionCollection->setToggleShortcut(uiWidget->kdeKeySequence->keySequence()); actionCollection->setLayoutShortcuts(keyboardConfig->layouts, rules); } void KCMKeyboardWidget::updateUI() { - if( rules == NULL ) + if( rules == nullptr ) return; uiWidget->layoutsTableView->setModel(uiWidget->layoutsTableView->model()); layoutsTableModel->refresh(); uiWidget->layoutsTableView->resizeRowsToContents(); uiUpdating = true; updateHardwareUI(); updateXkbOptionsUI(); updateSwitcingPolicyUI(); updateLayoutsUI(); updateShortcutsUI(); layoutSelectionChanged(); uiUpdating = false; } void KCMKeyboardWidget::uiChanged() { - if( rules == NULL ) + if( rules == nullptr ) return; ((LayoutsTableModel*)uiWidget->layoutsTableView->model())->refresh(); layoutSelectionChanged(); // this collapses the tree so use more fine-grained updates // ((LayoutsTableModel*)uiWidget->xkbOptionsTreeView->model())->refresh(); if( uiUpdating ) return; keyboardConfig->showIndicator = uiWidget->showIndicatorChk->isChecked(); keyboardConfig->showSingle = uiWidget->showSingleChk->isChecked(); keyboardConfig->configureLayouts = uiWidget->layoutsGroupBox->isChecked(); keyboardConfig->keyboardModel = uiWidget->keyboardModelComboBox->itemData(uiWidget->keyboardModelComboBox->currentIndex()).toString(); if( uiWidget->showFlagRadioBtn->isChecked() ) { keyboardConfig->indicatorType = KeyboardConfig::SHOW_FLAG; } else if( uiWidget->showLabelRadioBtn->isChecked() ) { keyboardConfig->indicatorType = KeyboardConfig::SHOW_LABEL; } else { // if( uiWidget->showFlagRadioBtn->isChecked() ) { keyboardConfig->indicatorType = KeyboardConfig::SHOW_LABEL_ON_FLAG; } keyboardConfig->resetOldXkbOptions = uiWidget->configureKeyboardOptionsChk->isChecked(); if( uiWidget->switchByDesktopRadioBtn->isChecked() ) { keyboardConfig->switchingPolicy = KeyboardConfig::SWITCH_POLICY_DESKTOP; } else if( uiWidget->switchByApplicationRadioBtn->isChecked() ) { keyboardConfig->switchingPolicy = KeyboardConfig::SWITCH_POLICY_APPLICATION; } else if( uiWidget->switchByWindowRadioBtn->isChecked() ) { keyboardConfig->switchingPolicy = KeyboardConfig::SWITCH_POLICY_WINDOW; } else { keyboardConfig->switchingPolicy = KeyboardConfig::SWITCH_POLICY_GLOBAL; } updateXkbShortcutsButtons(); updateLoopCount(); int loop = uiWidget->layoutLoopCountSpinBox->text().isEmpty() ? KeyboardConfig::NO_LOOPING : uiWidget->layoutLoopCountSpinBox->value(); keyboardConfig->layoutLoopCount = loop; layoutsTableModel->refresh(); layoutSelectionChanged(); emit changed(true); } void KCMKeyboardWidget::initializeKeyboardModelUI() { foreach(ModelInfo* modelInfo, rules->modelInfos) { QString vendor = modelInfo->vendor; if( vendor.isEmpty() ) { vendor = i18nc("unknown keyboard model vendor", "Unknown"); } uiWidget->keyboardModelComboBox->addItem(i18nc("vendor | keyboard model", "%1 | %2", vendor, modelInfo->description), modelInfo->name); } uiWidget->keyboardModelComboBox->model()->sort(0); connect(uiWidget->keyboardModelComboBox, SIGNAL(activated(int)), this, SLOT(uiChanged())); } void KCMKeyboardWidget::addLayout() { if( keyboardConfig->layouts.count() >= X11Helper::ARTIFICIAL_GROUP_LIMIT_COUNT ) { // artificial limit now QMessageBox msgBox; msgBox.setText(i18np("Only up to %1 keyboard layout is supported", "Only up to %1 keyboard layouts are supported", X11Helper::ARTIFICIAL_GROUP_LIMIT_COUNT)); // more information https://bugs.freedesktop.org/show_bug.cgi?id=19501 msgBox.exec(); return; } - AddLayoutDialog dialog(rules, keyboardConfig->isFlagShown() ? flags : NULL, keyboardConfig->keyboardModel, keyboardConfig->isLabelShown(), this); + AddLayoutDialog dialog(rules, keyboardConfig->isFlagShown() ? flags : nullptr, keyboardConfig->keyboardModel, keyboardConfig->isLabelShown(), this); dialog.setModal(true); if( dialog.exec() == QDialog::Accepted ) { keyboardConfig->layouts.append( dialog.getSelectedLayoutUnit() ); layoutsTableModel->refresh(); uiWidget->layoutsTableView->resizeRowsToContents(); uiChanged(); } updateLoopCount(); } void KCMKeyboardWidget::updateLoopCount() { int maxLoop = qMin(X11Helper::MAX_GROUP_COUNT, keyboardConfig->layouts.count() - 1); uiWidget->layoutLoopCountSpinBox->setMaximum(qMax(MIN_LOOPING_COUNT, maxLoop)); bool layoutsConfigured = uiWidget->layoutsGroupBox->isChecked(); if( maxLoop < MIN_LOOPING_COUNT ) { uiWidget->layoutLoopingCheckBox->setEnabled(false); uiWidget->layoutLoopingCheckBox->setChecked(false); } else if( maxLoop >= X11Helper::MAX_GROUP_COUNT ) { uiWidget->layoutLoopingCheckBox->setEnabled(false); uiWidget->layoutLoopingCheckBox->setChecked(true); } else { uiWidget->layoutLoopingCheckBox->setEnabled(layoutsConfigured); } uiWidget->layoutLoopingGroupBox->setEnabled( layoutsConfigured && uiWidget->layoutLoopingCheckBox->isChecked()); if( uiWidget->layoutLoopingCheckBox->isChecked() ) { if( uiWidget->layoutLoopCountSpinBox->text().isEmpty() ) { uiWidget->layoutLoopCountSpinBox->setValue(maxLoop); keyboardConfig->layoutLoopCount = maxLoop; } } else { uiWidget->layoutLoopCountSpinBox->clear(); keyboardConfig->layoutLoopCount = KeyboardConfig::NO_LOOPING; } } void KCMKeyboardWidget::initializeLayoutsUI() { layoutsTableModel = new LayoutsTableModel(rules, flags, keyboardConfig, uiWidget->layoutsTableView); uiWidget->layoutsTableView->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed | QAbstractItemView::AnyKeyPressed); uiWidget->layoutsTableView->setModel(layoutsTableModel); uiWidget->layoutsTableView->setIconSize( flags->getTransparentPixmap().size() ); //TODO: do we need to delete this delegate or parent will take care of it? VariantComboDelegate* variantDelegate = new VariantComboDelegate(keyboardConfig, rules, uiWidget->layoutsTableView); uiWidget->layoutsTableView->setItemDelegateForColumn(LayoutsTableModel::VARIANT_COLUMN, variantDelegate); LabelEditDelegate* labelDelegate = new LabelEditDelegate(keyboardConfig, uiWidget->layoutsTableView); uiWidget->layoutsTableView->setItemDelegateForColumn(LayoutsTableModel::DISPLAY_NAME_COLUMN, labelDelegate); KKeySequenceWidgetDelegate* shortcutDelegate = new KKeySequenceWidgetDelegate(keyboardConfig, uiWidget->layoutsTableView); uiWidget->layoutsTableView->setItemDelegateForColumn(LayoutsTableModel::SHORTCUT_COLUMN, shortcutDelegate); //TODO: is it ok to hardcode sizes? any better approach? uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::MAP_COLUMN, 70); uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::LAYOUT_COLUMN, 200); uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::VARIANT_COLUMN, 200); uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::DISPLAY_NAME_COLUMN, 50); uiWidget->layoutsTableView->setColumnWidth(LayoutsTableModel::SHORTCUT_COLUMN, 130); connect(layoutsTableModel, &LayoutsTableModel::dataChanged, this, [this]() { Q_EMIT changed(true); }); uiWidget->layoutLoopCountSpinBox->setMinimum(MIN_LOOPING_COUNT); #ifdef DRAG_ENABLED uiWidget->layoutsTableView->setDragEnabled(true); uiWidget->layoutsTableView->setAcceptDrops(true); #endif uiWidget->moveUpBtn->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up"))); uiWidget->moveDownBtn->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down"))); uiWidget->addLayoutBtn->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); uiWidget->removeLayoutBtn->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); QIcon clearIcon = qApp->isLeftToRight() ? QIcon::fromTheme(QStringLiteral("edit-clear-locationbar-rtl")) : QIcon::fromTheme(QStringLiteral("edit-clear-locationbar-ltr")); uiWidget->xkbGrpClearBtn->setIcon(clearIcon); uiWidget->xkb3rdLevelClearBtn->setIcon(clearIcon); QIcon configIcon = QIcon::fromTheme(QStringLiteral("configure")); uiWidget->xkbGrpShortcutBtn->setIcon(configIcon); uiWidget->xkb3rdLevelShortcutBtn->setIcon(configIcon); uiWidget->kdeKeySequence->setModifierlessAllowed(false); connect(uiWidget->addLayoutBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::addLayout); connect(uiWidget->removeLayoutBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::removeLayout); // connect(uiWidget->layoutsTable, SIGNAL(itemSelectionChanged()), this, SLOT(layoutSelectionChanged())); connect(uiWidget->layoutsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KCMKeyboardWidget::layoutSelectionChanged); // connect(uiWidget->moveUpBtn, SIGNAL(triggered(QAction*)), this, SLOT(moveUp())); // connect(uiWidget->moveDownBtn, SIGNAL(triggered(QAction*)), this, SLOT(moveDown())); connect(uiWidget->moveUpBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::moveUp); connect(uiWidget->moveDownBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::moveDown); #ifdef NEW_GEOMETRY connect(uiWidget->previewButton, &QAbstractButton::clicked, this, &KCMKeyboardWidget::previewLayout); #endif connect(uiWidget->xkbGrpClearBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::clearGroupShortcuts); connect(uiWidget->xkb3rdLevelClearBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::clear3rdLevelShortcuts); // connect(uiWidget->xkbGrpClearBtn, SIGNAL(triggered(QAction*)), this, SLOT(uiChanged())); // connect(uiWidget->xkb3rdLevelClearBtn, SIGNAL(triggered(QAction*)), this, SLOT(uiChanged())); connect(uiWidget->kdeKeySequence, &KKeySequenceWidget::keySequenceChanged, this, &KCMKeyboardWidget::uiChanged); connect(uiWidget->switchingPolicyButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(uiChanged())); connect(uiWidget->xkbGrpShortcutBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::scrollToGroupShortcut); connect(uiWidget->xkb3rdLevelShortcutBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::scrollTo3rdLevelShortcut); // connect(uiWidget->configureLayoutsChk, SIGNAL(toggled(bool)), uiWidget->layoutsGroupBox, SLOT(setEnabled(bool))); connect(uiWidget->layoutsGroupBox, &QGroupBox::toggled, this, &KCMKeyboardWidget::configureLayoutsChanged); connect(uiWidget->showIndicatorChk, &QAbstractButton::clicked, this, &KCMKeyboardWidget::uiChanged); connect(uiWidget->showIndicatorChk, &QAbstractButton::toggled, uiWidget->showSingleChk, &QWidget::setEnabled); connect(uiWidget->showFlagRadioBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::uiChanged); connect(uiWidget->showLabelRadioBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::uiChanged); connect(uiWidget->showLabelOnFlagRadioBtn, &QAbstractButton::clicked, this, &KCMKeyboardWidget::uiChanged); connect(uiWidget->showSingleChk, &QAbstractButton::toggled, this, &KCMKeyboardWidget::uiChanged); connect(uiWidget->layoutLoopingCheckBox, &QAbstractButton::clicked, this, &KCMKeyboardWidget::uiChanged); connect(uiWidget->layoutLoopCountSpinBox, SIGNAL(valueChanged(int)), this, SLOT(uiChanged())); } #ifdef NEW_GEOMETRY void KCMKeyboardWidget::previewLayout(){ QModelIndex index = uiWidget->layoutsTableView->currentIndex(); QModelIndex idcountry = index.sibling(index.row(),0) ; QString country=uiWidget->layoutsTableView->model()->data(idcountry).toString(); QModelIndex idvariant = index.sibling(index.row(),2) ; QString variant=uiWidget->layoutsTableView->model()->data(idvariant).toString(); QString model = keyboardConfig->keyboardModel; KeyboardPainter layoutPreview; const LayoutInfo* layoutInfo = rules->getLayoutInfo(country); if (!layoutInfo) { return; } foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { if(variant==variantInfo->description){ variant=variantInfo->name; break; } } QString title = Flags::getLongText( LayoutUnit(country, variant), rules ); layoutPreview.generateKeyboardLayout(country,variant, model, title); layoutPreview.setModal(true); layoutPreview.exec(); } #endif void KCMKeyboardWidget::configureLayoutsChanged() { if( uiWidget->layoutsGroupBox->isChecked() && keyboardConfig->layouts.isEmpty() ) { populateWithCurrentLayouts(); } uiChanged(); } static QPair getSelectedRowRange(const QModelIndexList& selected) { if( selected.isEmpty() ) { return QPair(-1, -1); } QList rows; foreach(const QModelIndex& index, selected) { rows << index.row(); } qSort(rows); return QPair(rows[0], rows[rows.size()-1]); } void KCMKeyboardWidget::layoutSelectionChanged() { QModelIndexList selected = uiWidget->layoutsTableView->selectionModel()->selectedIndexes(); uiWidget->removeLayoutBtn->setEnabled( ! selected.isEmpty() ); QPair rowsRange( getSelectedRowRange(selected) ); uiWidget->moveUpBtn->setEnabled( ! selected.isEmpty() && rowsRange.first > 0); #ifdef NEW_GEOMETRY uiWidget->previewButton->setEnabled( uiWidget->layoutsTableView->selectionModel()->selectedRows().size() == 1 ); #else uiWidget->previewButton->setVisible(false); #endif uiWidget->moveDownBtn->setEnabled( ! selected.isEmpty() && rowsRange.second < keyboardConfig->layouts.size()-1 ); } void KCMKeyboardWidget::removeLayout() { if( ! uiWidget->layoutsTableView->selectionModel()->hasSelection() ) return; QModelIndexList selected = uiWidget->layoutsTableView->selectionModel()->selectedIndexes(); QPair rowsRange( getSelectedRowRange(selected) ); foreach(const QModelIndex& idx, selected) { if( idx.column() == 0 ) { keyboardConfig->layouts.removeAt(rowsRange.first); } } layoutsTableModel->refresh(); uiChanged(); if( keyboardConfig->layouts.size() > 0 ) { int rowToSelect = rowsRange.first; if( rowToSelect >= keyboardConfig->layouts.size() ) { rowToSelect--; } QModelIndex topLeft = layoutsTableModel->index(rowToSelect, 0, QModelIndex()); QModelIndex bottomRight = layoutsTableModel->index(rowToSelect, layoutsTableModel->columnCount(topLeft)-1, QModelIndex()); QItemSelection selection(topLeft, bottomRight); uiWidget->layoutsTableView->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); uiWidget->layoutsTableView->setFocus(); } layoutSelectionChanged(); updateLoopCount(); } void KCMKeyboardWidget::moveUp() { moveSelectedLayouts(-1); } void KCMKeyboardWidget::moveDown() { moveSelectedLayouts(1); } void KCMKeyboardWidget::moveSelectedLayouts(int shift) { QItemSelectionModel* selectionModel = uiWidget->layoutsTableView->selectionModel(); - if( selectionModel == NULL || !selectionModel->hasSelection() ) + if( selectionModel == nullptr || !selectionModel->hasSelection() ) return; QModelIndexList selected = selectionModel->selectedRows(); if( selected.count() < 1 ) return; int newFirstRow = selected[0].row() + shift; int newLastRow = selected[ selected.size()-1 ].row() + shift; if( newFirstRow >= 0 && newLastRow <= keyboardConfig->layouts.size() - 1 ) { QList selectionRows; foreach(const QModelIndex& index, selected) { int newRowIndex = index.row() + shift; keyboardConfig->layouts.move(index.row(), newRowIndex); selectionRows << newRowIndex; } uiChanged(); QItemSelection selection; foreach(int row, selectionRows) { QModelIndex topLeft = layoutsTableModel->index(row, 0, QModelIndex()); QModelIndex bottomRight = layoutsTableModel->index(row, layoutsTableModel->columnCount(topLeft)-1, QModelIndex()); selection << QItemSelectionRange(topLeft, bottomRight); } uiWidget->layoutsTableView->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); uiWidget->layoutsTableView->setFocus(); } } void KCMKeyboardWidget::scrollToGroupShortcut() { this->setCurrentIndex(TAB_ADVANCED); if( ! uiWidget->configureKeyboardOptionsChk->isChecked() ) { uiWidget->configureKeyboardOptionsChk->setChecked(true); } ((XkbOptionsTreeModel*)uiWidget->xkbOptionsTreeView->model())->gotoGroup(GROUP_SWITCH_GROUP_NAME, uiWidget->xkbOptionsTreeView); } void KCMKeyboardWidget::scrollTo3rdLevelShortcut() { this->setCurrentIndex(TAB_ADVANCED); if( ! uiWidget->configureKeyboardOptionsChk->isChecked() ) { uiWidget->configureKeyboardOptionsChk->setChecked(true); } ((XkbOptionsTreeModel*)uiWidget->xkbOptionsTreeView->model())->gotoGroup(LV3_SWITCH_GROUP_NAME, uiWidget->xkbOptionsTreeView); } void KCMKeyboardWidget::clearGroupShortcuts() { clearXkbGroup(GROUP_SWITCH_GROUP_NAME); } void KCMKeyboardWidget::clear3rdLevelShortcuts() { clearXkbGroup(LV3_SWITCH_GROUP_NAME); } void KCMKeyboardWidget::clearXkbGroup(const QString& groupName) { for(int ii=keyboardConfig->xkbOptions.count()-1; ii>=0; ii--) { if( keyboardConfig->xkbOptions[ii].startsWith(groupName + Rules::XKB_OPTION_GROUP_SEPARATOR) ) { keyboardConfig->xkbOptions.removeAt(ii); } } ((XkbOptionsTreeModel*)uiWidget->xkbOptionsTreeView->model())->reset(); uiWidget->xkbOptionsTreeView->update(); updateXkbShortcutsButtons(); emit changed(true); } static bool xkbOptionGroupLessThan(const OptionGroupInfo* og1, const OptionGroupInfo* og2) { return og1->description.toLower() < og2->description.toLower(); } static bool xkbOptionLessThan(const OptionInfo* o1, const OptionInfo* o2) { return o1->description.toLower() < o2->description.toLower(); } void KCMKeyboardWidget::initializeXkbOptionsUI() { qSort(rules->optionGroupInfos.begin(), rules->optionGroupInfos.end(), xkbOptionGroupLessThan); foreach(OptionGroupInfo* optionGroupInfo, rules->optionGroupInfos) { qSort(optionGroupInfo->optionInfos.begin(), optionGroupInfo->optionInfos.end(), xkbOptionLessThan); } XkbOptionsTreeModel* model = new XkbOptionsTreeModel(rules, keyboardConfig, uiWidget->xkbOptionsTreeView); uiWidget->xkbOptionsTreeView->setModel(model); connect(model, &QAbstractItemModel::dataChanged, this, &KCMKeyboardWidget::uiChanged); connect(uiWidget->configureKeyboardOptionsChk, &QAbstractButton::toggled, this, &KCMKeyboardWidget::configureXkbOptionsChanged); // connect(uiWidget->configureKeyboardOptionsChk, SIGNAL(toggled(bool)), this, SLOT(uiChanged())); connect(uiWidget->configureKeyboardOptionsChk, &QAbstractButton::toggled, uiWidget->xkbOptionsTreeView, &QWidget::setEnabled); } void KCMKeyboardWidget::configureXkbOptionsChanged() { if( uiWidget->configureKeyboardOptionsChk->isChecked() && keyboardConfig->xkbOptions.isEmpty() ) { populateWithCurrentXkbOptions(); } ((XkbOptionsTreeModel*)uiWidget->xkbOptionsTreeView->model())->reset(); uiChanged(); } void KCMKeyboardWidget::updateSwitcingPolicyUI() { switch (keyboardConfig->switchingPolicy){ case KeyboardConfig::SWITCH_POLICY_DESKTOP: uiWidget->switchByDesktopRadioBtn->setChecked(true); break; case KeyboardConfig::SWITCH_POLICY_APPLICATION: uiWidget->switchByApplicationRadioBtn->setChecked(true); break; case KeyboardConfig::SWITCH_POLICY_WINDOW: uiWidget->switchByWindowRadioBtn->setChecked(true); break; default: case KeyboardConfig::SWITCH_POLICY_GLOBAL: uiWidget->switchByGlobalRadioBtn->setChecked(true); } } void KCMKeyboardWidget::updateXkbShortcutButton(const QString& groupName, QPushButton* button) { QStringList grpOptions; if( keyboardConfig->resetOldXkbOptions ) { QRegExp regexp = QRegExp("^" + groupName + Rules::XKB_OPTION_GROUP_SEPARATOR); grpOptions = keyboardConfig->xkbOptions.filter(regexp); } switch( grpOptions.size() ) { case 0: button->setText(i18nc("no shortcuts defined", "None")); break; case 1: { const QString& option = grpOptions.first(); const OptionGroupInfo* optionGroupInfo = rules->getOptionGroupInfo(groupName); const OptionInfo* optionInfo = optionGroupInfo->getOptionInfo(option); - if( optionInfo == NULL || optionInfo->description == NULL ) { + if( optionInfo == nullptr || optionInfo->description == nullptr ) { qCDebug(KCM_KEYBOARD) << "Could not find option info for " << option; button->setText(grpOptions.first()); } else { button->setText(optionInfo->description); } } break; default: button->setText(i18np("%1 shortcut", "%1 shortcuts", grpOptions.size())); } } void KCMKeyboardWidget::updateXkbShortcutsButtons() { updateXkbShortcutButton(GROUP_SWITCH_GROUP_NAME, uiWidget->xkbGrpShortcutBtn); updateXkbShortcutButton(LV3_SWITCH_GROUP_NAME, uiWidget->xkb3rdLevelShortcutBtn); } void KCMKeyboardWidget::updateShortcutsUI() { updateXkbShortcutsButtons(); delete actionCollection; actionCollection = new KeyboardLayoutActionCollection(this, true); QAction* toggleAction = actionCollection->getToggleAction(); const auto shortcuts = KGlobalAccel::self()->shortcut(toggleAction); uiWidget->kdeKeySequence->setKeySequence(shortcuts.isEmpty() ? QKeySequence() : shortcuts.first()); actionCollection->loadLayoutShortcuts(keyboardConfig->layouts, rules); layoutsTableModel->refresh(); } void KCMKeyboardWidget::updateXkbOptionsUI() { uiWidget->configureKeyboardOptionsChk->setChecked(keyboardConfig->resetOldXkbOptions); } void KCMKeyboardWidget::updateLayoutsUI() { uiWidget->layoutsGroupBox->setChecked(keyboardConfig->configureLayouts); uiWidget->showIndicatorChk->setChecked(keyboardConfig->showIndicator); uiWidget->showSingleChk->setChecked(keyboardConfig->showSingle); uiWidget->showFlagRadioBtn->setChecked(keyboardConfig->indicatorType == KeyboardConfig::SHOW_FLAG); uiWidget->showLabelRadioBtn->setChecked(keyboardConfig->indicatorType == KeyboardConfig::SHOW_LABEL); uiWidget->showLabelOnFlagRadioBtn->setChecked(keyboardConfig->indicatorType == KeyboardConfig::SHOW_LABEL_ON_FLAG); bool loopingOn = keyboardConfig->configureLayouts && keyboardConfig->layoutLoopCount != KeyboardConfig::NO_LOOPING; uiWidget->layoutLoopingCheckBox->setChecked(loopingOn); uiWidget->layoutLoopingGroupBox->setEnabled(loopingOn); if( loopingOn ) { // Set maximum to 99 to make sure following setValue succeeds // Correct maximum value will be set in updateLoopCount() uiWidget->layoutLoopCountSpinBox->setMaximum(99); uiWidget->layoutLoopCountSpinBox->setValue(keyboardConfig->layoutLoopCount); } else { uiWidget->layoutLoopCountSpinBox->clear(); } updateLoopCount(); } void KCMKeyboardWidget::updateHardwareUI() { int idx = uiWidget->keyboardModelComboBox->findData(keyboardConfig->keyboardModel); if( idx != -1 ) { uiWidget->keyboardModelComboBox->setCurrentIndex(idx); } } void KCMKeyboardWidget::populateWithCurrentLayouts() { QList layouts = X11Helper::getLayoutsList(); foreach(LayoutUnit layoutUnit, layouts) { keyboardConfig->layouts.append(layoutUnit); } } void KCMKeyboardWidget::populateWithCurrentXkbOptions() { if (!KWindowSystem::isPlatformX11()) { // TODO: implement for Wayland - query dbus maybe? return; } XkbConfig xkbConfig; if( X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::ALL) ) { foreach(QString xkbOption, xkbConfig.options) { keyboardConfig->xkbOptions.append(xkbOption); } } } diff --git a/kcms/keyboard/kcm_keyboard_widget.h b/kcms/keyboard/kcm_keyboard_widget.h index 86b45f318..5e2e97f28 100644 --- a/kcms/keyboard/kcm_keyboard_widget.h +++ b/kcms/keyboard/kcm_keyboard_widget.h @@ -1,103 +1,103 @@ /* * 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. */ #ifndef KCM_KEYBOARD_WIDGET_H_ #define KCM_KEYBOARD_WIDGET_H_ #include "ui_kcm_keyboard.h" #include #include class QWidget; class KeyboardConfig; struct Rules; class Flags; class QString; class QPushButton; class LayoutsTableModel; class KCMiscKeyboardWidget; class KeyboardLayoutActionCollection; class KCMKeyboardWidget: public QTabWidget { Q_OBJECT public: KCMKeyboardWidget(Rules* rules, KeyboardConfig* keyboardConfig, - const QVariantList &args, QWidget* parent=0); + const QVariantList &args, QWidget* parent=nullptr); ~KCMKeyboardWidget() override; void updateUI(); void save(); //temp hack KCMiscKeyboardWidget* getKcmMiscWidget() const { return kcmMiscWidget; } Q_SIGNALS: void changed(bool state); private Q_SLOTS: void addLayout(); void removeLayout(); void layoutSelectionChanged(); void uiChanged(); void scrollToGroupShortcut(); void scrollTo3rdLevelShortcut(); void clearGroupShortcuts(); void clear3rdLevelShortcuts(); void updateXkbShortcutsButtons(); void moveUp(); void moveDown(); void configureLayoutsChanged(); void configureXkbOptionsChanged(); #ifdef NEW_GEOMETRY void previewLayout(); #endif private: Rules *rules; Flags *flags; Ui::TabWidget *uiWidget; KeyboardConfig *keyboardConfig; KeyboardLayoutActionCollection* actionCollection; LayoutsTableModel* layoutsTableModel; KCMiscKeyboardWidget* kcmMiscWidget; bool uiUpdating; void initializeLayoutsUI(); void initializeXkbOptionsUI(); void initializeKeyboardModelUI(); void updateHardwareUI(); void updateLayoutsUI(); void updateShortcutsUI(); void updateXkbOptionsUI(); void updateSwitcingPolicyUI(); void updateXkbShortcutButton(const QString& groupName, QPushButton* button); void clearXkbGroup(const QString& groupName); void moveSelectedLayouts(int shift); void populateWithCurrentLayouts(); void populateWithCurrentXkbOptions(); void updateLoopCount(); void handleParameters(const QVariantList &args); }; #endif /* KCM_KEYBOARD_WIDGET_H_ */ diff --git a/kcms/keyboard/kcm_view_models.cpp b/kcms/keyboard/kcm_view_models.cpp index 409eccd2f..f85039ece 100644 --- a/kcms/keyboard/kcm_view_models.cpp +++ b/kcms/keyboard/kcm_view_models.cpp @@ -1,521 +1,521 @@ /* * 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 "kcm_view_models.h" #include #include #include #include #include #include #include #ifdef DRAG_ENABLED #include #endif #include "keyboard_config.h" #include "xkb_rules.h" #include "flags.h" #include "x11_helper.h" #include "bindings.h" const int LayoutsTableModel::MAP_COLUMN = 0; const int LayoutsTableModel::LAYOUT_COLUMN = 1; const int LayoutsTableModel::VARIANT_COLUMN = 2; const int LayoutsTableModel::DISPLAY_NAME_COLUMN = 3; const int LayoutsTableModel::SHORTCUT_COLUMN = 4; static const int COLUMN_COUNT = 5; LayoutsTableModel::LayoutsTableModel(Rules* rules_, Flags *flags_, KeyboardConfig* keyboardConfig_, QObject* parent): QAbstractTableModel(parent), keyboardConfig(keyboardConfig_), rules(rules_), countryFlags(flags_) { } void LayoutsTableModel::refresh() { beginResetModel(); endResetModel(); countryFlags->clearCache(); } int LayoutsTableModel::rowCount(const QModelIndex &/*parent*/) const { return keyboardConfig->layouts.count(); } int LayoutsTableModel::columnCount(const QModelIndex&) const { return COLUMN_COUNT; } Qt::ItemFlags LayoutsTableModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return 0; + return nullptr; Qt::ItemFlags flags = QAbstractTableModel::flags(index); if( index.column() == DISPLAY_NAME_COLUMN || index.column() == VARIANT_COLUMN || index.column() == SHORTCUT_COLUMN ) { flags |= Qt::ItemIsEditable; } #ifdef DRAG_ENABLED flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; #endif return flags; } #ifdef DRAG_ENABLED QStringList LayoutsTableModel::mimeTypes() const { QStringList types; types << "application/keyboard-layout-item"; return types; } QMimeData *LayoutsTableModel::mimeData(const QModelIndexList &indexes) const { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QSet rows; foreach (const QModelIndex& index, indexes) { if (index.isValid()) { rows << index.row(); } } foreach (int row, rows) { stream << row; } mimeData->setData("application/keyboard-layout-item", encodedData); return mimeData; } #endif QVariant LayoutsTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= keyboardConfig->layouts.size()) return QVariant(); const LayoutUnit& layoutUnit = keyboardConfig->layouts.at(index.row()); if (role == Qt::DecorationRole) { switch( index.column() ) { case DISPLAY_NAME_COLUMN: { // if( keyboardConfig->isFlagShown() ) { QIcon icon = countryFlags->getIconWithText(layoutUnit, *keyboardConfig); return icon.isNull() ? countryFlags->getTransparentPixmap() : icon; // } } //TODO: show the cells are editable // case VARIANT_COLUMN: { // case DISPLAY_NAME_COLUMN: { // int sz = 5; // QPixmap pm = QPixmap(sz, sz+5); // pm.fill(Qt::transparent); // QPainter p(&pm); // QPoint points[] = { QPoint(0, 0), QPoint(0, sz), QPoint(sz, 0) }; // p.drawPolygon(points, 3); // return pm; // } break; } } else if( role == Qt::BackgroundRole ) { if( keyboardConfig->layoutLoopCount != KeyboardConfig::NO_LOOPING && index.row() >= keyboardConfig->layoutLoopCount ) { return QBrush(Qt::lightGray); } } else if (role == Qt::DisplayRole) { switch( index.column() ) { case MAP_COLUMN: return layoutUnit.layout; break; case LAYOUT_COLUMN: { const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout); - return layoutInfo != NULL ? layoutInfo->description : layoutUnit.layout; + return layoutInfo != nullptr ? layoutInfo->description : layoutUnit.layout; } case VARIANT_COLUMN: { if( layoutUnit.variant.isEmpty() ) return QVariant(); const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout); - if( layoutInfo == NULL ) + if( layoutInfo == nullptr ) return QVariant(); const VariantInfo* variantInfo = layoutInfo->getVariantInfo(layoutUnit.variant); - return variantInfo != NULL ? variantInfo->description : layoutUnit.variant; + return variantInfo != nullptr ? variantInfo->description : layoutUnit.variant; } break; case DISPLAY_NAME_COLUMN: // if( keyboardConfig->indicatorType == KeyboardConfig::SHOW_LABEL ) { // return layoutUnit.getDisplayName(); // } break; case SHORTCUT_COLUMN: { return layoutUnit.getShortcut().toString(); } break; } } else if (role==Qt::EditRole ) { switch( index.column() ) { case DISPLAY_NAME_COLUMN: return layoutUnit.getDisplayName(); break; case VARIANT_COLUMN: return layoutUnit.variant; break; case SHORTCUT_COLUMN: return layoutUnit.getShortcut().toString(); break; default:; } } else if( role == Qt::TextAlignmentRole ) { switch( index.column() ) { case MAP_COLUMN: case DISPLAY_NAME_COLUMN: case SHORTCUT_COLUMN: return Qt::AlignCenter; break; default:; } } return QVariant(); } QVariant LayoutsTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { const QString headers[] = {i18nc("layout map name", "Map"), i18n("Layout"), i18n("Variant"), i18n("Label"), i18n("Shortcut")}; return headers[section]; } return QVariant(); } bool LayoutsTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role != Qt::EditRole || (index.column() != DISPLAY_NAME_COLUMN && index.column() != VARIANT_COLUMN && index.column() != SHORTCUT_COLUMN) ) return false; if (index.row() >= keyboardConfig->layouts.size() || index.data(role) == value) return false; LayoutUnit& layoutUnit = keyboardConfig->layouts[index.row()]; switch( index.column() ) { case DISPLAY_NAME_COLUMN: { QString displayText = value.toString().left(3); layoutUnit.setDisplayName(displayText); countryFlags->clearCache(); // regenerate the label } break; case VARIANT_COLUMN: { QString variant = value.toString(); layoutUnit.variant = variant; } break; case SHORTCUT_COLUMN: { QString shortcut = value.toString(); layoutUnit.setShortcut(QKeySequence(shortcut)); } break; } emit dataChanged(index, index); return true; } // // LabelEditDelegate // LabelEditDelegate::LabelEditDelegate(const KeyboardConfig* keyboardConfig_, QObject *parent): QStyledItemDelegate(parent), keyboardConfig(keyboardConfig_) {} QWidget *LabelEditDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option , const QModelIndex & index ) const { if( keyboardConfig->indicatorType == KeyboardConfig::SHOW_FLAG ) - return NULL; + return nullptr; QWidget* widget = QStyledItemDelegate::createEditor(parent, option, index); QLineEdit* lineEdit = static_cast(widget); - if( lineEdit != NULL ) { + if( lineEdit != nullptr ) { lineEdit->setMaxLength(LayoutUnit::MAX_LABEL_LENGTH); connect(lineEdit, &QLineEdit::textEdited, this, [this, lineEdit]() { Q_EMIT const_cast(this)->commitData(lineEdit); }); } return widget; } void LabelEditDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } //void LabelEditDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const //{ // QStyleOptionViewItem option2(option); //// option2.decorationPosition = QStyleOptionViewItem::Right; // option2.decorationAlignment = Qt::AlignHCenter | Qt::AlignVCenter; // QStyledItemDelegate::paint(painter, option2, index); //} // // VariantComboDelegate // //TODO: reuse this function in kcm_add_layout_dialog.cpp static void populateComboWithVariants(QComboBox* combo, const QString& layout, const Rules* rules) { combo->clear(); const LayoutInfo* layoutInfo = rules->getLayoutInfo(layout); foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { combo->addItem(variantInfo->description, variantInfo->name); } combo->model()->sort(0); combo->insertItem(0, i18nc("variant", "Default"), ""); combo->setCurrentIndex(0); } VariantComboDelegate::VariantComboDelegate(const KeyboardConfig* keyboardConfig_, const Rules* rules_, QObject *parent): QStyledItemDelegate(parent), keyboardConfig(keyboardConfig_), rules(rules_) {} QWidget *VariantComboDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex & index ) const { QComboBox *editor = new QComboBox(parent); const LayoutUnit& layoutUnit = keyboardConfig->layouts[index.row()]; populateComboWithVariants(editor, layoutUnit.layout, rules); connect(editor, &QComboBox::currentTextChanged, this, [this, editor]() { Q_EMIT const_cast(this)->commitData(editor); }); return editor; } void VariantComboDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QComboBox *combo = static_cast(editor); QString variant = index.model()->data(index, Qt::EditRole).toString(); int itemIndex = combo->findData(variant); if( itemIndex == -1 ) { itemIndex = 0; } combo->setCurrentIndex(itemIndex); } void VariantComboDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *combo = static_cast(editor); QString variant = combo->itemData(combo->currentIndex()).toString(); model->setData(index, variant, Qt::EditRole); } void VariantComboDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } // // KKeySequenceWidgetDelegate // KKeySequenceWidgetDelegate::KKeySequenceWidgetDelegate(const KeyboardConfig* keyboardConfig_, QObject *parent): QStyledItemDelegate(parent), keyboardConfig(keyboardConfig_) {} QWidget *KKeySequenceWidgetDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & index ) const { itemsBeingEdited.insert(index); KKeySequenceWidget *editor = new KKeySequenceWidget(parent); editor->setFocusPolicy(Qt::StrongFocus); editor->setModifierlessAllowed(false); const LayoutUnit& layoutUnit = keyboardConfig->layouts[index.row()]; editor->setKeySequence(layoutUnit.getShortcut()); editor->captureKeySequence(); connect(editor, &KKeySequenceWidget::keySequenceChanged, this, [this, editor]() { Q_EMIT const_cast(this)->commitData(editor); }); return editor; } //void KKeySequenceWidgetDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const //{ // KKeySequenceWidget *kkeysequencewidget = static_cast(editor); // QString shortcut = index.model()->data(index, Qt::EditRole).toString(); // kkeysequencewidget->setKeySequence(QKeySequence(shortcut)); // kkeysequencewidget->captureKeySequence(); // qDebug() << "set editor data"; //} void KKeySequenceWidgetDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { KKeySequenceWidget *kkeysequencewidget = static_cast(editor); QString shortcut = kkeysequencewidget->keySequence().toString(); model->setData(index, shortcut, Qt::EditRole); itemsBeingEdited.remove(index); } void KKeySequenceWidgetDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { if (itemsBeingEdited.contains(index)) { // StyledBackgroundPainter::drawBackground(painter,option,index); } else { QStyledItemDelegate::paint(painter,option,index); } } // // Xkb Options Tree View // int XkbOptionsTreeModel::rowCount(const QModelIndex& parent) const { if( ! parent.isValid() ) return rules->optionGroupInfos.count(); if( ! parent.parent().isValid() ) return rules->optionGroupInfos[parent.row()]->optionInfos.count(); return 0; } QVariant XkbOptionsTreeModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); int row = index.row(); if (role == Qt::DisplayRole) { if( ! index.parent().isValid() ) { return rules->optionGroupInfos[row]->description; } else { int groupRow = index.parent().row(); const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; return xkbGroup->optionInfos[row]->description; } } else if (role==Qt::CheckStateRole ) { if( index.parent().isValid() ) { int groupRow = index.parent().row(); const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; const QString& xkbOptionName = xkbGroup->optionInfos[row]->name; return keyboardConfig->xkbOptions.indexOf(xkbOptionName) == -1 ? Qt::Unchecked : Qt::Checked; } else { int groupRow = index.row(); const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; foreach(const OptionInfo* optionInfo, xkbGroup->optionInfos) { if( keyboardConfig->xkbOptions.indexOf(optionInfo->name) != -1 ) return Qt::PartiallyChecked; } return Qt::Unchecked; } } return QVariant(); } bool XkbOptionsTreeModel::setData(const QModelIndex & index, const QVariant & value, int role) { int groupRow = index.parent().row(); if( groupRow < 0 ) return false; const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; const OptionInfo* option = xkbGroup->optionInfos[index.row()]; if( value.toInt() == Qt::Checked ) { if( xkbGroup->exclusive ) { // clear if exclusive (TODO: radiobutton) int idx = keyboardConfig->xkbOptions.indexOf(QRegExp(xkbGroup->name + ".*")); if( idx >= 0 ) { for(int i=0; ioptionInfos.count(); i++) if( xkbGroup->optionInfos[i]->name == keyboardConfig->xkbOptions[idx] ) { setData(createIndex(i, index.column(), (quint32)index.internalId()-index.row()+i), Qt::Unchecked, role); break; } // m_kxkbConfig->m_options.removeAt(idx); // idx = m_kxkbConfig->m_options.indexOf(QRegExp(xkbGroupNm+".*")); } } if( keyboardConfig->xkbOptions.indexOf(option->name) < 0 ) { keyboardConfig->xkbOptions.append(option->name); } } else { keyboardConfig->xkbOptions.removeAll(option->name); } emit dataChanged(index, index); emit dataChanged(index.parent(), index.parent()); return true; } void XkbOptionsTreeModel::gotoGroup(const QString& groupName, QTreeView* view) { const OptionGroupInfo* optionGroupInfo = rules->getOptionGroupInfo(groupName); int index = rules->optionGroupInfos.indexOf((OptionGroupInfo*)optionGroupInfo); if( index != -1 ) { QModelIndex modelIdx = createIndex(index,0); // view->selectionModel()->setCurrentIndex(createIndex(index,0), QItemSelectionModel::NoUpdate); view->setExpanded(modelIdx, true); view->scrollTo(modelIdx, QAbstractItemView::PositionAtTop); view->selectionModel()->setCurrentIndex(modelIdx, QItemSelectionModel::Current); view->setFocus(Qt::OtherFocusReason); } // else { // qDebug() << "can't scroll to group" << group; // } } diff --git a/kcms/keyboard/kcm_view_models.h b/kcms/keyboard/kcm_view_models.h index bc712318d..006541943 100644 --- a/kcms/keyboard/kcm_view_models.h +++ b/kcms/keyboard/kcm_view_models.h @@ -1,175 +1,175 @@ /* * 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. */ #ifndef KCM_VIEW_MODELS_H_ #define KCM_VIEW_MODELS_H_ #include #include #include #include class QTreeView; class KeyboardConfig; struct Rules; class Flags; class LayoutsTableModel : public QAbstractTableModel { Q_OBJECT public: LayoutsTableModel(Rules* rules, Flags *flags, KeyboardConfig* keyboardConfig, QObject *parent = nullptr); int columnCount(const QModelIndex&) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; #ifdef DRAG_ENABLED Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } QStringList mimeTypes() const; QMimeData *mimeData(const QModelIndexList &indexes) const; #endif void refresh(); static const int MAP_COLUMN; static const int LAYOUT_COLUMN; static const int VARIANT_COLUMN; static const int DISPLAY_NAME_COLUMN; static const int SHORTCUT_COLUMN; private: KeyboardConfig* keyboardConfig; const Rules *rules; Flags *countryFlags; }; class LabelEditDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit LabelEditDelegate(const KeyboardConfig* keyboardConfig, QObject *parent = nullptr); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; // void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; private: const KeyboardConfig* keyboardConfig; }; class VariantComboDelegate : public QStyledItemDelegate { Q_OBJECT public: VariantComboDelegate(const KeyboardConfig* keyboardConfig, const Rules* rules, QObject *parent = nullptr); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setEditorData(QWidget *editor, const QModelIndex &index) const override; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: const KeyboardConfig* keyboardConfig; const Rules* rules; }; class KKeySequenceWidgetDelegate : public QStyledItemDelegate { Q_OBJECT public: KKeySequenceWidgetDelegate(const KeyboardConfig* keyboardConfig_, QObject *parent = nullptr); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; // void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; private: const KeyboardConfig* keyboardConfig; mutable QSet itemsBeingEdited; }; class XkbOptionsTreeModel: public QAbstractItemModel { public: XkbOptionsTreeModel(Rules* rules_, KeyboardConfig* keyboardConfig_, QObject *parent) : QAbstractItemModel(parent), keyboardConfig(keyboardConfig_), rules(rules_) { } int columnCount(const QModelIndex& /*parent*/) const override { return 1; } int rowCount(const QModelIndex& parent) const override; QModelIndex parent(const QModelIndex& index) const override { if (!index.isValid() ) return QModelIndex(); if( index.internalId() < 100 ) return QModelIndex(); return createIndex(((index.internalId() - index.row())/100) - 1, index.column()); } QModelIndex index(int row, int column, const QModelIndex& parent) const override { if(!parent.isValid()) return createIndex(row, column); return createIndex(row, column, (100 * (parent.row()+1)) + row); } Qt::ItemFlags flags ( const QModelIndex & index ) const override { if( ! index.isValid() ) - return 0; + return nullptr; if( !index.parent().isValid() ) return Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable; } bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ) override; QVariant data(const QModelIndex& index, int role) const override; void reset() { beginResetModel(); endResetModel(); } void gotoGroup(const QString& group, QTreeView* view); private: KeyboardConfig* keyboardConfig; Rules *rules; }; #endif /* KCM_VIEW_MODELS_H_ */ diff --git a/kcms/keyboard/keyboard_config.cpp b/kcms/keyboard/keyboard_config.cpp index 6c2d14b49..733e67f0b 100644 --- a/kcms/keyboard/keyboard_config.cpp +++ b/kcms/keyboard/keyboard_config.cpp @@ -1,208 +1,208 @@ /* * 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 "keyboard_config.h" #include "debug.h" #include #include -static const char* const SWITCHING_POLICIES[] = {"Global", "Desktop", "WinClass", "Window", NULL }; +static const char* const SWITCHING_POLICIES[] = {"Global", "Desktop", "WinClass", "Window", nullptr }; static const char LIST_SEPARATOR[] = ","; //static const char* DEFAULT_LAYOUT = "us"; static const char DEFAULT_MODEL[] = "pc104"; static const QString CONFIG_FILENAME(QStringLiteral("kxkbrc")); static const QString CONFIG_GROUPNAME(QStringLiteral("Layout")); const int KeyboardConfig::NO_LOOPING = -1; KeyboardConfig::KeyboardConfig() { setDefaults(); } QString KeyboardConfig::getSwitchingPolicyString(SwitchingPolicy switchingPolicy) { return SWITCHING_POLICIES[switchingPolicy]; } static int findStringIndex(const char* const strings[], const QString& toFind, int defaultIndex) { - for(int i=0; strings[i] != NULL; i++) { + for(int i=0; strings[i] != nullptr; i++) { if( toFind == strings[i] ) { return i; } } return defaultIndex; } void KeyboardConfig::setDefaults() { keyboardModel = DEFAULT_MODEL; resetOldXkbOptions = false; xkbOptions.clear(); // init layouts options configureLayouts = false; layouts.clear(); // layouts.append(LayoutUnit(DEFAULT_LAYOUT)); layoutLoopCount = NO_LOOPING; // switch control options switchingPolicy = SWITCH_POLICY_GLOBAL; // stickySwitching = false; // stickySwitchingDepth = 2; // display options showIndicator = true; indicatorType = SHOW_LABEL; showSingle = false; } static KeyboardConfig::IndicatorType getIndicatorType(bool showFlag, bool showLabel) { if( showFlag ) { if( showLabel ) return KeyboardConfig::SHOW_LABEL_ON_FLAG; else return KeyboardConfig::SHOW_FLAG; } else { return KeyboardConfig::SHOW_LABEL; } } void KeyboardConfig::load() { KConfigGroup config(KSharedConfig::openConfig( CONFIG_FILENAME, KConfig::NoGlobals ), CONFIG_GROUPNAME); keyboardModel = config.readEntry("Model", ""); resetOldXkbOptions = config.readEntry("ResetOldOptions", false); QString options = config.readEntry("Options", ""); xkbOptions = options.split(LIST_SEPARATOR, QString::SkipEmptyParts); configureLayouts = config.readEntry("Use", false); QString layoutsString = config.readEntry("LayoutList", ""); QStringList layoutStrings = layoutsString.split(LIST_SEPARATOR, QString::SkipEmptyParts); // if( layoutStrings.isEmpty() ) { // layoutStrings.append(DEFAULT_LAYOUT); // } layouts.clear(); foreach(const QString& layoutString, layoutStrings) { layouts.append(LayoutUnit(layoutString)); } if( layouts.isEmpty() ) { configureLayouts = false; } layoutLoopCount = config.readEntry("LayoutLoopCount", NO_LOOPING); QString layoutMode = config.readEntry("SwitchMode", "Global"); switchingPolicy = static_cast(findStringIndex(SWITCHING_POLICIES, layoutMode, SWITCH_POLICY_GLOBAL)); showIndicator = config.readEntry("ShowLayoutIndicator", true); bool showFlag = config.readEntry("ShowFlag", false); bool showLabel = config.readEntry("ShowLabel", true); indicatorType = getIndicatorType(showFlag, showLabel); showSingle = config.readEntry("ShowSingle", false); QString labelsStr = config.readEntry("DisplayNames", ""); QStringList labels = labelsStr.split(LIST_SEPARATOR, QString::KeepEmptyParts); for(int i=0; i KeyboardConfig::getDefaultLayouts() const { QList defaultLayoutList; int i = 0; foreach(const LayoutUnit& layoutUnit, layouts) { defaultLayoutList.append(layoutUnit); if( layoutLoopCount != KeyboardConfig::NO_LOOPING && i >= layoutLoopCount-1 ) break; i++; } return defaultLayoutList; } QList KeyboardConfig::getExtraLayouts() const { if( layoutLoopCount == KeyboardConfig::NO_LOOPING ) return QList(); return layouts.mid(layoutLoopCount, layouts.size()); } diff --git a/kcms/keyboard/keyboard_daemon.cpp b/kcms/keyboard/keyboard_daemon.cpp index 9fed73d6b..ad7ecc2d9 100644 --- a/kcms/keyboard/keyboard_daemon.cpp +++ b/kcms/keyboard/keyboard_daemon.cpp @@ -1,249 +1,249 @@ /* * 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 "keyboard_daemon.h" #include "debug.h" #include #include #include #include #include #include #include #include "x11_helper.h" #include "xinput_helper.h" #include "xkb_helper.h" #include "keyboard_dbus.h" #include "xkb_rules.h" #include "bindings.h" #include "keyboard_hardware.h" #include "layout_tray_icon.h" #include "layout_memory_persister.h" #include "layouts_menu.h" K_PLUGIN_FACTORY_WITH_JSON(KeyboardFactory, "keyboard.json", registerPlugin();) KeyboardDaemon::KeyboardDaemon(QObject *parent, const QList&) : KDEDModule(parent), - actionCollection(NULL), - xEventNotifier(NULL), - layoutTrayIcon(NULL), + actionCollection(nullptr), + xEventNotifier(nullptr), + layoutTrayIcon(nullptr), layoutMemory(keyboardConfig), rules(Rules::readRules(Rules::READ_EXTRAS)) { - if( ! X11Helper::xkbSupported(NULL) ) + if( ! X11Helper::xkbSupported(nullptr) ) return; //TODO: shut down the daemon? QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerService(KEYBOARD_DBUS_SERVICE_NAME); dbus.registerObject(KEYBOARD_DBUS_OBJECT_PATH, this, QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportScriptableSignals); dbus.connect(QString(), KEYBOARD_DBUS_OBJECT_PATH, KEYBOARD_DBUS_SERVICE_NAME, KEYBOARD_DBUS_CONFIG_RELOAD_MESSAGE, this, SLOT(configureKeyboard())); configureKeyboard(); registerListeners(); LayoutMemoryPersister layoutMemoryPersister(layoutMemory); if( layoutMemoryPersister.restore() ) { if( layoutMemoryPersister.getGlobalLayout().isValid() ) { X11Helper::setLayout(layoutMemoryPersister.getGlobalLayout()); } } } KeyboardDaemon::~KeyboardDaemon() { LayoutMemoryPersister layoutMemoryPersister(layoutMemory); layoutMemoryPersister.setGlobalLayout(currentLayout); layoutMemoryPersister.save(); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.disconnect(QString(), KEYBOARD_DBUS_OBJECT_PATH, KEYBOARD_DBUS_SERVICE_NAME, KEYBOARD_DBUS_CONFIG_RELOAD_MESSAGE, this, SLOT(configureKeyboard())); dbus.unregisterObject(KEYBOARD_DBUS_OBJECT_PATH); dbus.unregisterService(KEYBOARD_DBUS_SERVICE_NAME); unregisterListeners(); unregisterShortcut(); delete xEventNotifier; delete layoutTrayIcon; delete rules; } void KeyboardDaemon::configureKeyboard() { qCDebug(KCM_KEYBOARD) << "Configuring keyboard"; init_keyboard_hardware(); keyboardConfig.load(); XkbHelper::initializeKeyboardLayouts(keyboardConfig); layoutMemory.configChanged(); setupTrayIcon(); unregisterShortcut(); registerShortcut(); } void KeyboardDaemon::configureMouse() { QStringList modules; modules << QStringLiteral("mouse"); QProcess::startDetached(QStringLiteral("kcminit"), modules); } void KeyboardDaemon::setupTrayIcon() { bool show = keyboardConfig.showIndicator && ( keyboardConfig.showSingle || X11Helper::getLayoutsList().size() > 1 ); if( show && ! layoutTrayIcon ) { layoutTrayIcon = new LayoutTrayIcon(rules, keyboardConfig); } else if( ! show && layoutTrayIcon ) { delete layoutTrayIcon; - layoutTrayIcon = NULL; + layoutTrayIcon = nullptr; } } void KeyboardDaemon::registerShortcut() { - if( actionCollection == NULL ) { + if( actionCollection == nullptr ) { actionCollection = new KeyboardLayoutActionCollection(this, false); QAction* toggleLayoutAction = actionCollection->getToggleAction(); connect(toggleLayoutAction, &QAction::triggered, this, &KeyboardDaemon::switchToNextLayout); actionCollection->loadLayoutShortcuts(keyboardConfig.layouts, rules); connect(actionCollection, SIGNAL(actionTriggered(QAction*)), this, SLOT(setLayout(QAction*))); } } void KeyboardDaemon::unregisterShortcut() { // register KDE keyboard shortcut for switching layouts - if( actionCollection != NULL ) { + if( actionCollection != nullptr ) { disconnect(actionCollection, SIGNAL(actionTriggered(QAction*)), this, SLOT(setLayout(QAction*))); disconnect(actionCollection->getToggleAction(), &QAction::triggered, this, &KeyboardDaemon::switchToNextLayout); delete actionCollection; - actionCollection = NULL; + actionCollection = nullptr; } } void KeyboardDaemon::registerListeners() { - if( xEventNotifier == NULL ) { + if( xEventNotifier == nullptr ) { xEventNotifier = new XInputEventNotifier(); } connect(xEventNotifier, &XInputEventNotifier::newPointerDevice, this, &KeyboardDaemon::configureMouse); connect(xEventNotifier, &XInputEventNotifier::newKeyboardDevice, this, &KeyboardDaemon::configureKeyboard); connect(xEventNotifier, &XEventNotifier::layoutMapChanged, this, &KeyboardDaemon::layoutMapChanged); connect(xEventNotifier, &XEventNotifier::layoutChanged, this, &KeyboardDaemon::layoutChanged); xEventNotifier->start(); } void KeyboardDaemon::unregisterListeners() { - if( xEventNotifier != NULL ) { + if( xEventNotifier != nullptr ) { xEventNotifier->stop(); disconnect(xEventNotifier, &XInputEventNotifier::newPointerDevice, this, &KeyboardDaemon::configureMouse); disconnect(xEventNotifier, &XInputEventNotifier::newKeyboardDevice, this, &KeyboardDaemon::configureKeyboard); disconnect(xEventNotifier, &XEventNotifier::layoutChanged, this, &KeyboardDaemon::layoutChanged); disconnect(xEventNotifier, &XEventNotifier::layoutMapChanged, this, &KeyboardDaemon::layoutMapChanged); } } void KeyboardDaemon::layoutChanged() { //TODO: pass newLayout into layoutTrayIcon? LayoutUnit newLayout = X11Helper::getCurrentLayout(); layoutMemory.layoutChanged(); - if( layoutTrayIcon != NULL ) { + if( layoutTrayIcon != nullptr ) { layoutTrayIcon->layoutChanged(); } if( newLayout != currentLayout ) { currentLayout = newLayout; emit currentLayoutChanged(newLayout.toString()); } } void KeyboardDaemon::layoutMapChanged() { keyboardConfig.load(); layoutMemory.layoutMapChanged(); emit layoutListChanged(); - if( layoutTrayIcon != NULL ) { + if( layoutTrayIcon != nullptr ) { layoutTrayIcon->layoutMapChanged(); } } void KeyboardDaemon::switchToNextLayout() { qCDebug(KCM_KEYBOARD) << "Toggling layout"; X11Helper::switchToNextLayout(); LayoutUnit newLayout = X11Helper::getCurrentLayout(); QDBusMessage msg = QDBusMessage::createMethodCall( QStringLiteral("org.kde.plasmashell"), QStringLiteral("/org/kde/osdService"), QStringLiteral("org.kde.osdService"), QStringLiteral("kbdLayoutChanged")); msg << Flags::getShortText(newLayout, keyboardConfig); QDBusConnection::sessionBus().asyncCall(msg); } bool KeyboardDaemon::setLayout(QAction* action) { if( action == actionCollection->getToggleAction() ) return false; LayoutUnit layoutUnit(action->data().toString()); return LayoutsMenu::switchToLayout(layoutUnit, keyboardConfig); // need this to be able to switch to spare layouts // return X11Helper::setLayout(LayoutUnit(action->data().toString())); } bool KeyboardDaemon::setLayout(const QString& layout) { return X11Helper::setLayout(LayoutUnit(layout)); } QString KeyboardDaemon::getCurrentLayout() { return X11Helper::getCurrentLayout().toString(); } QStringList KeyboardDaemon::getLayoutsList() { return X11Helper::getLayoutsListAsString( X11Helper::getLayoutsList() ); } QString KeyboardDaemon::getLayoutDisplayName(const QString &layout) { return Flags::getShortText(LayoutUnit(layout), keyboardConfig); } #include "keyboard_daemon.moc" diff --git a/kcms/keyboard/keyboard_hardware.cpp b/kcms/keyboard/keyboard_hardware.cpp index dc8d9b35b..f04508aa5 100644 --- a/kcms/keyboard/keyboard_hardware.cpp +++ b/kcms/keyboard/keyboard_hardware.cpp @@ -1,103 +1,103 @@ /* * 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 #include #include #include #include #include #include "x11_helper.h" #include "kcmmisc.h" #include "debug.h" #include #include #include // This code is taken from xset utility from XFree 4.3 (http://www.xfree86.org/) static void set_repeatrate(int delay, double rate) { - if( !X11Helper::xkbSupported(NULL) ) { + if( !X11Helper::xkbSupported(nullptr) ) { qCCritical(KCM_KEYBOARD) << "Failed to set keyboard repeat rate: xkb is not supported"; return; } XkbDescPtr xkb = XkbAllocKeyboard(); if (xkb) { Display* dpy = QX11Info::display(); //int res = XkbGetControls(dpy, XkbRepeatKeysMask, xkb); xkb->ctrls->repeat_delay = delay; xkb->ctrls->repeat_interval = (int)floor(1000/rate + 0.5); //res = XkbSetControls(dpy, XkbRepeatKeysMask, xkb); XkbFreeKeyboard(xkb, 0, true); return; } } static int set_repeat_mode(TriState keyboardRepeatMode) { XKeyboardState kbd; XKeyboardControl kbdc; XGetKeyboardControl(QX11Info::display(), &kbd); int flags = 0; if( keyboardRepeatMode != STATE_UNCHANGED ) { flags |= KBAutoRepeatMode; kbdc.auto_repeat_mode = (keyboardRepeatMode==STATE_ON ? AutoRepeatModeOn : AutoRepeatModeOff); } return XChangeKeyboardControl(QX11Info::display(), flags, &kbdc); } void init_keyboard_hardware() { KConfigGroup config(KSharedConfig::openConfig( QStringLiteral("kcminputrc") ), "Keyboard"); QString keyRepeatStr = config.readEntry("KeyboardRepeating", TriStateHelper::getString(STATE_ON)); TriState keyRepeat = STATE_UNCHANGED; if( keyRepeatStr == QLatin1String("true") || keyRepeatStr == TriStateHelper::getString(STATE_ON) ) { keyRepeat = STATE_ON; } else if( keyRepeatStr == QLatin1String("false") || keyRepeatStr == TriStateHelper::getString(STATE_OFF) ) { keyRepeat = STATE_OFF; } if( keyRepeat == STATE_ON ) { int delay_ = config.readEntry("RepeatDelay", DEFAULT_REPEAT_DELAY); double rate_ = config.readEntry("RepeatRate", DEFAULT_REPEAT_RATE); set_repeatrate(delay_, rate_); } set_repeat_mode(keyRepeat); TriState numlockState = TriStateHelper::getTriState( config.readEntry( "NumLock", TriStateHelper::getInt(STATE_UNCHANGED) ) ); if( numlockState != STATE_UNCHANGED ) { KModifierKeyInfo keyInfo; keyInfo.setKeyLocked(Qt::Key_NumLock, numlockState == STATE_ON); } } diff --git a/kcms/keyboard/layouts_menu.cpp b/kcms/keyboard/layouts_menu.cpp index 69104b3c5..733826bec 100644 --- a/kcms/keyboard/layouts_menu.cpp +++ b/kcms/keyboard/layouts_menu.cpp @@ -1,140 +1,140 @@ /* * 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 "layouts_menu.h" #include "debug.h" #include #include #include #include "keyboard_config.h" #include "x11_helper.h" #include "xkb_helper.h" #include "flags.h" LayoutsMenu::LayoutsMenu(const KeyboardConfig& keyboardConfig_, const Rules& rules_, Flags& flags_): keyboardConfig(keyboardConfig_), rules(rules_), flags(flags_), - actionGroup(NULL) + actionGroup(nullptr) { } LayoutsMenu::~LayoutsMenu() { delete actionGroup; } const QIcon LayoutsMenu::getFlag(const QString& layout) const { return keyboardConfig.isFlagShown() ? flags.getIcon(layout) : QIcon(); } void LayoutsMenu::actionTriggered(QAction* action) { QString data = action->data().toString(); if( data == QLatin1String("config") ) { QStringList args; args << QStringLiteral("--args=--tab=layouts"); args << QStringLiteral("kcm_keyboard"); KToolInvocation::kdeinitExec(QStringLiteral("kcmshell5"), args); } else { LayoutUnit layoutUnit(LayoutUnit(action->data().toString())); switchToLayout(layoutUnit, keyboardConfig); } } int LayoutsMenu::switchToLayout(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig) { QList layouts = X11Helper::getCurrentLayouts().layouts; bool res; if( layouts.contains(layoutUnit) ) { res = X11Helper::setLayout(layoutUnit); } else if ( keyboardConfig.layouts.contains(layoutUnit) ) { QList layouts(keyboardConfig.getDefaultLayouts()); layouts.removeLast(); layouts.append(layoutUnit); XkbHelper::initializeKeyboardLayouts(layouts); res = X11Helper::setLayout(layoutUnit); } else { qCWarning(KCM_KEYBOARD) << "switchToLayout with unknown layout" << layoutUnit.toString(); res = -1; } return res; } QAction* LayoutsMenu::createAction(const LayoutUnit& layoutUnit) const { QString menuText = Flags::getFullText(layoutUnit, keyboardConfig, &rules); QAction* action = new QAction(getFlag(layoutUnit.layout), menuText, actionGroup); action->setData(layoutUnit.toString()); //FIXME: tooltips don't work on dbusmenus??? // if( ! layoutUnit.getShortcut().isEmpty() ) { // action->setToolTip(layoutUnit.getShortcut().toString()); // } return action; } QList LayoutsMenu::contextualActions() { if( actionGroup ) { disconnect(actionGroup, &QActionGroup::triggered, this, &LayoutsMenu::actionTriggered); delete actionGroup; } actionGroup = new QActionGroup(this); X11Helper::getLayoutsList(); //UGLY: seems to be more reliable with extra call QList currentLayouts = X11Helper::getLayoutsList(); foreach(const LayoutUnit& layoutUnit, currentLayouts) { QAction* action = createAction(layoutUnit); actionGroup->addAction(action); } if( keyboardConfig.configureLayouts ) { QList extraLayouts = keyboardConfig.layouts; foreach(const LayoutUnit& layoutUnit, currentLayouts) { extraLayouts.removeOne(layoutUnit); } if( extraLayouts.size() > 0 ) { QAction* separator = new QAction(actionGroup); separator->setSeparator(true); actionGroup->addAction(separator); foreach(const LayoutUnit& layoutUnit, extraLayouts) { QAction* action = createAction(layoutUnit); actionGroup->addAction(action); } } } QAction* separator = new QAction(actionGroup); separator->setSeparator(true); actionGroup->addAction(separator); QAction* configAction = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure Layouts..."), actionGroup); actionGroup->addAction(configAction); configAction->setData("config"); connect(actionGroup, &QActionGroup::triggered, this, &LayoutsMenu::actionTriggered); return actionGroup->actions(); } diff --git a/kcms/keyboard/tests/flags_test.cpp b/kcms/keyboard/tests/flags_test.cpp index 9a79a05cd..3dae69394 100644 --- a/kcms/keyboard/tests/flags_test.cpp +++ b/kcms/keyboard/tests/flags_test.cpp @@ -1,101 +1,101 @@ /* * Copyright (C) 2011 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 #include #include "../flags.h" #include "../xkb_rules.h" #include "../keyboard_config.h" static QImage image(const QIcon& icon) { return icon.pixmap(QSize(16,16), QIcon::Normal, QIcon::On).toImage(); } class FlagsTest : public QObject { Q_OBJECT Flags* flags; const Rules* rules; private Q_SLOTS: void initTestCase() { flags = new Flags(); - rules = NULL; + rules = nullptr; } void cleanupTestCase() { delete flags; delete rules; } void testRules() { - QVERIFY( flags != NULL ); + QVERIFY( flags != nullptr ); QVERIFY( ! flags->getTransparentPixmap().isNull() ); const QIcon iconUs(flags->getIcon(QStringLiteral("us"))); QVERIFY( ! iconUs.isNull() ); QVERIFY( flags->getIcon("--").isNull() ); KeyboardConfig keyboardConfig; LayoutUnit layoutUnit(QStringLiteral("us")); LayoutUnit layoutUnit1(QStringLiteral("us"), QStringLiteral("intl")); layoutUnit1.setDisplayName(QStringLiteral("usi")); LayoutUnit layoutUnit2(QStringLiteral("us"), QStringLiteral("other")); keyboardConfig.indicatorType = KeyboardConfig::SHOW_FLAG; const QIcon iconUsFlag = flags->getIconWithText(layoutUnit, keyboardConfig); QVERIFY( ! iconUsFlag.isNull() ); QCOMPARE( image(iconUsFlag), image(iconUs) ); keyboardConfig.indicatorType = KeyboardConfig::SHOW_LABEL; const QIcon iconUsText = flags->getIconWithText(layoutUnit, keyboardConfig); QVERIFY( ! iconUsText.isNull() ); QVERIFY( image(iconUsText) != image(iconUs) ); keyboardConfig.layouts.append(layoutUnit1); QCOMPARE( flags->getShortText(layoutUnit, keyboardConfig), QString("us") ); QCOMPARE( flags->getShortText(layoutUnit1, keyboardConfig), QString("usi") ); QCOMPARE( flags->getShortText(layoutUnit2, keyboardConfig), QString("us") ); const Rules* rules = Rules::readRules(Rules::NO_EXTRAS); QCOMPARE( flags->getLongText(layoutUnit, rules), QString("English (US)") ); QCOMPARE( flags->getLongText(layoutUnit2, rules), QString("other") ); - rules = NULL; // when no rules found + rules = nullptr; // when no rules found QCOMPARE( flags->getLongText(layoutUnit1, rules), QString("us - intl") ); flags->clearCache(); } // void loadRulesBenchmark() { // QBENCHMARK { // Flags* flags = new Flags(); // delete flags; // } // } }; // need GUI for xkb protocol in xkb_rules.cpp QTEST_MAIN(FlagsTest) #include "flags_test.moc" diff --git a/kcms/keyboard/tests/iso_codes_test.cpp b/kcms/keyboard/tests/iso_codes_test.cpp index 5dc777d0c..7d633a638 100644 --- a/kcms/keyboard/tests/iso_codes_test.cpp +++ b/kcms/keyboard/tests/iso_codes_test.cpp @@ -1,74 +1,74 @@ /* * Copyright (C) 2011 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 #include "../iso_codes.h" class IsoCodesTest : public QObject { Q_OBJECT IsoCodes* isoCodes; private Q_SLOTS: void initTestCase() { // isoCodes = new IsoCodes(IsoCodes::iso_639); isoCodes = new IsoCodes(IsoCodes::iso_639_3); } void cleanupTestCase() { delete isoCodes; } void testIsoCodes() { - QVERIFY( isoCodes != NULL ); + QVERIFY( isoCodes != nullptr ); QVERIFY( ! isoCodes->getEntryList().isEmpty() ); // const IsoCodeEntry* isoEntry = isoCodes->getEntry(IsoCodes::attr_iso_639_2T_code, "eng"); const IsoCodeEntry* isoEntry = isoCodes->getEntry(IsoCodes::attr_iso_639_3_id, QStringLiteral("eng")); - QVERIFY( isoEntry != NULL ); + QVERIFY( isoEntry != nullptr ); QVERIFY( ! isoEntry->empty() ); // QCOMPARE( isoEntry->value(IsoCodes::attr_iso_639_2T_code), QString("eng") ); // QCOMPARE( isoEntry->value(IsoCodes::attr_iso_639_2B_code), QString("eng") ); // QCOMPARE( isoEntry->value(IsoCodes::attr_iso_639_1_code), QString("en") ); QCOMPARE( isoEntry->value("name"), QString("English") ); // QCOMPARE( isoEntry->value("status"), QString("Active") ); } void testIso639_3_Codes() { - QVERIFY( isoCodes != NULL ); + QVERIFY( isoCodes != nullptr ); QVERIFY( ! isoCodes->getEntryList().isEmpty() ); const IsoCodeEntry* isoEntry = isoCodes->getEntry(IsoCodes::attr_iso_639_3_id, QStringLiteral("ant")); - QVERIFY( isoEntry != NULL ); + QVERIFY( isoEntry != nullptr ); QVERIFY( ! isoEntry->empty() ); QVERIFY( isoEntry->value("name") != QString("ant") ); QCOMPARE( isoEntry->value("name"), QString("Antakarinya") ); } void loadIsoCodesBenchmark() { QBENCHMARK { IsoCodes* isoCodes = new IsoCodes(IsoCodes::iso_639_3); delete isoCodes; } } }; QTEST_MAIN(IsoCodesTest) #include "iso_codes_test.moc" diff --git a/kcms/keyboard/tests/keyboard_daemon_test.cpp b/kcms/keyboard/tests/keyboard_daemon_test.cpp index 6e0d1fb42..fbd083f14 100644 --- a/kcms/keyboard/tests/keyboard_daemon_test.cpp +++ b/kcms/keyboard/tests/keyboard_daemon_test.cpp @@ -1,100 +1,100 @@ /* * Copyright (C) 2011 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 #include #include #include "../flags.h" #include "../xkb_rules.h" #include "../keyboard_config.h" #include "../keyboard_daemon.h" class KeyboardDaemonTest : public QObject { Q_OBJECT KeyboardDaemon* keyboardDaemon; // KApplication* kapplication; private Q_SLOTS: void initTestCase() { // kapplication = new KApplication(); // const KAboutData* kAboutData = new KAboutData(i18n("a").toLatin1(), i18n("a").toLatin1(), KLocalizedString(), i18n("a").toLatin1()); // KCmdLineArgs::init(kAboutData); keyboardDaemon = new KeyboardDaemon(this, QList()); } void cleanupTestCase() { delete keyboardDaemon; // delete kapplication; } void testDaemon() { - QVERIFY( keyboardDaemon != NULL ); + QVERIFY( keyboardDaemon != nullptr ); // QVERIFY( ! flags->getTransparentPixmap().isNull() ); // // const QIcon iconUs(flags->getIcon("us")); // QVERIFY( ! iconUs.isNull() ); // QVERIFY( flags->getIcon("--").isNull() ); // // KeyboardConfig keyboardConfig; // LayoutUnit layoutUnit("us"); // LayoutUnit layoutUnit1("us", "intl"); // layoutUnit1.setDisplayName("usi"); // LayoutUnit layoutUnit2("us", "other"); // // keyboardConfig.showFlag = true; // const QIcon iconUsFlag = flags->getIconWithText(layoutUnit, keyboardConfig); // QVERIFY( ! iconUsFlag.isNull() ); // QCOMPARE( image(iconUsFlag), image(iconUs) ); // // keyboardConfig.showFlag = false; // const QIcon iconUsText = flags->getIconWithText(layoutUnit, keyboardConfig); // QVERIFY( ! iconUsText.isNull() ); // QVERIFY( image(iconUsText) != image(iconUs) ); // // keyboardConfig.layouts.append(layoutUnit1); // QCOMPARE( flags->getShortText(layoutUnit, keyboardConfig), QString("us") ); // QCOMPARE( flags->getShortText(layoutUnit1, keyboardConfig), QString("usi") ); // QCOMPARE( flags->getShortText(layoutUnit2, keyboardConfig), QString("us") ); // // const Rules* rules = Rules::readRules(); // QCOMPARE( flags->getLongText(layoutUnit, rules), QString("USA") ); // QVERIFY( flags->getLongText(layoutUnit1, rules).startsWith("USA - International") ); // QCOMPARE( flags->getLongText(layoutUnit2, rules), QString("USA - other") ); // // flags->clearCache(); } // void loadRulesBenchmark() { // QBENCHMARK { // Flags* flags = new Flags(); // delete flags; // } // } }; // need GUI for xkb protocol in xkb_rules.cpp QTEST_MAIN(KeyboardDaemonTest) #include "keyboard_daemon_test.moc" diff --git a/kcms/keyboard/tests/xkb_rules_test.cpp b/kcms/keyboard/tests/xkb_rules_test.cpp index c9d11969d..4eb24d748 100644 --- a/kcms/keyboard/tests/xkb_rules_test.cpp +++ b/kcms/keyboard/tests/xkb_rules_test.cpp @@ -1,237 +1,237 @@ /* * Copyright (C) 2011 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 #include "../xkb_rules.h" #include #include static const Rules::ExtrasFlag readExtras = Rules::NO_EXTRAS; class RulesTest : public QObject { Q_OBJECT Rules* rules; private Q_SLOTS: void initTestCase() { rules = Rules::readRules(readExtras); } void cleanupTestCase() { delete rules; } void testRules() { - QVERIFY( rules != NULL ); + QVERIFY( rules != nullptr ); QVERIFY( rules->modelInfos.size() > 0 ); QVERIFY( rules->layoutInfos.size() > 0 ); QVERIFY( rules->optionGroupInfos.size() > 0 ); } void testModel() { foreach(const ModelInfo* modelInfo, rules->modelInfos) { - QVERIFY( modelInfo != NULL); + QVERIFY( modelInfo != nullptr); QVERIFY( modelInfo->name.length() > 0 ); QVERIFY( modelInfo->description.length() > 0 ); // QVERIFY( ! modelInfo->vendor.isEmpty() ); } } void testLayouts() { foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { - QVERIFY( layoutInfo != NULL); + QVERIFY( layoutInfo != nullptr); QVERIFY( ! layoutInfo->name.isEmpty() ); // const char* desc = layoutInfo->name.toUtf8() ; // qDebug() << layoutInfo->name; QVERIFY( ! layoutInfo->description.isEmpty() ); foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { - QVERIFY( variantInfo != NULL ); + QVERIFY( variantInfo != nullptr ); QVERIFY( ! variantInfo->name.isEmpty() ); QVERIFY( ! variantInfo->description.isEmpty() ); } foreach(const QString& language, layoutInfo->languages) { QVERIFY( ! language.isEmpty() ); } } } void testOptionGroups() { foreach(const OptionGroupInfo* optionGroupInfo, rules->optionGroupInfos) { - QVERIFY( optionGroupInfo != NULL); + QVERIFY( optionGroupInfo != nullptr); QVERIFY( ! optionGroupInfo->name.isEmpty() ); QVERIFY( ! optionGroupInfo->description.isEmpty() ); // optionGroupInfo->exclusive foreach(const OptionInfo* optionInfo, optionGroupInfo->optionInfos) { - QVERIFY( optionInfo != NULL ); + QVERIFY( optionInfo != nullptr ); QVERIFY( ! optionInfo->name.isEmpty() ); QVERIFY( ! optionInfo->description.isEmpty() ); } } } void testExtras() { Rules* rulesWithExtras = Rules::readRules(Rules::READ_EXTRAS); QVERIFY2(rulesWithExtras->layoutInfos.size() > rules->layoutInfos.size(), "Rules with extras should have more layouts"); foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { QVERIFY( ! layoutInfo->fromExtras ); } bool foundFromExtras = false, foundNonExtras = false; foreach(const LayoutInfo* layoutInfo, rulesWithExtras->layoutInfos) { if( layoutInfo->fromExtras ) foundFromExtras = true; if( ! layoutInfo->fromExtras ) foundNonExtras = true; layoutInfo->languages.size(); // make sure we can access all merged objects layoutInfo->variantInfos.size(); // make sure we can access all merged objects } QVERIFY( foundNonExtras ); QVERIFY( foundFromExtras ); } void testWriteNewXml() { QDomDocument doc(QStringLiteral("xkbConfigRegistry")); QDomElement root = doc.createElement(QStringLiteral("xkbConfigRegistry")); root.setAttribute(QStringLiteral("version"), QStringLiteral("2.0")); doc.appendChild(root); QDomElement modelList = doc.createElement(QStringLiteral("modelList")); root.appendChild(modelList); foreach(const ModelInfo* modelInfo, rules->modelInfos) { QDomElement model = doc.createElement(QStringLiteral("model")); model.setAttribute(QStringLiteral("name"), modelInfo->name); model.setAttribute(QStringLiteral("description"), modelInfo->description); model.setAttribute(QStringLiteral("vendor"), modelInfo->vendor); modelList.appendChild(model); } QDomElement layoutList = doc.createElement(QStringLiteral("layoutList")); foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { QDomElement layout = doc.createElement(QStringLiteral("layout")); layout.setAttribute(QStringLiteral("name"), layoutInfo->name); layout.setAttribute(QStringLiteral("description"), layoutInfo->description); QDomElement langList = doc.createElement(QStringLiteral("languageList")); foreach(const QString& lang, layoutInfo->languages) { QDomElement langNode = doc.createElement(QStringLiteral("lang")); langNode.setAttribute(QStringLiteral("iso639Id"), lang); langList.appendChild(langNode); } if( langList.hasChildNodes() ) { layout.appendChild(langList); } QDomElement variantList = doc.createElement(QStringLiteral("variantList")); foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { QDomElement variant = doc.createElement(QStringLiteral("variant")); variant.setAttribute(QStringLiteral("name"), variantInfo->name); variant.setAttribute(QStringLiteral("description"), variantInfo->description); QDomElement langList = doc.createElement(QStringLiteral("languageList")); foreach(const QString& lang, variantInfo->languages) { QDomElement langNode = doc.createElement(QStringLiteral("lang")); langNode.setAttribute(QStringLiteral("iso639Id"), lang); langList.appendChild(langNode); } if( langList.hasChildNodes() ) { variant.appendChild(langList); } variantList.appendChild(variant); } if( variantList.hasChildNodes() ) { layout.appendChild(variantList); } layoutList.appendChild(layout); } root.appendChild(layoutList); QDomElement optionGroupList = doc.createElement(QStringLiteral("optionList")); foreach(const OptionGroupInfo* optionGroupInfo, rules->optionGroupInfos) { QDomElement optionGroup = doc.createElement(QStringLiteral("optionGroup")); optionGroup.setAttribute(QStringLiteral("name"), optionGroupInfo->name); optionGroup.setAttribute(QStringLiteral("description"), optionGroupInfo->description); optionGroup.setAttribute(QStringLiteral("exclusive"), optionGroupInfo->exclusive); foreach(const OptionInfo* optionGroupInfo, optionGroupInfo->optionInfos) { QDomElement option = doc.createElement(QStringLiteral("option")); option.setAttribute(QStringLiteral("name"), optionGroupInfo->name); option.setAttribute(QStringLiteral("description"), optionGroupInfo->description); optionGroup.appendChild(option); } optionGroupList.appendChild(optionGroup); } root.appendChild(optionGroupList); QFile file(QStringLiteral("base2.xml")); if( ! file.open( QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) ) { qWarning() << "Failed to open layout memory xml file for writing" << file.fileName(); QFAIL("failed"); } QTextStream out(&file); out << doc.toString(); } void testRulesVersion() { QVERIFY(!rules->version.isEmpty()); Rules* rules10 = new Rules(); Rules::readRules(rules10, QStringLiteral("config/base.xml"), false); QCOMPARE(rules10->version, QString("1.0")); delete rules10; Rules* rules11 = new Rules(); Rules::readRules(rules11, QStringLiteral("config/base.1.1.xml"), false); QCOMPARE(rules11->version, QString("1.1")); foreach(const LayoutInfo* layoutInfo, rules11->layoutInfos) { - QVERIFY( layoutInfo != NULL); + QVERIFY( layoutInfo != nullptr); QVERIFY( ! layoutInfo->name.isEmpty() ); QVERIFY( ! layoutInfo->description.isEmpty() ); foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { - QVERIFY( variantInfo != NULL ); + QVERIFY( variantInfo != nullptr ); QVERIFY( ! variantInfo->name.isEmpty() ); QVERIFY( ! variantInfo->description.isEmpty() ); } } delete rules11; } void loadRulesBenchmark() { QBENCHMARK { Rules* rules = Rules::readRules(readExtras); delete rules; } } }; // need kde libs for config-workspace.h used in xkb_rules.cpp QTEST_MAIN(RulesTest) #include "xkb_rules_test.moc" diff --git a/kcms/keyboard/x11_helper.cpp b/kcms/keyboard/x11_helper.cpp index 5eb8b4064..a8a96e9f8 100644 --- a/kcms/keyboard/x11_helper.cpp +++ b/kcms/keyboard/x11_helper.cpp @@ -1,452 +1,452 @@ /* * 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 "x11_helper.h" #include "debug.h" #define explicit explicit_is_keyword_in_cpp #include #undef explicit #include #include #include #include #include #include #include #include #include #include // more information about the limit https://bugs.freedesktop.org/show_bug.cgi?id=19501 const int X11Helper::MAX_GROUP_COUNT = 4; const int X11Helper::ARTIFICIAL_GROUP_LIMIT_COUNT = 8; const char X11Helper::LEFT_VARIANT_STR[] = "("; const char X11Helper::RIGHT_VARIANT_STR[] = ")"; bool X11Helper::xkbSupported(int* xkbOpcode) { if (!QX11Info::isPlatformX11()) { return false; } // Verify the Xlib has matching XKB extension. int major = XkbMajorVersion; int minor = XkbMinorVersion; if (!XkbLibraryVersion(&major, &minor)) { qCWarning(KCM_KEYBOARD) << "Xlib XKB extension " << major << '.' << minor << " != " << XkbMajorVersion << '.' << XkbMinorVersion; return false; } // Verify the X server has matching XKB extension. int opcode_rtrn; int error_rtrn; int xkb_opcode; if( ! XkbQueryExtension(QX11Info::display(), &opcode_rtrn, &xkb_opcode, &error_rtrn, &major, &minor)) { qCWarning(KCM_KEYBOARD) << "X server XKB extension " << major << '.' << minor << " != " << XkbMajorVersion << '.' << XkbMinorVersion; return false; } - if( xkbOpcode != NULL ) { + if( xkbOpcode != nullptr ) { *xkbOpcode = xkb_opcode; } return true; } void X11Helper::switchToNextLayout() { int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count int group = (X11Helper::getGroup() + 1) % size; X11Helper::setGroup(group); } void X11Helper::scrollLayouts(int delta) { int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count int group = X11Helper::getGroup() + delta; group = group < 0 ? size - ((-group) % size) : group % size; X11Helper::setGroup(group); } QStringList X11Helper::getLayoutsListAsString(const QList& layoutsList) { QStringList stringList; foreach(const LayoutUnit& layoutUnit, layoutsList) { stringList << layoutUnit.toString(); } return stringList; } bool X11Helper::setLayout(const LayoutUnit& layout) { QList currentLayouts = getLayoutsList(); int idx = currentLayouts.indexOf(layout); if( idx == -1 || idx >= X11Helper::MAX_GROUP_COUNT ) { qCWarning(KCM_KEYBOARD) << "Layout" << layout.toString() << "is not found in current layout list" << getLayoutsListAsString(currentLayouts); return false; } return X11Helper::setGroup((unsigned int)idx); } bool X11Helper::setDefaultLayout() { return X11Helper::setGroup(0); } bool X11Helper::isDefaultLayout() { return X11Helper::getGroup() == 0; } LayoutUnit X11Helper::getCurrentLayout() { if (!QX11Info::isPlatformX11()) { return LayoutUnit(); } QList currentLayouts = getLayoutsList(); unsigned int group = X11Helper::getGroup(); if( group < (unsigned int)currentLayouts.size() ) return currentLayouts[group]; qCWarning(KCM_KEYBOARD) << "Current group number" << group << "is outside of current layout list" << getLayoutsListAsString(currentLayouts); return LayoutUnit(); } LayoutSet X11Helper::getCurrentLayouts() { LayoutSet layoutSet; QList currentLayouts = getLayoutsList(); layoutSet.layouts = currentLayouts; unsigned int group = X11Helper::getGroup(); if( group < (unsigned int)currentLayouts.size() ) { layoutSet.currentLayout = currentLayouts[group]; } else { qCWarning(KCM_KEYBOARD) << "Current group number" << group << "is outside of current layout list" << getLayoutsListAsString(currentLayouts); layoutSet.currentLayout = LayoutUnit(); } return layoutSet; } //static QString addNum(const QString& str, int n) //{ // QString format("%1%2"); // if( str.length() >= 3 ) return format.arg(str.left(2)).arg(n); // return format.arg(str).arg(n); //} QList X11Helper::getLayoutsList() { if (!QX11Info::isPlatformX11()) { return QList(); } XkbConfig xkbConfig; QList layouts; if( X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::LAYOUTS_ONLY) ) { for(int i=0; ierror_code; return false; } return true; } unsigned int X11Helper::getGroup() { XkbStateRec xkbState; XkbGetState( QX11Info::display(), XkbUseCoreKbd, &xkbState ); return xkbState.group; } bool X11Helper::getGroupNames(Display* display, XkbConfig* xkbConfig, FetchType fetchType) { static const char OPTIONS_SEPARATOR[] = ","; Atom real_prop_type; int fmt; unsigned long nitems, extra_bytes; - char *prop_data = NULL; + char *prop_data = nullptr; Status ret; Atom rules_atom = XInternAtom(display, _XKB_RF_NAMES_PROP_ATOM, False); /* no such atom! */ if (rules_atom == None) { /* property cannot exist */ qCWarning(KCM_KEYBOARD) << "Failed to fetch layouts from server:" << "could not find the atom" << _XKB_RF_NAMES_PROP_ATOM; return false; } ret = XGetWindowProperty(display, DefaultRootWindow(display), rules_atom, 0L, _XKB_RF_NAMES_PROP_MAXLEN, False, XA_STRING, &real_prop_type, &fmt, &nitems, &extra_bytes, (unsigned char **) (void *) &prop_data); /* property not found! */ if (ret != Success) { qCWarning(KCM_KEYBOARD) << "Failed to fetch layouts from server:" << "Could not get the property"; return false; } /* has to be array of strings */ if ((extra_bytes > 0) || (real_prop_type != XA_STRING) || (fmt != 8)) { if (prop_data) XFree(prop_data); qCWarning(KCM_KEYBOARD) << "Failed to fetch layouts from server:" << "Wrong property format"; return false; } // qCDebug(KCM_KEYBOARD) << "prop_data:" << nitems << prop_data; QStringList names; - for(char* p=prop_data; p-prop_data < (long)nitems && p != NULL; p += strlen(p)+1) { + for(char* p=prop_data; p-prop_data < (long)nitems && p != nullptr; p += strlen(p)+1) { names.append( p ); // qDebug() << " " << p; } if( names.count() < 4 ) { //{ rules, model, layouts, variants, options } XFree(prop_data); return false; } if( fetchType == ALL || fetchType == LAYOUTS_ONLY ) { QStringList layouts = names[2].split(OPTIONS_SEPARATOR); QStringList variants = names[3].split(OPTIONS_SEPARATOR); for(int ii=0; iilayouts << (layouts[ii] != NULL ? layouts[ii] : QLatin1String("")); - xkbConfig->variants << (ii < variants.count() && variants[ii] != NULL ? variants[ii] : QLatin1String("")); + xkbConfig->layouts << (layouts[ii] != nullptr ? layouts[ii] : QLatin1String("")); + xkbConfig->variants << (ii < variants.count() && variants[ii] != nullptr ? variants[ii] : QLatin1String("")); } qCDebug(KCM_KEYBOARD) << "Fetched layout groups from X server:" << "\tlayouts:" << xkbConfig->layouts << "\tvariants:" << xkbConfig->variants; } if( fetchType == ALL || fetchType == MODEL_ONLY ) { - xkbConfig->keyboardModel = (names[1] != NULL ? names[1] : QLatin1String("")); + xkbConfig->keyboardModel = (names[1] != nullptr ? names[1] : QLatin1String("")); qCDebug(KCM_KEYBOARD) << "Fetched keyboard model from X server:" << xkbConfig->keyboardModel; } if( fetchType == ALL ) { if( names.count() >= 5 ) { - QString options = (names[4] != NULL ? names[4] : QLatin1String("")); + QString options = (names[4] != nullptr ? names[4] : QLatin1String("")); xkbConfig->options = options.split(OPTIONS_SEPARATOR); qCDebug(KCM_KEYBOARD) << "Fetched xkbOptions from X server:" << options; } } XFree(prop_data); return true; } XEventNotifier::XEventNotifier(): xkbOpcode(-1) { - if( QCoreApplication::instance() == NULL ) { + if( QCoreApplication::instance() == nullptr ) { qCWarning(KCM_KEYBOARD) << "Layout Widget won't work properly without QCoreApplication instance"; } } void XEventNotifier::start() { qCDebug(KCM_KEYBOARD) << "qCoreApp" << QCoreApplication::instance(); - if( QCoreApplication::instance() != NULL && X11Helper::xkbSupported(&xkbOpcode) ) { + if( QCoreApplication::instance() != nullptr && X11Helper::xkbSupported(&xkbOpcode) ) { registerForXkbEvents(QX11Info::display()); // start the event loop QCoreApplication::instance()->installNativeEventFilter(this); } } void XEventNotifier::stop() { - if( QCoreApplication::instance() != NULL ) { + if( QCoreApplication::instance() != nullptr ) { //TODO: unregister // XEventNotifier::unregisterForXkbEvents(QX11Info::display()); // stop the event loop QCoreApplication::instance()->removeNativeEventFilter(this); } } bool XEventNotifier::isXkbEvent(xcb_generic_event_t* event) { // qDebug() << "event response type:" << (event->response_type & ~0x80) << xkbOpcode << ((event->response_type & ~0x80) == xkbOpcode + XkbEventCode); return (event->response_type & ~0x80) == xkbOpcode + XkbEventCode; } bool XEventNotifier::processOtherEvents(xcb_generic_event_t* /*event*/) { return true; } bool XEventNotifier::processXkbEvents(xcb_generic_event_t* event) { _xkb_event *xkbevt = reinterpret_cast<_xkb_event *>(event); if( XEventNotifier::isGroupSwitchEvent(xkbevt) ) { // qDebug() << "group switch event"; emit(layoutChanged()); } else if( XEventNotifier::isLayoutSwitchEvent(xkbevt) ) { // qDebug() << "layout switch event"; emit(layoutMapChanged()); } return true; } bool XEventNotifier::nativeEventFilter(const QByteArray &eventType, void *message, long *) { // qDebug() << "event type:" << eventType; if (eventType == "xcb_generic_event_t") { xcb_generic_event_t* ev = static_cast(message); if( isXkbEvent(ev) ) { processXkbEvents(ev); } else { processOtherEvents(ev); } } return false; } //bool XEventNotifier::x11Event(XEvent * event) //{ // // qApp->x11ProcessEvent ( event ); // if( isXkbEvent(event) ) { // processXkbEvents(event); // } // else { // processOtherEvents(event); // } // return QWidget::x11Event(event); //} bool XEventNotifier::isGroupSwitchEvent(_xkb_event* xkbEvent) { // XkbEvent *xkbEvent = (XkbEvent*) event; #define GROUP_CHANGE_MASK \ ( XkbGroupStateMask | XkbGroupBaseMask | XkbGroupLatchMask | XkbGroupLockMask ) return xkbEvent->any.xkbType == XkbStateNotify && (xkbEvent->state_notify.changed & GROUP_CHANGE_MASK); } bool XEventNotifier::isLayoutSwitchEvent(_xkb_event* xkbEvent) { // XkbEvent *xkbEvent = (XkbEvent*) event; return //( (xkbEvent->any.xkb_type == XkbMapNotify) && (xkbEvent->map.changed & XkbKeySymsMask) ) || /* || ( (xkbEvent->any.xkb_type == XkbNamesNotify) && (xkbEvent->names.changed & XkbGroupNamesMask) || )*/ (xkbEvent->any.xkbType == XkbNewKeyboardNotify); } int XEventNotifier::registerForXkbEvents(Display* display) { int eventMask = XkbNewKeyboardNotifyMask | XkbStateNotifyMask; if( ! XkbSelectEvents(display, XkbUseCoreKbd, eventMask, eventMask) ) { qCWarning(KCM_KEYBOARD) << "Couldn't select desired XKB events"; return false; } return true; } static const char LAYOUT_VARIANT_SEPARATOR_PREFIX[] = "("; static const char LAYOUT_VARIANT_SEPARATOR_SUFFIX[] = ")"; static QString& stripVariantName(QString& variant) { if( variant.endsWith(LAYOUT_VARIANT_SEPARATOR_SUFFIX) ) { int suffixLen = strlen(LAYOUT_VARIANT_SEPARATOR_SUFFIX); return variant.remove(variant.length()-suffixLen, suffixLen); } return variant; } LayoutUnit::LayoutUnit(const QString& fullLayoutName) { QStringList lv = fullLayoutName.split(LAYOUT_VARIANT_SEPARATOR_PREFIX); layout = lv[0]; variant = lv.size() > 1 ? stripVariantName(lv[1]) : QLatin1String(""); } QString LayoutUnit::toString() const { if( variant.isEmpty() ) return layout; return layout + LAYOUT_VARIANT_SEPARATOR_PREFIX+variant+LAYOUT_VARIANT_SEPARATOR_SUFFIX; } const int LayoutUnit::MAX_LABEL_LENGTH = 3; diff --git a/kcms/keyboard/xinput_helper.cpp b/kcms/keyboard/xinput_helper.cpp index 6d65300de..9cae43369 100644 --- a/kcms/keyboard/xinput_helper.cpp +++ b/kcms/keyboard/xinput_helper.cpp @@ -1,192 +1,192 @@ /* * 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 "xinput_helper.h" #include "debug.h" #include #include #include #include #include #include #include #ifdef HAVE_XINPUT #include #include typedef struct xcb_input_device_presence_notify_event_t { uint8_t response_type; uint8_t pad0; uint16_t sequence; xcb_timestamp_t time; uint8_t devchange; uint8_t device_id; uint16_t control; uint8_t pad1[20]; } xcb_input_device_presence_notify_event_t; // FIXME: #include once xcb-xinput is stable #endif #include "x11_helper.h" #include "udev_helper.h" #include static const int DEVICE_NONE = 0; static const int DEVICE_KEYBOARD = 1; static const int DEVICE_POINTER = 2; XInputEventNotifier::XInputEventNotifier(QWidget* parent): XEventNotifier(), //TODO: destruct properly? xinputEventType(-1), udevNotifier(nullptr) { Q_UNUSED(parent) } void XInputEventNotifier::start() { - if( QCoreApplication::instance() != NULL ) { + if( QCoreApplication::instance() != nullptr ) { registerForNewDeviceEvent(QX11Info::display()); } XEventNotifier::start(); } void XInputEventNotifier::stop() { XEventNotifier::stop(); - if( QCoreApplication::instance() != NULL ) { + if( QCoreApplication::instance() != nullptr ) { // XEventNotifier::unregisterForNewDeviceEvent(QX11Info::display()); } } bool XInputEventNotifier::processOtherEvents(xcb_generic_event_t* event) { int newDeviceType = getNewDeviceEventType(event); if( newDeviceType == DEVICE_KEYBOARD ) { emit(newKeyboardDevice()); } else if( newDeviceType == DEVICE_POINTER ) { emit(newPointerDevice()); emit(newKeyboardDevice()); // arghhh, looks like X resets xkb map even when only pointer device is connected } return true; } #if defined(HAVE_XINPUT) // This is ugly but allows to skip multiple execution of setxkbmap // for all keyboard devices that don't care about layouts static bool isRealKeyboard(const char* deviceName) { - return strstr(deviceName, "Video Bus") == NULL - && strstr(deviceName, "Sleep Button") == NULL - && strstr(deviceName, "Power Button") == NULL - && strstr(deviceName, "WMI hotkeys") == NULL; + return strstr(deviceName, "Video Bus") == nullptr + && strstr(deviceName, "Sleep Button") == nullptr + && strstr(deviceName, "Power Button") == nullptr + && strstr(deviceName, "WMI hotkeys") == nullptr; } int XInputEventNotifier::getNewDeviceEventType(xcb_generic_event_t* event) { int newDeviceType = DEVICE_NONE; if( xinputEventType != -1 && event->response_type == xinputEventType ) { xcb_input_device_presence_notify_event_t *xdpne = reinterpret_cast(event); if( xdpne->devchange == DeviceEnabled ) { int ndevices; XDeviceInfo *devices = XListInputDevices(display, &ndevices); - if( devices != NULL ) { + if( devices != nullptr ) { qCDebug(KCM_KEYBOARD) << "New device id:" << xdpne->device_id; for(int i=0; idevice_id ) { if( devices[i].use == IsXKeyboard || devices[i].use == IsXExtensionKeyboard ) { if( isRealKeyboard(devices[i].name) ) { newDeviceType = DEVICE_KEYBOARD; qCDebug(KCM_KEYBOARD) << "new keyboard device, id:" << devices[i].id << "name:" << devices[i].name << "used as:" << devices[i].use; break; } } if( devices[i].use == IsXPointer || devices[i].use == IsXExtensionPointer ) { newDeviceType = DEVICE_POINTER; qCDebug(KCM_KEYBOARD) << "new pointer device, id:" << devices[i].id << "name:" << devices[i].name << "used as:" << devices[i].use; break; } } } XFreeDeviceList(devices); } } } return newDeviceType; } int XInputEventNotifier::registerForNewDeviceEvent(Display* display_) { int xitype; XEventClass xiclass; display = display_; DevicePresence(display, xitype, xiclass); XSelectExtensionEvent(display, DefaultRootWindow(display), &xiclass, 1); qCDebug(KCM_KEYBOARD) << "Registered for new device events from XInput, class" << xitype; xinputEventType = xitype; return xitype; } #elif defined(HAVE_UDEV) int XInputEventNotifier::registerForNewDeviceEvent(Display* /*display*/) { if (!udevNotifier) { udevNotifier = new UdevDeviceNotifier(this); connect(udevNotifier, &UdevDeviceNotifier::newKeyboardDevice, this, &XInputEventNotifier::newKeyboardDevice); connect(udevNotifier, &UdevDeviceNotifier::newPointerDevice, this, &XInputEventNotifier::newPointerDevice); // Same as with XInput notifier, also emit newKeyboardDevice when pointer device is found connect(udevNotifier, &UdevDeviceNotifier::newPointerDevice, this, &XInputEventNotifier::newKeyboardDevice); } return -1; } int XInputEventNotifier::getNewDeviceEventType(xcb_generic_event_t* /*event*/) { return DEVICE_NONE; } #else #ifdef __GNUC__ #warning "Keyboard daemon is compiled without XInput and UDev, keyboard settings will be reset when new keyboard device is plugged in!" #endif int XInputEventNotifier::registerForNewDeviceEvent(Display* /*display*/) { qCWarning(KCM_KEYBOARD) << "Keyboard kded daemon is compiled without XInput, xkb configuration will be reset when new keyboard device is plugged in!"; return -1; } int XInputEventNotifier::getNewDeviceEventType(xcb_generic_event_t* /*event*/) { return DEVICE_NONE; } #endif diff --git a/kcms/keyboard/xinput_helper.h b/kcms/keyboard/xinput_helper.h index 214953f39..e29fdc22a 100644 --- a/kcms/keyboard/xinput_helper.h +++ b/kcms/keyboard/xinput_helper.h @@ -1,56 +1,56 @@ /* * 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. */ #ifndef XINPUT_HELPER_H_ #define XINPUT_HELPER_H_ #include "x11_helper.h" #include #include class UdevDeviceNotifier; class XInputEventNotifier: public XEventNotifier { Q_OBJECT public: - XInputEventNotifier(QWidget* parent=NULL); + XInputEventNotifier(QWidget* parent=nullptr); void start() override; void stop() override; int registerForNewDeviceEvent(Display* dpy); Q_SIGNALS: void newKeyboardDevice(); void newPointerDevice(); protected: bool processOtherEvents(xcb_generic_event_t* event) override; private: int getNewDeviceEventType(xcb_generic_event_t* event); int xinputEventType; Display* display; UdevDeviceNotifier *udevNotifier; }; #endif /* XINPUT_HELPER_H_ */ diff --git a/kcms/keyboard/xkb_rules.cpp b/kcms/keyboard/xkb_rules.cpp index 57db105fe..3cc081935 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 = NULL; + char *tmp = nullptr; - if (XkbRF_GetNamesProp(QX11Info::display(), &tmp, &vd) && tmp != NULL ) { + 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 != NULL ) { + 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 NULL; + 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 NULL; + 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 NULL; + 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("/")); 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("/")); if( strPath.endsWith(QLatin1String("layoutList/layout/configItem/name")) ) { - if( rules->layoutInfos.last() != NULL ) { + 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/keyboard/xkb_rules.h b/kcms/keyboard/xkb_rules.h index 336776daa..46595ccb2 100644 --- a/kcms/keyboard/xkb_rules.h +++ b/kcms/keyboard/xkb_rules.h @@ -1,142 +1,142 @@ /* * 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. */ #ifndef XKB_RULES_H_ #define XKB_RULES_H_ #include #include #include #include struct ConfigItem { QString name; QString description; }; template inline T* findByName(QList list, QString name) { foreach(T* info, list) { if( info->name == name ) return info; } - return NULL; + return nullptr; } struct VariantInfo: public ConfigItem { QList languages; const bool fromExtras; VariantInfo(bool fromExtras_): fromExtras(fromExtras_) {} }; struct LayoutInfo: public ConfigItem { QList variantInfos; QList languages; const bool fromExtras; // LayoutInfo() {} LayoutInfo(bool fromExtras_): fromExtras(fromExtras_) {} ~LayoutInfo() { foreach(VariantInfo* variantInfo, variantInfos) delete variantInfo; } VariantInfo* getVariantInfo(const QString& variantName) const { return findByName(variantInfos, variantName); } bool isLanguageSupportedByLayout(const QString& lang) const; bool isLanguageSupportedByDefaultVariant(const QString& lang) const; bool isLanguageSupportedByVariants(const QString& lang) const; bool isLanguageSupportedByVariant(const VariantInfo* variantInfo, const QString& lang) const; }; struct ModelInfo: public ConfigItem { QString vendor; }; struct OptionInfo: public ConfigItem { }; struct OptionGroupInfo: public ConfigItem { QList optionInfos; bool exclusive; ~OptionGroupInfo() { foreach(OptionInfo* opt, optionInfos) delete opt; } const OptionInfo* getOptionInfo(const QString& optionName) const { return findByName(optionInfos, optionName); } }; struct Rules { enum ExtrasFlag { NO_EXTRAS, READ_EXTRAS }; static const char XKB_OPTION_GROUP_SEPARATOR; QList layoutInfos; QList modelInfos; QList optionGroupInfos; QString version; Rules(); ~Rules() { foreach(LayoutInfo* layoutInfo, layoutInfos) delete layoutInfo; foreach(ModelInfo* modelInfo, modelInfos) delete modelInfo; foreach(OptionGroupInfo* optionGroupInfo, optionGroupInfos) delete optionGroupInfo; } const LayoutInfo* getLayoutInfo(const QString& layoutName) const { return findByName(layoutInfos, layoutName); } const OptionGroupInfo* getOptionGroupInfo(const QString& optionGroupName) const { return findByName(optionGroupInfos, optionGroupName); } static Rules* readRules(ExtrasFlag extrasFlag); static Rules* readRules(Rules* rules, const QString& filename, bool fromExtras); static QString getRulesName(); static QString findXkbDir(); #ifdef NEW_GEOMETRY class GeometryId { public: QString fileName; QString geoName; GeometryId(const QString& fileName_, const QString& geoName_): fileName(fileName_), geoName(geoName_) {} GeometryId& operator=(const GeometryId& geoId) { fileName = geoId.fileName; geoName = geoId.geoName; return *this; } }; static GeometryId getGeometryId(const QString& model); #endif }; #endif /* XKB_RULES_H_ */ diff --git a/kcms/keys/export_scheme_dialog.h b/kcms/keys/export_scheme_dialog.h index b8a255557..bb00d73b9 100644 --- a/kcms/keys/export_scheme_dialog.h +++ b/kcms/keys/export_scheme_dialog.h @@ -1,59 +1,59 @@ #ifndef EXPORT_SCHEME_DIALOG_H #define EXPORT_SCHEME_DIALOG_H /** * Copyright (C) 2009 Michael Jansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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 "ui_export_scheme_dialog.h" #include #include /** * @author Michael Jansen */ class ExportSchemeDialog : public KDialog { Q_OBJECT public: - ExportSchemeDialog (QStringList components, QWidget *parent=NULL); + ExportSchemeDialog (QStringList components, QWidget *parent=nullptr); ~ExportSchemeDialog() override; // Get the list of currently selected components QStringList selectedComponents() const; private: Ui::ExportSchemeDialog ui; // list of components to choose from QStringList mComponents; // list of buttons for the components QButtonGroup mButtons; }; // ExportSchemeDialog #endif /* EXPORT_SCHEME_DIALOG_H */ diff --git a/kcms/keys/kglobalshortcutseditor.cpp b/kcms/keys/kglobalshortcutseditor.cpp index 0fdf81046..219ace3e9 100644 --- a/kcms/keys/kglobalshortcutseditor.cpp +++ b/kcms/keys/kglobalshortcutseditor.cpp @@ -1,847 +1,847 @@ /* * Copyright 2008 Michael Jansen * * 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 "kglobalshortcutseditor.h" #include "ui_kglobalshortcutseditor.h" #include "ui_select_application.h" #include "export_scheme_dialog.h" #include "select_scheme_dialog.h" #include "globalshortcuts.h" #include "kglobalaccel_interface.h" #include "kglobalaccel_component_interface.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * README * * This class was created because the kshortcutseditor class has some shortcomings. That class uses * QTreeWidget and therefore makes it impossible for an outsider to switch the models. But the * global shortcuts editor did that. Each global component ( kded, krunner, kopete ... ) was * destined to be separately edited. If you selected another component the kshortcutseditor was * cleared and refilled. But the items take care of undoing. Therefore when switching the component * you lost the undo history. * * To solve that problem this class keeps one kshortcuteditor for each component. That is easier * than rewrite that dialog to a model/view framework. * * It perfectly covers a bug of KExtedableItemDelegate when clearing and refilling the associated * model. */ class ComponentData { public: ComponentData( const QString &uniqueName, const QDBusObjectPath &path, KShortcutsEditor *_editor); ~ComponentData(); QString uniqueName() const; KShortcutsEditor *editor(); QDBusObjectPath dbusPath(); private: QString _uniqueName; QDBusObjectPath _path; QPointer _editor; }; ComponentData::ComponentData( const QString &uniqueName, const QDBusObjectPath &path, KShortcutsEditor *editor) : _uniqueName(uniqueName), _path(path), _editor(editor) {} ComponentData::~ComponentData() { delete _editor; _editor = nullptr; } QString ComponentData::uniqueName() const { return _uniqueName; } QDBusObjectPath ComponentData::dbusPath() { return _path; } KShortcutsEditor *ComponentData::editor() { return _editor; } class KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate { public: KGlobalShortcutsEditorPrivate(KGlobalShortcutsEditor *q) : q(q), bus(QDBusConnection::sessionBus()) {} //! Setup the gui void initGUI(); //! Load the component at @a componentPath bool loadComponent(const QDBusObjectPath &componentPath); //! Return the componentPath for component QDBusObjectPath componentPath(const QString &componentUnique); //! Remove the component void removeComponent(const QString &componentUnique); KGlobalShortcutsEditor *q; Ui::KGlobalShortcutsEditor ui; Ui::SelectApplicationDialog selectApplicationDialogUi; QDialog *selectApplicationDialog = nullptr; QStackedWidget *stack = nullptr; KShortcutsEditor::ActionTypes actionTypes; QHash components; QDBusConnection bus; QStandardItemModel *model = nullptr; KCategorizedSortFilterProxyModel *proxyModel = nullptr; }; void loadAppsCategory(KServiceGroup::Ptr group, QStandardItemModel *model, QStandardItem *item) { if (group && group->isValid()) { KServiceGroup::List list = group->entries(); for( KServiceGroup::List::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) { const KSycocaEntry::Ptr p = (*it); if (p->isType(KST_KService)) { const KService::Ptr service(static_cast(p.data())); if (!service->noDisplay()) { QString genericName = service->genericName(); if (genericName.isNull()) { genericName = service->comment(); } QString description; if (!service->genericName().isEmpty() && service->genericName() != service->name()) { description = service->genericName(); } else if (!service->comment().isEmpty()) { description = service->comment(); } QStandardItem *subItem = new QStandardItem(QIcon::fromTheme(service->icon()), service->name()); subItem->setData(service->entryPath()); if (item) { item->appendRow(subItem); } else { model->appendRow(subItem); } } } else if (p->isType(KST_KServiceGroup)) { KServiceGroup::Ptr subGroup(static_cast(p.data())); if (!subGroup->noDisplay() && subGroup->childCount() > 0) { if (item) { loadAppsCategory(subGroup, model, item); } else { QStandardItem *subItem = new QStandardItem(QIcon::fromTheme(subGroup->icon()), subGroup->caption()); model->appendRow(subItem); loadAppsCategory(subGroup, model, subItem); } } } } } } void KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate::initGUI() { ui.setupUi(q); selectApplicationDialog = new QDialog(); selectApplicationDialogUi.setupUi(selectApplicationDialog); // Create a stacked widget. stack = new QStackedWidget(q); ui.currentComponentLayout->addWidget(stack); //HACK to make those two un-alignable components, aligned ui.componentLabel->setMinimumHeight(ui.lineEditSpacer->sizeHint().height()); ui.lineEditSpacer->setVisible(false); ui.addButton->setIcon(QIcon::fromTheme("list-add")); ui.removeButton->setIcon(QIcon::fromTheme("list-remove")); ui.components->setCategoryDrawer(new KCategoryDrawer(ui.components)); ui.components->setModelColumn(0); // Build the menu QMenu *menu = new QMenu(q); menu->addAction( QIcon::fromTheme(QStringLiteral("document-import")), i18n("Import Scheme..."), q, SLOT(importScheme())); menu->addAction( QIcon::fromTheme(QStringLiteral("document-export")), i18n("Export Scheme..."), q, SLOT(exportScheme())); menu->addAction( i18n("Set All Shortcuts to None"), q, SLOT(clearConfiguration())); connect(ui.addButton, &QToolButton::clicked, [this]() { if (!selectApplicationDialogUi.treeView->model()) { KRecursiveFilterProxyModel *filterModel = new KRecursiveFilterProxyModel(selectApplicationDialogUi.treeView); QStandardItemModel *appModel = new QStandardItemModel(selectApplicationDialogUi.treeView); selectApplicationDialogUi.kfilterproxysearchline->setProxy(filterModel); filterModel->setSourceModel(appModel); appModel->setHorizontalHeaderLabels({i18n("Applications")}); loadAppsCategory(KServiceGroup::root(), appModel, nullptr); selectApplicationDialogUi.treeView->setModel(filterModel); } selectApplicationDialog->show(); }); connect(selectApplicationDialog, &QDialog::accepted, [this]() { if (selectApplicationDialogUi.treeView->selectionModel()->selectedIndexes().length() == 1) { const QString desktopPath = selectApplicationDialogUi.treeView->model()->data(selectApplicationDialogUi.treeView->selectionModel()->selectedIndexes().first(), Qt::UserRole+1).toString(); if (!desktopPath.isEmpty() &&QFile::exists(desktopPath) ) { const QString desktopFile = desktopPath.split(QLatin1Char('/')).last(); if (!desktopPath.isEmpty()) { KDesktopFile sourceDF(desktopPath); KDesktopFile *destinationDF = sourceDF.copyTo(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kglobalaccel/") + desktopFile); qWarning()<sync(); //TODO: a DBUS call to tell the daemon to refresh desktop files // Create a action collection for our current component:context KActionCollection *col = new KActionCollection(q, desktopFile); foreach(const QString &actionId, sourceDF.readActions()) { const QString friendlyName = sourceDF.actionGroup(actionId).readEntry(QStringLiteral("Name")); QAction *action = col->addAction(actionId); action->setProperty("isConfigurationAction", QVariant(true)); // see KAction::~KAction action->setProperty("componentDisplayName", friendlyName); action->setText(friendlyName); KGlobalAccel::self()->setShortcut(action, QList()); QStringList sequencesStrings = sourceDF.actionGroup(actionId).readEntry(QStringLiteral("X-KDE-Shortcuts"), QString()).split(QLatin1Char('/')); QList sequences; if (!sequencesStrings.isEmpty()) { Q_FOREACH (const QString &seqString, sequencesStrings) { sequences.append(QKeySequence(seqString)); } } if (!sequences.isEmpty()) { KGlobalAccel::self()->setDefaultShortcut(action, sequences); } } //Global launch action { const QString friendlyName = i18n("Launch %1", sourceDF.readName()); QAction *action = col->addAction(QStringLiteral("_launch")); action->setProperty("isConfigurationAction", QVariant(true)); // see KAction::~KAction action->setProperty("componentDisplayName", friendlyName); action->setText(friendlyName); KGlobalAccel::self()->setShortcut(action, QList()); QStringList sequencesStrings = sourceDF.desktopGroup().readEntry(QStringLiteral("X-KDE-Shortcuts"), QString()).split(QLatin1Char('/')); QList sequences; if (!sequencesStrings.isEmpty()) { Q_FOREACH (const QString &seqString, sequencesStrings) { sequences.append(QKeySequence(seqString)); } } if (!sequences.isEmpty()) { KGlobalAccel::self()->setDefaultShortcut(action, sequences); } } q->addCollection(col, QDBusObjectPath(), desktopFile, sourceDF.readName()); } } } }); connect(ui.removeButton, &QToolButton::clicked, [this]() { //TODO: different way to remove components that are desktop files //disabled desktop files need Hidden=true key QString name = proxyModel->data(ui.components->currentIndex()).toString(); QString componentUnique = components.value(name)->uniqueName(); // The confirmation text is different when the component is active if (KGlobalAccel::isComponentActive(componentUnique)) { if (KMessageBox::questionYesNo( q, i18n("Component '%1' is currently active. Only global shortcuts currently not active will be removed from the list.\n" "All global shortcuts will reregister themselves with their defaults when they are next started.", componentUnique), i18n("Remove component")) != KMessageBox::Yes) { return; } } else { if (KMessageBox::questionYesNo( q, i18n("Are you sure you want to remove the registered shortcuts for component '%1'? " "The component and shortcuts will reregister themselves with their default settings" " when they are next started.", componentUnique), i18n("Remove component")) != KMessageBox::Yes) { return; } } // Initiate the removing of the component. if (KGlobalAccel::cleanComponent(componentUnique)) { // Get the objectPath BEFORE we delete the source of it QDBusObjectPath oPath = components.value(name)->dbusPath(); // Remove the component from the gui removeComponent(componentUnique); // Load it again // ############# if (loadComponent(oPath)) { // Active it q->activateComponent(name); } } }); ui.menu_button->setMenu(menu); proxyModel = new KCategorizedSortFilterProxyModel(q); proxyModel->setCategorizedModel(true); model = new QStandardItemModel(0, 1, proxyModel); proxyModel->setSourceModel(model); proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); ui.components->setModel(proxyModel); connect(ui.components->selectionModel(), &QItemSelectionModel::currentChanged, q, [this](const QModelIndex &index) { QString name = proxyModel->data(index).toString(); q->activateComponent(name); }); } KGlobalShortcutsEditor::KGlobalShortcutsEditor(QWidget *parent, KShortcutsEditor::ActionTypes actionTypes) : QWidget(parent), d(new KGlobalShortcutsEditorPrivate(this)) { d->actionTypes = actionTypes; // Setup the ui d->initGUI(); } KGlobalShortcutsEditor::~KGlobalShortcutsEditor() { // Before closing the door, undo all changes undo(); delete d->selectApplicationDialog; qDeleteAll(d->components); delete d; } void KGlobalShortcutsEditor::activateComponent(const QString &component) { QHash::Iterator iter = d->components.find(component); if (iter == d->components.end()) { Q_ASSERT(iter != d->components.end()); return; } else { QModelIndexList results = d->proxyModel->match(d->proxyModel->index(0, 0), Qt::DisplayRole, component); Q_ASSERT(!results.isEmpty()); if (results.first().isValid()) { // Known component. Get it. d->ui.components->setCurrentIndex(results.first()); d->stack->setCurrentWidget((*iter)->editor()); } } } void KGlobalShortcutsEditor::addCollection( KActionCollection *collection, const QDBusObjectPath &objectPath, const QString &id, const QString &friendlyName) { KShortcutsEditor *editor; // Check if this component is known QHash::Iterator iter = d->components.find(friendlyName); if (iter == d->components.end()) { // Unknown component. Create an editor. editor = new KShortcutsEditor(this, d->actionTypes); d->stack->addWidget(editor); // try to find one appropriate icon ( allowing NULL pixmap to be returned) QPixmap pixmap = KIconLoader::global()->loadIcon(id, KIconLoader::Small, 0, - KIconLoader::DefaultState, QStringList(), 0, true); + KIconLoader::DefaultState, QStringList(), nullptr, true); if (pixmap.isNull()) { KService::Ptr service = KService::serviceByStorageId(id); if(service) { pixmap = KIconLoader::global()->loadIcon(service->icon(), KIconLoader::Small, 0, - KIconLoader::DefaultState, QStringList(), 0, true); + KIconLoader::DefaultState, QStringList(), nullptr, true); } } // if NULL pixmap is returned, use the F.D.O "system-run" icon if (pixmap.isNull()) { pixmap = KIconLoader::global()->loadIcon(QStringLiteral("system-run"), KIconLoader::Small); } // Add to the component list QStandardItem *item = new QStandardItem(pixmap, friendlyName); if (id.endsWith(QLatin1String(".desktop"))) { item->setData(i18n("Application Launchers"), KCategorizedSortFilterProxyModel::CategoryDisplayRole); item->setData(0, KCategorizedSortFilterProxyModel::CategorySortRole); } else { item->setData(i18n("Other Shortcuts"), KCategorizedSortFilterProxyModel::CategoryDisplayRole); item->setData(1, KCategorizedSortFilterProxyModel::CategorySortRole); } d->model->appendRow(item); d->proxyModel->sort(0); // Add to our component registry ComponentData *cd = new ComponentData(id, objectPath, editor); d->components.insert(friendlyName, cd); connect(editor, &KShortcutsEditor::keyChange, this, &KGlobalShortcutsEditor::_k_key_changed); } else { // Known component. editor = (*iter)->editor(); } // Add the collection to the editor of the component editor->addCollection(collection, friendlyName); if (d->proxyModel->rowCount() > -1) { d->ui.components->setCurrentIndex(d->proxyModel->index(0, 0)); QString name = d->proxyModel->data(d->proxyModel->index(0, 0)).toString(); activateComponent(name); } } void KGlobalShortcutsEditor::clearConfiguration() { QString name = d->proxyModel->data(d->ui.components->currentIndex()).toString(); d->components[name]->editor()->clearConfiguration(); } void KGlobalShortcutsEditor::defaults(ComponentScope scope) { switch (scope) { case AllComponents: Q_FOREACH (ComponentData *cd, d->components) { // The editors are responsible for the reset cd->editor()->allDefault(); } break; case CurrentComponent: { QString name = d->proxyModel->data(d->ui.components->currentIndex()).toString(); // The editors are responsible for the reset d->components[name]->editor()->allDefault(); } break; default: Q_ASSERT(false); }; } void KGlobalShortcutsEditor::clear() { // Remove all components and their associated editors qDeleteAll(d->components); d->components.clear(); d->model->clear(); } static bool compare(const QString &a, const QString &b) { return a.toLower().localeAwareCompare(b.toLower()) < 0; } void KGlobalShortcutsEditor::exportScheme() { QStringList keys = d->components.keys(); qSort(keys.begin(), keys.end(), compare); ExportSchemeDialog dia(keys); if (dia.exec() != KMessageBox::Ok) { return; } const QUrl url = QFileDialog::getSaveFileUrl(this, QString(), QUrl(), QStringLiteral("*.kksrc")); if (!url.isEmpty()) { KConfig config(url.path(), KConfig::SimpleConfig); // TODO: Bug ossi to provide a method for this Q_FOREACH(const QString &group, config.groupList()) { // do not overwrite the Settings group. That makes it possible to // update the standard scheme kksrc file with the editor. if (group == QLatin1String("Settings")) continue; config.deleteGroup(group); } exportConfiguration(dia.selectedComponents(), &config); } } void KGlobalShortcutsEditor::importScheme() { // Check for unsaved modifications if (isModified()) { int choice = KMessageBox::warningContinueCancel( this, i18n("Your current changes will be lost if you load another scheme before saving this one"), i18n("Load Shortcut Scheme"), KGuiItem(i18n("Load"))); if (choice != KMessageBox::Continue) { return; } } SelectSchemeDialog dialog(this); if (dialog.exec() != KDialog::Accepted) { return; } QUrl url = dialog.selectedScheme(); if (!url.isLocalFile()) { KMessageBox::sorry(this, i18n("This file (%1) does not exist. You can only select local files.", url.url())); return; } KConfig config(url.path(), KConfig::SimpleConfig); importConfiguration(&config); } void KGlobalShortcutsEditor::load() { // Connect to kglobalaccel. If that fails there is no need to continue. qRegisterMetaType >(); qDBusRegisterMetaType >(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); org::kde::KGlobalAccel kglobalaccel( QStringLiteral("org.kde.kglobalaccel"), QStringLiteral("/kglobalaccel"), d->bus); if (!kglobalaccel.isValid()) { QString errorString; QDBusError error = kglobalaccel.lastError(); // The global shortcuts DBus service manages all global shortcuts and we // can't do anything useful without it. if (error.isValid()) { errorString = i18n("Message: %1\nError: %2", error.message(), error.name()); } KMessageBox::sorry( this, i18n("Failed to contact the KDE global shortcuts daemon\n") + errorString ); return; } // Undo all changes not yet applied undo(); clear(); QDBusReply< QList > componentsRc = kglobalaccel.allComponents(); if (!componentsRc.isValid()) { // Sometimes error pop up only after the first real call. QString errorString; QDBusError error = componentsRc.error(); // The global shortcuts DBus service manages all global shortcuts and we // can't do anything useful without it. if (error.isValid()) { errorString = i18n("Message: %1\nError: %2", error.message(), error.name()); } KMessageBox::sorry( this, i18n("Failed to contact the KDE global shortcuts daemon\n") + errorString ); return; } QList components = componentsRc; Q_FOREACH(const QDBusObjectPath &componentPath, components) { d->loadComponent(componentPath); } // Q_FOREACH(component) } void KGlobalShortcutsEditor::save() { // The editors are responsible for the saving //qDebug() << "Save the changes"; Q_FOREACH (ComponentData *cd, d->components) { cd->editor()->commit(); } } void KGlobalShortcutsEditor::importConfiguration(KConfigBase *config) { //qDebug() << config->groupList(); // In a first step clean out the current configurations. We do this // because we want to minimize the chance of conflicts. Q_FOREACH (ComponentData *cd, d->components) { KConfigGroup group(config, cd->uniqueName()); //qDebug() << cd->uniqueName() << group.name(); if (group.exists()) { //qDebug() << "Removing" << cd->uniqueName(); cd->editor()->clearConfiguration(); } } // Now import the new configurations. Q_FOREACH (ComponentData *cd, d->components) { KConfigGroup group(config, cd->uniqueName()); if (group.exists()) { //qDebug() << "Importing" << cd->uniqueName(); cd->editor()->importConfiguration(&group); } } } void KGlobalShortcutsEditor::exportConfiguration(QStringList components, KConfig *config) const { Q_FOREACH (const QString &componentFriendly, components) { QHash::Iterator iter = d->components.find(componentFriendly); if (iter == d->components.end()) { Q_ASSERT(iter != d->components.end()); continue; } else { KConfigGroup group(config, (*iter)->uniqueName()); (*iter)->editor()->exportConfiguration(&group); } } } void KGlobalShortcutsEditor::undo() { // The editors are responsible for the undo //qDebug() << "Undo the changes"; Q_FOREACH (ComponentData *cd, d->components) { cd->editor()->undoChanges(); } } bool KGlobalShortcutsEditor::isModified() const { Q_FOREACH (ComponentData *cd, d->components) { if (cd->editor()->isModified()) { return true; } } return false; } void KGlobalShortcutsEditor::_k_key_changed() { emit changed(isModified()); } QDBusObjectPath KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate::componentPath(const QString &componentUnique) { return QDBusObjectPath(QStringLiteral("/component/") + componentUnique); } bool KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate::loadComponent(const QDBusObjectPath &componentPath) { // Get the component org::kde::kglobalaccel::Component component( QStringLiteral("org.kde.kglobalaccel"), componentPath.path(), bus); if (!component.isValid()) { //qDebug() << "Component " << componentPath.path() << "not valid! Skipping!"; return false; } // Get the shortcut contexts. QDBusReply shortcutContextsRc = component.getShortcutContexts(); if (!shortcutContextsRc.isValid()) { //qDebug() << "Failed to get contexts for component " //<< componentPath.path() <<"! Skipping!"; //qDebug() << shortcutContextsRc.error(); return false; } QStringList shortcutContexts = shortcutContextsRc; // We add the shortcuts for all shortcut contexts to the editor. This // way the user keeps full control of it's shortcuts. Q_FOREACH (const QString &shortcutContext, shortcutContexts) { QDBusReply< QList > shortcutsRc = component.allShortcutInfos(shortcutContext); if (!shortcutsRc.isValid()) { //qDebug() << "allShortcutInfos() failed for " << componentPath.path() << shortcutContext; continue; } QList shortcuts = shortcutsRc; // Shouldn't happen. But you never know if (shortcuts.isEmpty()) { //qDebug() << "Got shortcut context" << shortcutContext << "without shortcuts for" //<< componentPath.path(); continue; } // It's safe now const QString componentUnique = shortcuts[0].componentUniqueName(); QString componentContextId = componentUnique; // kglobalaccel knows that '|' is our separator between // component and context if (shortcutContext != QLatin1String("default")) { componentContextId += QStringLiteral("|") + shortcutContext; } // Create a action collection for our current component:context KActionCollection* col = new KActionCollection( q, componentContextId); // Now add the shortcuts. Q_FOREACH (const KGlobalShortcutInfo &shortcut, shortcuts) { const QString &objectName = shortcut.uniqueName(); QAction *action = col->addAction(objectName); action->setProperty("isConfigurationAction", QVariant(true)); // see KAction::~KAction action->setProperty("componentDisplayName", shortcut.componentFriendlyName()); action->setText(shortcut.friendlyName()); // Always call this to enable global shortcuts for the action. The editor widget // checks it. // Also actually loads the shortcut using the KAction::Autoloading mechanism. // Avoid setting the default shortcut; it would just be written to the global // configuration so we would not get the real one below. KGlobalAccel::self()->setShortcut(action, QList()); // The default shortcut will never be loaded because it's pointless in a real // application. There are no scarce resources [i.e. physical keys] to manage // so applications can set them at will and there's no autoloading. QList sc = shortcut.defaultKeys(); if (sc.count()>0) { KGlobalAccel::self()->setDefaultShortcut(action, sc); } } // Q_FOREACH(shortcut) QString componentFriendlyName = shortcuts[0].componentFriendlyName(); if (shortcuts[0].contextUniqueName() != QLatin1String("default")) { componentFriendlyName += QString('[') + shortcuts[0].contextFriendlyName() + QString(']'); } q->addCollection(col, componentPath, componentContextId, componentFriendlyName ); } // Q_FOREACH(context) return true; } void KGlobalShortcutsEditor::KGlobalShortcutsEditorPrivate::removeComponent( const QString &componentUnique ) { // TODO: Remove contexts too. Q_FOREACH (const QString &text, components.keys()) { if (components.value(text)->uniqueName() == componentUnique) { // Remove from QComboBox QModelIndexList results = proxyModel->match(proxyModel->index(0, 0), Qt::DisplayRole, text); Q_ASSERT(!results.isEmpty()); model->removeRow(proxyModel->mapToSource(results.first()).row()); // Remove from QStackedWidget stack->removeWidget(components[text]->editor()); // Remove the componentData delete components.take(text); } } } diff --git a/kcms/kfontinst/apps/CreateParent.h b/kcms/kfontinst/apps/CreateParent.h index 96b5b153a..d302ec087 100644 --- a/kcms/kfontinst/apps/CreateParent.h +++ b/kcms/kfontinst/apps/CreateParent.h @@ -1,72 +1,72 @@ #ifndef __CREATE_PARENT_H__ #define __CREATE_PARENT_H__ /* * 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 #include #include // // *Very* hacky way to get some KDE dialogs to appear to be transient // for 'xid' // // Create's a QWidget with size 0/0 and no border, makes this transient // for xid, and all other widgets can use this as their parent... static QWidget * createParent(int xid) { if(!xid) - return NULL; + return nullptr; - QWidget *parent=new QWidget(NULL, Qt::FramelessWindowHint); + QWidget *parent=new QWidget(nullptr, Qt::FramelessWindowHint); parent->resize(1, 1); parent->show(); XWindowAttributes attr; int rx, ry; Window junkwin; XSetTransientForHint(QX11Info::display(), parent->winId(), xid); if(XGetWindowAttributes(QX11Info::display(), xid, &attr)) { XTranslateCoordinates(QX11Info::display(), xid, attr.root, -attr.border_width, -16, &rx, &ry, &junkwin); rx=(rx+(attr.width/2)); if(rx<0) rx=0; ry=(ry+(attr.height/2)); if(ry<0) ry=0; parent->move(rx, ry); } parent->setWindowOpacity(0); parent->setWindowTitle(QLatin1String("KFI")); return parent; } #endif diff --git a/kcms/kfontinst/apps/Installer.cpp b/kcms/kfontinst/apps/Installer.cpp index a303a2993..4ac088a0a 100644 --- a/kcms/kfontinst/apps/Installer.cpp +++ b/kcms/kfontinst/apps/Installer.cpp @@ -1,160 +1,160 @@ /* * 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 "Installer.h" #include "Misc.h" #include "FontsPackage.h" #include #include #include #include #include #include #include #include #include "JobRunner.h" #include "CreateParent.h" #include "config-workspace.h" namespace KFI { int CInstaller::install(const QSet &urls) { QSet::ConstIterator it(urls.begin()), end(urls.end()); bool sysInstall(false); CJobRunner *jobRunner=new CJobRunner(itsParent); CJobRunner::startDbusService(); if(!Misc::root()) { switch(KMessageBox::questionYesNoCancel(itsParent, i18n("Do you wish to install the font(s) for personal use " "(only available to you), or " "system-wide (available to all users)?"), i18n("Where to Install"), KGuiItem(i18n(KFI_KIO_FONTS_USER)), KGuiItem(i18n(KFI_KIO_FONTS_SYS)))) { case KMessageBox::No: sysInstall=true; break; case KMessageBox::Cancel: return -1; default: break; } } QSet instUrls; for(; it!=end; ++it) { auto job = KIO::mostLocalUrl(*it); job->exec(); QUrl local = job->mostLocalUrl(); bool package(false); if(local.isLocalFile()) { QString localFile(local.toLocalFile()); if(Misc::isPackage(localFile)) { instUrls+=FontsPackage::extract(localFile, &itsTempDir); package=true; } } if(!package) { QList associatedUrls; CJobRunner::getAssociatedUrls(*it, associatedUrls, false, itsParent); instUrls.insert(*it); QList::Iterator aIt(associatedUrls.begin()), aEnd(associatedUrls.end()); for(; aIt!=aEnd; ++aIt) instUrls.insert(*aIt); } } if(instUrls.count()) { CJobRunner::ItemList list; QSet::ConstIterator it(instUrls.begin()), end(instUrls.end()); for(; it!=end; ++it) list.append(*it); return jobRunner->exec(CJobRunner::CMD_INSTALL, list, Misc::root() || sysInstall); } else return -1; } CInstaller::~CInstaller() { delete itsTempDir; } } int main(int argc, char **argv) { QApplication app(argc, argv); KLocalizedString::setApplicationDomain(KFI_CATALOGUE); KAboutData aboutData("kfontinst", i18n("Font Installer"), WORKSPACE_VERSION_STRING, i18n("Simple font installer"), KAboutLicense::GPL, i18n("(C) Craig Drummond, 2007")); KAboutData::setApplicationData(aboutData); QGuiApplication::setWindowIcon(QIcon::fromTheme("preferences-desktop-font-installer")); QCommandLineParser parser; const QCommandLineOption embedOption(QLatin1String("embed"), i18n("Makes the dialog transient for an X app specified by winid"), QLatin1String("winid")); parser.addOption(embedOption); parser.addPositionalArgument(QLatin1String("[URL]"), i18n("URL to install")); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); QSet urls; foreach (const QString &arg, parser.positionalArguments()) urls.insert(QUrl::fromUserInput(arg, QDir::currentPath())); if (urls.count()) { QString opt(parser.value(embedOption)); - KFI::CInstaller inst(createParent(opt.size() ? opt.toInt(0, 16) : 0)); + KFI::CInstaller inst(createParent(opt.size() ? opt.toInt(nullptr, 16) : 0)); return inst.install(urls); } return -1; } diff --git a/kcms/kfontinst/apps/Installer.h b/kcms/kfontinst/apps/Installer.h index a0e447865..107aaa2f4 100644 --- a/kcms/kfontinst/apps/Installer.h +++ b/kcms/kfontinst/apps/Installer.h @@ -1,53 +1,53 @@ #ifndef __INSTALLER_H__ #define __INSTALLER_H__ /* * 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 #include class QWidget; class QTemporaryDir; namespace KFI { class CInstaller { public: CInstaller(QWidget *p) - : itsParent(p), itsTempDir(NULL) { } + : itsParent(p), itsTempDir(nullptr) { } ~CInstaller(); int install(const QSet &urls); private: QWidget *itsParent; QTemporaryDir *itsTempDir; }; } #endif diff --git a/kcms/kfontinst/apps/Printer.cpp b/kcms/kfontinst/apps/Printer.cpp index 8374104ce..a2e39468b 100644 --- a/kcms/kfontinst/apps/Printer.cpp +++ b/kcms/kfontinst/apps/Printer.cpp @@ -1,513 +1,513 @@ /* * 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 "config-fontinst.h" #include "Printer.h" #include "FcEngine.h" #include "ActionLabel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config-workspace.h" #if defined(Q_WS_X11) || defined(Q_WS_QWS) #include #include #include FT_FREETYPE_H #endif #ifdef HAVE_LOCALE_H #include #include #include #include #endif #include "CreateParent.h" // Enable the following to allow printing of non-installed fonts. Does not seem to work :-( //#define KFI_PRINT_APP_FONTS using namespace KFI; static const int constMarginLineBefore=1; static const int constMarginLineAfter=2; static const int constMarginFont=4; inline bool sufficientSpace(int y, int pageHeight, const QFontMetrics &fm) { return (y+constMarginFont+fm.height())fontMetrics().height(), required=titleFontHeight+constMarginLineBefore+constMarginLineAfter; for(unsigned int s=0; sizes[s]; ++s) { font.setPointSize(sizes[s]); required+=QFontMetrics(font, painter->device()).height(); if(sizes[s+1]) required+=constMarginFont; } if(0==size) { font.setPointSize(CFcEngine::constDefaultAlphaSize); int fontHeight=QFontMetrics(font, painter->device()).height(); required+=(3*(constMarginFont+fontHeight))+ constMarginLineBefore+constMarginLineAfter; } return (y+required)num_charmaps; ++cmap) if(face->charmaps[cmap] && FT_ENCODING_ADOBE_CUSTOM==face->charmaps[cmap]->encoding) { FT_Select_Charmap(face, FT_ENCODING_ADOBE_CUSTOM); break; } for(unsigned int i=1; i<65535; ++i) if(FT_Get_Char_Index(face, i)) { newStr+=QChar(i); if(newStr.length()>255) break; } return newStr; } static QString usableStr(FT_Face face, const QString &str) { unsigned int slen=str.length(), ch; QString newStr; for(ch=0; ch &items, int size, QObject *parent) : QThread(parent) , itsPrinter(printer) , itsItems(items) , itsSize(size) , itsCancelled(false) { } CPrintThread::~CPrintThread() { } void CPrintThread::cancel() { itsCancelled=true; } void CPrintThread::run() { QPainter painter; QFont sans("sans", 12, QFont::Bold); bool changedFontEmbeddingSetting(false); QString str(CFcEngine(false).getPreviewString()); if(!itsPrinter->fontEmbeddingEnabled()) { itsPrinter->setFontEmbeddingEnabled(true); changedFontEmbeddingSetting=true; } itsPrinter->setResolution(72); painter.begin(itsPrinter); int pageWidth=painter.device()->width(), pageHeight=painter.device()->height(), y=0, oneSize[2]={itsSize, 0}; const int *sizes=oneSize; bool firstFont(true); if(0==itsSize) sizes=CFcEngine::constScalableSizes; painter.setClipping(true); painter.setClipRect(0, 0, pageWidth, pageHeight); QList::ConstIterator it(itsItems.constBegin()), end(itsItems.constEnd()); for(int i=0; it!=end && !itsCancelled; ++it, ++i) { QString name(FC::createName((*it).family, (*it).styleInfo)); emit progress(i, name); unsigned int s=0; QFont font; #ifdef KFI_PRINT_APP_FONTS QString family; if(-1!=appFont[(*it).family]) { family=QFontDatabase::applicationFontFamilies(appFont[(*it).family]).first(); font=QFont(family); } #else font=CFcEngine::getQFont((*it).family, (*it).styleInfo, CFcEngine::constDefaultAlphaSize); #endif painter.setFont(sans); if(!firstFont && !sufficientSpace(y, &painter, font, sizes, pageHeight, itsSize)) { itsPrinter->newPage(); y=0; } painter.setFont(sans); y+=painter.fontMetrics().height(); painter.drawText(0, y, name); y+=constMarginLineBefore; painter.drawLine(0, y, pageWidth, y); y+=constMarginLineAfter; bool onlyDrawChars=false; Qt::TextElideMode em=Qt::LeftToRight==QApplication::layoutDirection() ? Qt::ElideRight : Qt::ElideLeft; if(0==itsSize) { font.setPointSize(CFcEngine::constDefaultAlphaSize); painter.setFont(font); QFontMetrics fm(font, painter.device()); bool lc=hasStr(font, CFcEngine::getLowercaseLetters()), uc=hasStr(font, CFcEngine::getUppercaseLetters()); onlyDrawChars=!lc && !uc; if(lc || uc) y+=CFcEngine::constDefaultAlphaSize; if(lc) { painter.drawText(0, y, fm.elidedText(CFcEngine::getLowercaseLetters(), em, pageWidth)); y+=constMarginFont+CFcEngine::constDefaultAlphaSize; } if(uc) { painter.drawText(0, y, fm.elidedText(CFcEngine::getUppercaseLetters(), em, pageWidth)); y+=constMarginFont+CFcEngine::constDefaultAlphaSize; } if(lc || uc) { QString validPunc(usableStr(font, CFcEngine::getPunctuation())); if(validPunc.length()>=(CFcEngine::getPunctuation().length()/2)) { painter.drawText(0, y, fm.elidedText(CFcEngine::getPunctuation(), em, pageWidth)); y+=constMarginFont+constMarginLineBefore; } painter.drawLine(0, y, pageWidth, y); y+=constMarginLineAfter; } } for(; sizes[s]; ++s) { y+=sizes[s]; font.setPointSize(sizes[s]); painter.setFont(font); QFontMetrics fm(font, painter.device()); if(sufficientSpace(y, pageHeight, fm)) { painter.drawText(0, y, fm.elidedText(previewString(font, str, onlyDrawChars), em, pageWidth)); if(sizes[s+1]) y+=constMarginFont; } else break; } y+=(s<1 || sizes[s-1]<25 ? 14 : 28); firstFont=false; } emit progress(itsItems.count(), QString()); painter.end(); // // Did we change the users font settings? If so, reset to their previous values... if(changedFontEmbeddingSetting) itsPrinter->setFontEmbeddingEnabled(false); } CPrinter::CPrinter(QWidget *parent) : QDialog(parent) { setWindowTitle(i18n("Print")); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::rejected, this, &CPrinter::slotCancelClicked); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QFrame *page = new QFrame(this); QGridLayout *layout=new QGridLayout(page); itsStatusLabel=new QLabel(page); itsProgress=new QProgressBar(page); layout->addWidget(itsActionLabel = new CActionLabel(this), 0, 0, 2, 1); layout->addWidget(itsStatusLabel, 0, 1); layout->addWidget(itsProgress, 1, 1); itsProgress->setRange(0, 100); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 2, 0); mainLayout->addWidget(page); mainLayout->addWidget(buttonBox); setMinimumSize(420, 80); } CPrinter::~CPrinter() { } void CPrinter::print(const QList &items, int size) { #ifdef HAVE_LOCALE_H char *oldLocale=setlocale(LC_NUMERIC, "C"); #endif QPrinter printer; QPrintDialog *dialog = new QPrintDialog(&printer, parentWidget()); if(dialog->exec()) { CPrintThread *thread = new CPrintThread(&printer, items, size, this); itsProgress->setRange(0, items.count()); itsProgress->setValue(0); progress(0, QString()); connect(thread, SIGNAL(progress(int,QString)), SLOT(progress(int,QString))); connect(thread, SIGNAL(finished()), SLOT(accept())); connect(this, SIGNAL(cancelled()), thread, SLOT(cancel())); itsActionLabel->startAnimation(); thread->start(); exec(); delete thread; } delete dialog; #ifdef HAVE_LOCALE_H if(oldLocale) setlocale(LC_NUMERIC, oldLocale); #endif } void CPrinter::progress(int p, const QString &label) { if(!label.isEmpty()) itsStatusLabel->setText(label); itsProgress->setValue(p); } void CPrinter::slotCancelClicked() { itsStatusLabel->setText(i18n("Canceling...")); emit cancelled(); } void CPrinter::closeEvent(QCloseEvent *e) { Q_UNUSED(e) e->ignore(); slotCancelClicked(); } int main(int argc, char **argv) { QApplication app(argc, argv); KLocalizedString::setApplicationDomain(KFI_CATALOGUE); KAboutData aboutData("kfontprint", i18n("Font Printer"), WORKSPACE_VERSION_STRING, i18n("Simple font printer"), KAboutLicense::GPL, i18n("(C) Craig Drummond, 2007")); KAboutData::setApplicationData(aboutData); QGuiApplication::setWindowIcon(QIcon::fromTheme("kfontprint")); QCommandLineParser parser; const QCommandLineOption embedOption(QLatin1String("embed"), i18n("Makes the dialog transient for an X app specified by winid"), QLatin1String("winid")); parser.addOption(embedOption); const QCommandLineOption sizeOption(QLatin1String("size"), i18n("Size index to print fonts"), QLatin1String("index")); parser.addOption(sizeOption); const QCommandLineOption pfontOption(QLatin1String("pfont"), i18n("Font to print, specified as \"Family,Style\" where Style is a 24-bit decimal number composed as: "), QLatin1String("font")); parser.addOption(pfontOption); const QCommandLineOption listfileOption(QLatin1String("listfile"), i18n("File containing list of fonts to print"), QLatin1String("file")); parser.addOption(listfileOption); const QCommandLineOption deletefileOption(QLatin1String("deletefile"), i18n("Remove file containing list of fonts to print")); parser.addOption(deletefileOption); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); QList fonts; int size(parser.value(sizeOption).toInt()); if(size>-1 && size<256) { QString listFile(parser.value(listfileOption)); if(listFile.size()) { QFile f(listFile); if(f.open(QIODevice::ReadOnly)) { QTextStream str(&f); while (!str.atEnd()) { QString family(str.readLine()), style(str.readLine()); if(!family.isEmpty() && !style.isEmpty()) fonts.append(Misc::TFont(family, style.toUInt())); else break; } f.close(); } if(parser.isSet(deletefileOption)) ::unlink(listFile.toLocal8Bit().constData()); } else { QStringList fl(parser.values(pfontOption)); QStringList::ConstIterator it(fl.begin()), end(fl.end()); for(; it!=end; ++it) { QString f(*it); int commaPos=f.lastIndexOf(','); if(-1!=commaPos) fonts.append(Misc::TFont(f.left(commaPos), f.mid(commaPos+1).toUInt())); } } if(fonts.count()) { - CPrinter(createParent(parser.value(embedOption).toInt(0, 16))).print(fonts, size); + CPrinter(createParent(parser.value(embedOption).toInt(nullptr, 16))).print(fonts, size); return 0; } } return -1; } diff --git a/kcms/kfontinst/dbus/FontInst.cpp b/kcms/kfontinst/dbus/FontInst.cpp index ca1720ba8..bce0e09d4 100644 --- a/kcms/kfontinst/dbus/FontInst.cpp +++ b/kcms/kfontinst/dbus/FontInst.cpp @@ -1,974 +1,974 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2009 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 #include #include #include #include #include #include #include #include #include "FontInst.h" #include "fontinstadaptor.h" #include "Misc.h" #include "Fc.h" #include "WritingSystems.h" #include "Utils.h" #include "FontinstIface.h" #define KFI_DBUG qDebug() << time(0L) namespace KFI { static void decompose(const QString &name, QString &family, QString &style) { int commaPos=name.lastIndexOf(','); family=-1==commaPos ? name : name.left(commaPos); style=-1==commaPos ? KFI_WEIGHT_REGULAR : name.mid(commaPos+2); } static bool isSystem=false; static Folder theFolders[FontInst::FOLDER_COUNT]; static const int constSystemReconfigured=-1; static const int constConnectionsTimeout = 30 * 1000; static const int constFontListTimeout = 10 * 1000; typedef void (*SignalHandler)(int); static void registerSignalHandler(SignalHandler handler) { if (!handler) handler = SIG_DFL; sigset_t mask; sigemptyset(&mask); #ifdef SIGSEGV signal(SIGSEGV, handler); sigaddset(&mask, SIGSEGV); #endif #ifdef SIGFPE signal(SIGFPE, handler); sigaddset(&mask, SIGFPE); #endif #ifdef SIGILL signal(SIGILL, handler); sigaddset(&mask, SIGILL); #endif #ifdef SIGABRT signal(SIGABRT, handler); sigaddset(&mask, SIGABRT); #endif - sigprocmask(SIG_UNBLOCK, &mask, 0); + sigprocmask(SIG_UNBLOCK, &mask, nullptr); } void signalHander(int) { static bool inHandler=false; if(!inHandler) { inHandler=true; theFolders[isSystem ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER].saveDisabled(); inHandler=false; } } FontInst::FontInst() { isSystem=Misc::root(); registerTypes(); new FontinstAdaptor(this); QDBusConnection bus=QDBusConnection::sessionBus(); KFI_DBUG << "Connecting to session bus"; if(!bus.registerService(OrgKdeFontinstInterface::staticInterfaceName())) { KFI_DBUG << "Failed to register service!"; ::exit(-1); } if(!bus.registerObject(FONTINST_PATH, this)) { KFI_DBUG << "Failed to register object!"; ::exit(-1); } registerSignalHandler(signalHander); itsConnectionsTimer=new QTimer(this); itsFontListTimer=new QTimer(this); connect(itsConnectionsTimer, SIGNAL(timeout()), SLOT(connectionsTimeout())); connect(itsFontListTimer, SIGNAL(timeout()), SLOT(fontListTimeout())); itsConnectionsTimer->start(constConnectionsTimeout); itsFontListTimer->start(constFontListTimeout); for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) theFolders[i].init(FOLDER_SYS==i, isSystem); updateFontList(false); } FontInst::~FontInst() { for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) theFolders[i].saveDisabled(); } void FontInst::list(int folders, int pid) { KFI_DBUG << folders << pid; itsConnections.insert(pid); updateFontList(false); QList fonts; for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) if(0==folders || folders&(1<start(constConnectionsTimeout); itsFontListTimer->start(constFontListTimeout); emit fontList(pid, fonts); } void FontInst::statFont(const QString &name, int folders, int pid) { KFI_DBUG << name << folders << pid; bool checkSystem=0==folders || folders&SYS_MASK || isSystem, checkUser=0==folders || (folders&USR_MASK && !isSystem); FamilyCont::ConstIterator fam; StyleCont::ConstIterator st; itsConnections.insert(pid); if( (checkSystem && findFont(name, FOLDER_SYS, fam, st)) || (checkUser && findFont(name, FOLDER_USER, fam, st, !checkSystem)) ) { Family rv((*fam).name()); rv.add(*st); KFI_DBUG << "Found font, emit details..."; emit fontStat(pid, rv); } else { KFI_DBUG << "Font not found, emit empty details..."; emit fontStat(pid, Family(name)); } } void FontInst::install(const QString &file, bool createAfm, bool toSystem, int pid, bool checkConfig) { KFI_DBUG << file << createAfm << toSystem << pid << checkConfig; itsConnections.insert(pid); if(checkConfig) updateFontList(); EFolder folder=isSystem || toSystem ? FOLDER_SYS : FOLDER_USER; Family font; Utils::EFileType type=Utils::check(file, font); int result=Utils::FILE_BITMAP==type && !FC::bitmapsEnabled() ? STATUS_BITMAPS_DISABLED : Utils::FILE_INVALID==type ? STATUS_NOT_FONT_FILE : STATUS_OK; if(STATUS_OK==result) { if(Utils::FILE_AFM!=type && Utils::FILE_PFM!=type) for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT) && STATUS_OK==result; ++i) if(theFolders[i].contains(font.name(), (*font.styles().begin()).value())) result=STATUS_ALREADY_INSTALLED; if(STATUS_OK==result) { QString name(Misc::modifyName(Misc::getFile(file))), destFolder(Misc::getDestFolder(theFolders[folder].location(), name)); result=Utils::FILE_AFM!=type && Utils::FILE_PFM!=type && Misc::fExists(destFolder+name) ? (int)KIO::ERR_FILE_ALREADY_EXIST : (int)STATUS_OK; if(STATUS_OK==result) { if(toSystem && !isSystem) { KFI_DBUG << "Send request to system helper" << file << destFolder << name; QVariantMap args; args["method"] = "install"; args["file"] = file; args["name"] = name; args["destFolder"] = destFolder; args["createAfm"] = createAfm; args["type"] = (int)type; result=performAction(args); } else { if(!Misc::dExists(destFolder)) result=Misc::createDir(destFolder) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; if(STATUS_OK==result) result=QFile::copy(file, destFolder+name) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; if(STATUS_OK==result) { Misc::setFilePerms(QFile::encodeName(destFolder+name)); if((Utils::FILE_SCALABLE==type || Utils::FILE_PFM==type) && createAfm) Utils::createAfm(destFolder+name, type); } } if(STATUS_OK==result && Utils::FILE_AFM!=type && Utils::FILE_PFM!=type) { StyleCont::ConstIterator st(font.styles().begin()); FileCont::ConstIterator f((*st).files().begin()); File df(destFolder+name, (*f).foundry(), (*f).index()); (*st).clearFiles(); (*st).add(df); theFolders[folder].add(font); theFolders[folder].addModifiedDir(destFolder); emit fontsAdded(Families(font, FOLDER_SYS==folder)); } } } } emit status(pid, result); itsConnectionsTimer->start(constConnectionsTimeout); itsFontListTimer->start(constFontListTimeout); } void FontInst::uninstall(const QString &family, quint32 style, bool fromSystem, int pid, bool checkConfig) { KFI_DBUG << family << style << fromSystem << pid << checkConfig; itsConnections.insert(pid); if(checkConfig) updateFontList(); EFolder folder=isSystem || fromSystem ? FOLDER_SYS : FOLDER_USER; FamilyCont::ConstIterator fam; StyleCont::ConstIterator st; int result=findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST; if(STATUS_OK==result) { Family del((*fam).name()); Style s((*st).value(), (*st).scalable(), (*st).writingSystems()); FileCont files((*st).files()); FileCont::ConstIterator it(files.begin()), end(files.end()); if(fromSystem && !isSystem) { QStringList fileList; bool wasDisabled(false); for(; it!=end; ++it) { fileList.append((*it).path()); theFolders[FOLDER_SYS].addModifiedDir(Misc::getDir((*it).path())); if(!wasDisabled && Misc::isHidden(Misc::getFile((*it).path()))) wasDisabled=true; } QVariantMap args; args["method"] = "uninstall"; args["files"] = fileList; result=performAction(args); if(STATUS_OK==result) { FileCont empty; s.setFiles(files); (*st).setFiles(empty); if(wasDisabled) theFolders[FOLDER_SYS].setDisabledDirty(); } } else { for(; it!=end; ++it) if(!Misc::fExists((*it).path()) || QFile::remove((*it).path())) { // Also remove any AFM or PFM files... QStringList other; Misc::getAssociatedFiles((*it).path(), other); QStringList::ConstIterator oit(other.constBegin()), oend(other.constEnd()); for(; oit!=oend; ++oit) QFile::remove(*oit); theFolders[folder].addModifiedDir(Misc::getDir((*it).path())); (*st).remove(*it); s.add(*it); if(!theFolders[folder].disabledDirty() && Misc::isHidden(Misc::getFile((*it).path()))) theFolders[folder].setDisabledDirty(); } } if(STATUS_OK==result) { if((*st).files().isEmpty()) { (*fam).remove(*st); if((*fam).styles().isEmpty()) theFolders[folder].removeFont(*fam); } else result=STATUS_PARTIAL_DELETE; del.add(s); } emit fontsRemoved(Families(del, FOLDER_SYS==folder)); } KFI_DBUG << "status" << result; emit status(pid, result); itsConnectionsTimer->start(constConnectionsTimeout); itsFontListTimer->start(constFontListTimeout); } void FontInst::uninstall(const QString &name, bool fromSystem, int pid, bool checkConfig) { KFI_DBUG << name << fromSystem << pid << checkConfig; FamilyCont::ConstIterator fam; StyleCont::ConstIterator st; if(findFont(name, fromSystem || isSystem ? FOLDER_SYS : FOLDER_USER, fam, st)) uninstall((*fam).name(), (*st).value(), fromSystem, pid, checkConfig); else emit status(pid, KIO::ERR_DOES_NOT_EXIST); } void FontInst::move(const QString &family, quint32 style, bool toSystem, int pid, bool checkConfig) { KFI_DBUG << family << style << toSystem << pid << checkConfig; itsConnections.insert(pid); if(checkConfig) updateFontList(); if(isSystem) emit status(pid, KIO::ERR_UNSUPPORTED_ACTION); else { FamilyCont::ConstIterator fam; StyleCont::ConstIterator st; EFolder from=toSystem ? FOLDER_USER : FOLDER_SYS, to=toSystem ? FOLDER_SYS : FOLDER_USER; if(findFont(family, style, from, fam, st)) { FileCont::ConstIterator it((*st).files().begin()), end((*st).files().end()); QStringList files; for(; it!=end; ++it) { files.append((*it).path()); theFolders[from].addModifiedDir(Misc::getDir((*it).path())); // Actual 'to' folder does not really matter, as we only want to call fc-cache // ...actual folders only matter for xreating fonts.dir, etc, and we wont be doing this... theFolders[to].addModifiedDir(theFolders[to].location()); } QVariantMap args; args["method"] = "move"; args["files"] = files; args["toSystem"] = toSystem; args["dest"] = theFolders[to].location(); args["uid"] = getuid(); args["gid"] = getgid(); int result=performAction(args); if(STATUS_OK==result) updateFontList(); emit status(pid, result); } else { KFI_DBUG << "does not exist"; emit status(pid, KIO::ERR_DOES_NOT_EXIST); } } itsConnectionsTimer->start(constConnectionsTimeout); itsFontListTimer->start(constFontListTimeout); } static bool renameFontFile(const QString &from, const QString &to, int uid=-1, int gid=-1) { if (!QFile::rename(from, to)) return false; QByteArray dest(QFile::encodeName(to)); Misc::setFilePerms(dest); if(-1!=uid && -1!=gid) ::chown(dest.data(), uid, gid); return true; } void FontInst::enable(const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig) { KFI_DBUG << family << style << inSystem << pid << checkConfig; toggle(true, family, style, inSystem, pid, checkConfig); } void FontInst::disable(const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig) { KFI_DBUG << family << style << inSystem << pid << checkConfig; toggle(false, family, style, inSystem, pid, checkConfig); } void FontInst::removeFile(const QString &family, quint32 style, const QString &file, bool fromSystem, int pid, bool checkConfig) { KFI_DBUG << family << style << file << fromSystem << pid << checkConfig; itsConnections.insert(pid); if(checkConfig) updateFontList(); // First find the family/style EFolder folder=isSystem || fromSystem ? FOLDER_SYS : FOLDER_USER; FamilyCont::ConstIterator fam; StyleCont::ConstIterator st; int result=findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST; if(STATUS_OK==result) { // Family/style found - now check that the requested file is *within* the same folder as one // of the files linked to this font... FileCont files((*st).files()); FileCont::ConstIterator it(files.begin()), end(files.end()); QString dir(Misc::getDir(file)); result=KIO::ERR_DOES_NOT_EXIST; for(; it!=end && STATUS_OK!=result; ++it) if(Misc::getDir((*it).path())==dir) result=STATUS_OK; if(STATUS_OK==result) { // OK, found folder - so can now proceed to delete the file... if(fromSystem && !isSystem) { QVariantMap args; args["method"] = "removeFile"; args["file"] = file; result=performAction(args); } else { result=Misc::fExists(file) ? QFile::remove(file) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED : (int)KIO::ERR_DOES_NOT_EXIST; } if(STATUS_OK==result) theFolders[folder].addModifiedDir(dir); } } emit status(pid, result); } void FontInst::reconfigure(int pid, bool force) { KFI_DBUG << pid << force; bool sysModified(theFolders[FOLDER_SYS].isModified()); saveDisabled(); KFI_DBUG << theFolders[FOLDER_USER].isModified() << sysModified; if(!isSystem && (force || theFolders[FOLDER_USER].isModified())) theFolders[FOLDER_USER].configure(force); if(sysModified) { if(isSystem) { theFolders[FOLDER_SYS].configure(); } else { QVariantMap args; args["method"] = "reconfigure"; performAction(args); theFolders[FOLDER_SYS].clearModified(); } } itsConnectionsTimer->start(constConnectionsTimeout); itsFontListTimer->start(constFontListTimeout); updateFontList(); emit status(pid, isSystem ? constSystemReconfigured : STATUS_OK); } QString FontInst::folderName(bool sys) { return theFolders[sys || isSystem ? FOLDER_SYS : FOLDER_USER].location(); } void FontInst::saveDisabled() { if(isSystem) theFolders[FOLDER_SYS].saveDisabled(); else for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) if(FOLDER_SYS==i && !isSystem) { if(theFolders[i].disabledDirty()) { QVariantMap args; args["method"] = "saveDisabled"; performAction(args); theFolders[i].saveDisabled(); } } else theFolders[i].saveDisabled(); } void FontInst::connectionsTimeout() { bool canExit(true); KFI_DBUG << "exiting"; checkConnections(); for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) { if(theFolders[i].disabledDirty()) canExit=false; theFolders[i].saveDisabled(); } if(0==itsConnections.count()) { if(canExit) qApp->exit(0); else // Try again later... itsConnectionsTimer->start(constConnectionsTimeout); } } void FontInst::fontListTimeout() { updateFontList(true); itsFontListTimer->start(constFontListTimeout); } void FontInst::updateFontList(bool emitChanges) { // For some reason just the "!FcConfigUptoDate(0)" check does not always work :-( - FcBool fcModified=!FcConfigUptoDate(0); + FcBool fcModified=!FcConfigUptoDate(nullptr); if(fcModified || theFolders[FOLDER_SYS].fonts().isEmpty() || (!isSystem && theFolders[FOLDER_USER].fonts().isEmpty()) || theFolders[FOLDER_SYS].disabledDirty() || (!isSystem && theFolders[FOLDER_USER].disabledDirty())) { KFI_DBUG << "Need to refresh font lists"; if(fcModified) { KFI_DBUG << "Re-init FC"; if(!FcInitReinitialize()) KFI_DBUG << "Re-init failed????"; } Folder::Flat old[FOLDER_COUNT]; if(emitChanges) { KFI_DBUG << "Flatten existing font lists"; for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) old[i]=theFolders[i].flatten(); } saveDisabled(); for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) theFolders[i].clearFonts(); KFI_DBUG << "update list of fonts"; FcPattern *pat = FcPatternCreate(); FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_FAMILY, FC_FAMILYLANG, FC_WEIGHT, FC_LANG, FC_CHARSET, FC_SCALABLE, #ifndef KFI_FC_NO_WIDTHS FC_WIDTH, #endif - FC_SLANT, FC_INDEX, FC_FOUNDRY, (void*)0); + FC_SLANT, FC_INDEX, FC_FOUNDRY, (void*)nullptr); - FcFontSet *list=FcFontList(0, pat, os); + FcFontSet *list=FcFontList(nullptr, pat, os); FcPatternDestroy(pat); FcObjectSetDestroy(os); theFolders[FOLDER_SYS].loadDisabled(); if(!isSystem) theFolders[FOLDER_USER].loadDisabled(); if(list) { QString home(Misc::dirSyntax(QDir::homePath())); for (int i = 0; i < list->nfont; i++) { QString fileName(Misc::fileSyntax(FC::getFcString(list->fonts[i], FC_FILE))); if(!fileName.isEmpty() && Misc::fExists(fileName)) // && 0!=fileName.indexOf(constDefomaLocation)) { QString family, foundry; quint32 styleVal; int index; qulonglong writingSystems(WritingSystems::instance()->get(list->fonts[i])); FcBool scalable=FcFalse; if(FcResultMatch!=FcPatternGetBool(list->fonts[i], FC_SCALABLE, 0, &scalable)) scalable=FcFalse; FC::getDetails(list->fonts[i], family, styleVal, index, foundry); FamilyCont::ConstIterator fam=theFolders[isSystem || 0!=fileName.indexOf(home) ? FOLDER_SYS : FOLDER_USER].addFont(Family(family)); StyleCont::ConstIterator style=(*fam).add(Style(styleVal)); FileCont::ConstIterator file=(*style).add(File(fileName, foundry, index)); (*style).setWritingSystems((*style).writingSystems()|writingSystems); if(scalable) (*style).setScalable(); } } FcFontSetDestroy(list); } if(emitChanges) { KFI_DBUG << "Look for differences"; for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i) { KFI_DBUG << "Flatten, and take copies..."; Folder::Flat newList=theFolders[i].flatten(), onlyNew=newList; KFI_DBUG << "Determine differences..."; onlyNew.subtract(old[i]); old[i].subtract(newList); KFI_DBUG << "Emit changes..."; Families families=onlyNew.build(isSystem || i==FOLDER_SYS); if(!families.items.isEmpty()) emit fontsAdded(families); families=old[i].build(isSystem || i==FOLDER_SYS); if(!families.items.isEmpty()) emit fontsRemoved(families); } } KFI_DBUG << "updated list of fonts"; } } void FontInst::toggle(bool enable, const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig) { KFI_DBUG; itsConnections.insert(pid); if(checkConfig) updateFontList(); EFolder folder=isSystem || inSystem ? FOLDER_SYS : FOLDER_USER; FamilyCont::ConstIterator fam; StyleCont::ConstIterator st; int result=findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST; if(STATUS_OK==result) { FileCont files((*st).files()), toggledFiles; FileCont::ConstIterator it(files.begin()), end(files.end()); QHash movedFonts; QHash movedAssoc; QSet modifiedDirs; for(; it!=end && STATUS_OK==result; ++it) { QString to=Misc::getDir((*it).path())+ QString(enable ? Misc::unhide(Misc::getFile((*it).path())) : Misc::hide(Misc::getFile((*it).path()))); if(to!=(*it).path()) { KFI_DBUG << "MOVE:" << (*it).path() << " to " << to; // If the font is a system font, and we're not root, then just go through the actions here - so // that we can build the list of changes that would happen... if((inSystem && !isSystem) || renameFontFile((*it).path(), to)) { modifiedDirs.insert(Misc::getDir(enable ? to : (*it).path())); toggledFiles.insert(File(to, (*it).foundry(), (*it).index())); // Now try to move an associated AFM or PFM files... QStringList assoc; movedFonts[*it]=to; Misc::getAssociatedFiles((*it).path(), assoc); QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); for(; ait!=aend && STATUS_OK==result; ++ait) { to=Misc::getDir(*ait)+ QString(enable ? Misc::unhide(Misc::getFile(*ait)) : Misc::hide(Misc::getFile(*ait))); if(to!=*ait) { if((inSystem && !isSystem) || renameFontFile(*ait, to)) { movedAssoc[*ait]=to; } else { result=KIO::ERR_WRITE_ACCESS_DENIED; } } } } else { result=KIO::ERR_WRITE_ACCESS_DENIED; } } } if(inSystem && !isSystem) { Family toggleFam((*fam).name()); toggleFam.add(*st); QVariantMap args; args["method"] = "toggle"; QString xml; QTextStream str(&xml); toggleFam.toXml(false, str); args["xml"] = xml; args["enable"] = enable; result=performAction(args); } if(STATUS_OK==result) { Family addFam((*fam).name()), delFam((*fam).name()); Style addStyle((*st).value(), (*st).scalable(), (*st).writingSystems()), delStyle((*st).value(), (*st).scalable(), (*st).writingSystems()); addStyle.setFiles(toggledFiles); addFam.add(addStyle); delStyle.setFiles(files); delFam.add(delStyle); (*st).setFiles(toggledFiles); theFolders[folder].addModifiedDirs(modifiedDirs); emit fontsAdded(Families(addFam, FOLDER_SYS==folder)); emit fontsRemoved(Families(delFam, FOLDER_SYS==folder)); theFolders[folder].setDisabledDirty(); } else // un-move fonts! { QHash::ConstIterator fit(movedFonts.constBegin()), fend(movedFonts.constEnd()); QHash::ConstIterator ait(movedAssoc.constBegin()), aend(movedAssoc.constEnd()); for(; fit!=fend; ++fit) renameFontFile(fit.value(), fit.key().path()); for(; ait!=aend; ++ait) renameFontFile(ait.value(), ait.key()); } } emit status(pid, result); itsConnectionsTimer->start(constConnectionsTimeout); itsFontListTimer->start(constFontListTimeout); } void FontInst::addModifedSysFolders(const Family &family) { StyleCont::ConstIterator style(family.styles().begin()), styleEnd(family.styles().end()); for(; style!=styleEnd; ++style) { FileCont::ConstIterator file((*style).files().begin()), fileEnd((*style).files().end()); for(; file!=fileEnd; ++file) theFolders[FOLDER_SYS].addModifiedDir(Misc::getDir((*file).path())); } } void FontInst::checkConnections() { KFI_DBUG; QSet::ConstIterator it(itsConnections.begin()), end(itsConnections.end()); QSet remove; for(; it!=end; ++it) if(0!=kill(*it, 0)) remove.insert(*it); itsConnections.subtract(remove); } bool FontInst::findFontReal(const QString &family, const QString &style, EFolder folder, FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st) { KFI_DBUG; Family f(family); fam=theFolders[folder].fonts().find(f); if(theFolders[folder].fonts().end()==fam) return false; StyleCont::ConstIterator end((*fam).styles().end()); for(st=(*fam).styles().begin(); st!=end; ++st) if(FC::createStyleName((*st).value())==style) return true; return false; } bool FontInst::findFont(const QString &font, EFolder folder, FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st, bool updateList) { KFI_DBUG; QString family, style; decompose(font, family, style); if(!findFontReal(family, style, folder, fam, st)) { if(updateList) { // Not found, so refresh font list and try again... updateFontList(); return findFontReal(family, style, folder, fam, st); } else { return false; } } return true; } bool FontInst::findFontReal(const QString &family, quint32 style, EFolder folder, FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st) { KFI_DBUG; fam=theFolders[folder].fonts().find(Family(family)); if(theFolders[folder].fonts().end()==fam) return false; else { st=(*fam).styles().find(style); return (*fam).styles().end()!=st; } } bool FontInst::findFont(const QString &family, quint32 style, EFolder folder, FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st, bool updateList) { KFI_DBUG; if(!findFontReal(family, style, folder, fam, st)) { if(updateList) { // Not found, so refresh font list and try again... updateFontList(); return findFontReal(family, style, folder, fam, st); } else { return false; } } return true; } int FontInst::performAction(const QVariantMap &args) { KAuth::Action action("org.kde.fontinst.manage"); action.setHelperId("org.kde.fontinst"); action.setArguments(args); KFI_DBUG << "Call " << args["method"].toString() << " on helper"; itsFontListTimer->stop(); itsConnectionsTimer->stop(); KAuth::ExecuteJob* j = action.execute(); j->exec(); if (j->error()) { qWarning() << "kauth action failed" << j->errorString() << j->errorText(); //error is a KAuth::ActionReply::Error rest of this code expects KIO error codes which are extended by EStatus switch (j->error()) { case KAuth::ActionReply::Error::UserCancelledError: return KIO::ERR_USER_CANCELED; case KAuth::ActionReply::Error::AuthorizationDeniedError: /*fall through*/ case KAuth::ActionReply::Error::NoSuchActionError: return KIO::ERR_COULD_NOT_AUTHENTICATE; default: return KIO::ERR_INTERNAL; } return KIO::ERR_INTERNAL; } KFI_DBUG << "Success!"; return STATUS_OK; } } diff --git a/kcms/kfontinst/dbus/Helper.cpp b/kcms/kfontinst/dbus/Helper.cpp index 69b71766b..1e03f310b 100644 --- a/kcms/kfontinst/dbus/Helper.cpp +++ b/kcms/kfontinst/dbus/Helper.cpp @@ -1,443 +1,443 @@ /* * KHelper - KDE Font Installer * * Copyright 2003-2010 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 "Helper.h" #include "Folder.h" #include "FontInst.h" #include "Misc.h" #include "Utils.h" #include #include #include #include #include #include #include #include #include #define KFI_DBUG qDebug() << time(0L) KAUTH_HELPER_MAIN("org.kde.fontinst", KFI::Helper) namespace KFI { static Folder theFontFolder; typedef void (*SignalHandler)(int); static void registerSignalHandler(SignalHandler handler) { if (!handler) handler = SIG_DFL; sigset_t mask; sigemptyset(&mask); #ifdef SIGSEGV signal(SIGSEGV, handler); sigaddset(&mask, SIGSEGV); #endif #ifdef SIGFPE signal(SIGFPE, handler); sigaddset(&mask, SIGFPE); #endif #ifdef SIGILL signal(SIGILL, handler); sigaddset(&mask, SIGILL); #endif #ifdef SIGABRT signal(SIGABRT, handler); sigaddset(&mask, SIGABRT); #endif - sigprocmask(SIG_UNBLOCK, &mask, 0); + sigprocmask(SIG_UNBLOCK, &mask, nullptr); } static void signalHander(int) { static bool inHandler=false; if(!inHandler) { inHandler=true; theFontFolder.saveDisabled(); inHandler=false; } } static void cleanup() { theFontFolder.saveDisabled(); } Helper::Helper() { KFI_DBUG; QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); registerSignalHandler(signalHander); qAddPostRoutine(cleanup); theFontFolder.init(true, true); theFontFolder.loadDisabled(); } Helper::~Helper() { theFontFolder.saveDisabled(); } ActionReply Helper::manage(const QVariantMap &args) { int result=KIO::ERR_UNSUPPORTED_ACTION; QString method=args["method"].toString(); KFI_DBUG << method; if("install"==method) result=install(args); else if("uninstall"==method) result=uninstall(args); else if("move"==method) result=move(args); else if("toggle"==method) result=toggle(args); else if("removeFile"==method) result=removeFile(args); else if("reconfigure"==method) result=reconfigure(); else if("saveDisabled"==method) result=saveDisabled(); else KFI_DBUG << "Uknown action"; if(FontInst::STATUS_OK==result) return ActionReply::SuccessReply(); ActionReply reply(ActionReply::HelperErrorType); reply.setErrorCode(static_cast(result)); return reply; } int Helper::install(const QVariantMap &args) { QString file(args["file"].toString()), name(args["name"].toString()), destFolder(args["destFolder"].toString()); bool createAfm(args["createAfm"].toBool()); int type(args["type"].toInt()); KFI_DBUG << file << destFolder << name << createAfm; int result=FontInst::STATUS_OK; if(!Misc::dExists(destFolder)) result=Misc::createDir(destFolder) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; if(FontInst::STATUS_OK==result) result=QFile::copy(file, destFolder+name) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; if(FontInst::STATUS_OK==result) { Misc::setFilePerms(QFile::encodeName(destFolder+name)); if((Utils::FILE_SCALABLE==type || Utils::FILE_PFM==type) && createAfm) Utils::createAfm(destFolder+name, (KFI::Utils::EFileType)type); theFontFolder.addModifiedDir(destFolder); } return result; } int Helper::uninstall(const QVariantMap &args) { QStringList files(args["files"].toStringList()); int result=checkWriteAction(files); if(FontInst::STATUS_OK==result) { QStringList::ConstIterator it(files.constBegin()), end(files.constEnd()); for(; it!=end; ++it) if(!Misc::fExists(*it) || QFile::remove(*it)) { // Also remove any AFM or PFM files... QStringList other; Misc::getAssociatedFiles(*it, other); QStringList::ConstIterator oit(other.constBegin()), oend(other.constEnd()); for(; oit!=oend; ++oit) QFile::remove(*oit); theFontFolder.addModifiedDir(Misc::getDir(*it)); } } return result; } static bool renameFontFile(const QString &from, const QString &to, int uid=-1, int gid=-1) { if(!QFile::rename(from, to)) return false; QByteArray dest(QFile::encodeName(to)); Misc::setFilePerms(dest); if(-1!=uid && -1!=gid) ::chown(dest.data(), uid, gid); return true; } int Helper::move(const QVariantMap &args) { QStringList files(args["files"].toStringList()); bool toSystem(args["toSystem"].toBool()); QString dest(args["dest"].toString()); int uid(args["uid"].toInt()), gid(args["gid"].toInt()); KFI_DBUG << files << dest << toSystem; int result=FontInst::STATUS_OK; QStringList::ConstIterator it(files.constBegin()), end(files.constEnd()); // Cant move hidden fonts - need to unhide first. for(; it!=end && FontInst::STATUS_OK==result; ++it) if(Misc::isHidden(Misc::getFile(*it))) result=KIO::ERR_UNSUPPORTED_ACTION; if(FontInst::STATUS_OK==result) { QHash movedFiles; int toUid=toSystem ? getuid() : uid, fromUid=toSystem ? uid : getuid(), toGid=toSystem ? getgid() : gid, fromGid=toSystem ? gid : getgid(); // Move fonts! for(it=files.constBegin(); it!=end && FontInst::STATUS_OK==result; ++it) { QString name(Misc::modifyName(Misc::getFile(*it))), destFolder(Misc::getDestFolder(dest, name)); if(!Misc::dExists(destFolder)) { result=Misc::createDir(destFolder) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; if(FontInst::STATUS_OK==result) ::chown(QFile::encodeName(destFolder).data(), toUid, toGid); } if(renameFontFile(*it, destFolder+name, toUid, toGid)) { movedFiles[*it]=destFolder+name; // Now try to move an associated AFM or PFM files... QStringList assoc; Misc::getAssociatedFiles(*it, assoc); QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); for(; ait!=aend && FontInst::STATUS_OK==result; ++ait) { name=Misc::getFile(*ait); if(renameFontFile(*ait, destFolder+name, toUid, toGid)) movedFiles[*ait]=destFolder+name; else result=KIO::ERR_WRITE_ACCESS_DENIED; } if(toSystem) theFontFolder.addModifiedDir(theFontFolder.location()); } else result=KIO::ERR_WRITE_ACCESS_DENIED; } if(FontInst::STATUS_OK!=result) // un-move fonts! { QHash::ConstIterator it(movedFiles.constBegin()), end(movedFiles.constEnd()); for(; it!=end; ++it) renameFontFile(it.value(), it.key(), fromUid, fromGid); } } return result; } int Helper::toggle(const QVariantMap &args) { QDomDocument doc; doc.setContent(args["xml"].toString()); Family font(doc.documentElement(), true); bool enable(args["enable"].toBool()); KFI_DBUG << font.name() << enable; if(1!=font.styles().count()) return KIO::ERR_WRITE_ACCESS_DENIED; int result=FontInst::STATUS_OK; FileCont files((*font.styles().begin()).files()), toggledFiles; FileCont::ConstIterator it(files.constBegin()), end(files.constEnd()); QHash movedFonts; QHash movedAssoc; QSet modifiedDirs; // Move fonts! for(; it!=end && FontInst::STATUS_OK==result; ++it) { QString to=Misc::getDir((*it).path())+ QString(enable ? Misc::unhide(Misc::getFile((*it).path())) : Misc::hide(Misc::getFile((*it).path()))); if(to!=(*it).path()) { KFI_DBUG << "MOVE:" << (*it).path() << " to " << to; if(renameFontFile((*it).path(), to)) { modifiedDirs.insert(Misc::getDir(enable ? to : (*it).path())); toggledFiles.insert(File(to, (*it).foundry(), (*it).index())); // Now try to move an associated AFM or PFM files... QStringList assoc; movedFonts[*it]=to; Misc::getAssociatedFiles((*it).path(), assoc); QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); for(; ait!=aend && FontInst::STATUS_OK==result; ++ait) { to=Misc::getDir(*ait)+ QString(enable ? Misc::unhide(Misc::getFile(*ait)) : Misc::hide(Misc::getFile(*ait))); if(to!=*ait) { if(renameFontFile(*ait, to)) movedAssoc[*ait]=to; else result=KIO::ERR_WRITE_ACCESS_DENIED; } } } else result=KIO::ERR_WRITE_ACCESS_DENIED; } } theFontFolder.addModifiedDirs(modifiedDirs); if(FontInst::STATUS_OK==result) { FamilyCont::ConstIterator f=theFontFolder.fonts().find(font); if(theFontFolder.fonts().end()==f) f=theFontFolder.addFont(font); StyleCont::ConstIterator st=(*f).styles().find(*font.styles().begin()); if((*f).styles().end()==st) st=(*f).add(*font.styles().begin()); // This helper only needs to store list of disabled fonts, // for writing back to disk - therefore no need to store // list of enabled font files. FileCont empty; (*st).setFiles(enable ? empty : toggledFiles); if((*st).files().isEmpty()) (*f).remove(*st); if((*f).styles().isEmpty()) theFontFolder.removeFont(*f); theFontFolder.setDisabledDirty(); } else { QHash::ConstIterator fit(movedFonts.constBegin()), fend(movedFonts.constEnd()); QHash::ConstIterator ait(movedAssoc.constBegin()), aend(movedAssoc.constEnd()); for(; fit!=fend; ++fit) renameFontFile(fit.value(), fit.key().path()); for(; ait!=aend; ++ait) renameFontFile(ait.value(), ait.key()); } return result; } int Helper::removeFile(const QVariantMap &args) { QString file(args["file"].toString()); KFI_DBUG << file; QString dir(Misc::getDir(file)); int result=Misc::fExists(file) ? QFile::remove(file) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED : (int)KIO::ERR_DOES_NOT_EXIST; if(FontInst::STATUS_OK==result) theFontFolder.addModifiedDir(dir); return result; } int Helper::reconfigure() { KFI_DBUG; saveDisabled(); KFI_DBUG << theFontFolder.isModified(); if(theFontFolder.isModified()) theFontFolder.configure(); return FontInst::STATUS_OK; } int Helper::saveDisabled() { KFI_DBUG; // Load internally calls save! theFontFolder.loadDisabled(); return FontInst::STATUS_OK; } int Helper::checkWriteAction(const QStringList &files) { QStringList::ConstIterator it(files.constBegin()), end(files.constEnd()); for(; it!=end; ++it) if(!Misc::dWritable(Misc::getDir(*it))) return KIO::ERR_WRITE_ACCESS_DENIED; return FontInst::STATUS_OK; } } diff --git a/kcms/kfontinst/dbus/Utils.cpp b/kcms/kfontinst/dbus/Utils.cpp index c8e9add48..634def77d 100644 --- a/kcms/kfontinst/dbus/Utils.cpp +++ b/kcms/kfontinst/dbus/Utils.cpp @@ -1,249 +1,249 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2009 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 #include #include #include #include #include "Utils.h" #include "FontInst.h" #include "Misc.h" #include "Fc.h" #include "WritingSystems.h" namespace KFI { namespace Utils { bool isAAfm(const QString &fname) { if(Misc::checkExt(QFile::encodeName(fname), "afm")) // CPD? Is this a necessary check? { QFile file(fname); if(file.open(QIODevice::ReadOnly)) { QTextStream stream(&file); QString line; for(int lc=0; lc<30 && !stream.atEnd(); ++lc) { line=stream.readLine(); if(line.contains("StartFontMetrics")) { file.close(); return true; } } file.close(); } } return false; } bool isAPfm(const QString &fname) { bool ok=false; // I know extension checking is bad, but Ghostscript's pf2afm requires the pfm file to // have the .pfm extension... QByteArray name(QFile::encodeName(fname)); if(Misc::checkExt(name, "pfm")) { // // OK, the extension matches, so perform a little contents checking... FILE *f=fopen(name.constData(), "r"); if(f) { static const unsigned long constCopyrightLen = 60; static const unsigned long constTypeToExt = 49; static const unsigned long constExtToFname = 20; static const unsigned long constExtLen = 30; static const unsigned long constFontnameMin = 75; static const unsigned long constFontnameMax = 512; unsigned short version=0, type=0, extlen=0; unsigned long length=0, fontname=0, fLength=0; fseek(f, 0, SEEK_END); fLength=ftell(f); fseek(f, 0, SEEK_SET); if(2==fread(&version, 1, 2, f) && // Read version 4==fread(&length, 1, 4, f) && // length... length==fLength && 0==fseek(f, constCopyrightLen, SEEK_CUR) && // Skip copyright notice... 2==fread(&type, 1, 2, f) && 0==fseek(f, constTypeToExt, SEEK_CUR) && 2==fread(&extlen, 1, 2, f) && extlen==constExtLen && 0==fseek(f, constExtToFname, SEEK_CUR) && 4==fread(&fontname, 1, 4, f) && fontname>constFontnameMin && fontname(0x80); FILE *f=fopen(name.constData(), "r"); if(f) { if(constPfbLen==fread(buffer, 1, constPfbLen, f)) match=buffer[0]==constPfbMarker && 0==memcmp(&buffer[constPfbOffset], constStr, constStrLen); fclose(f); } } return match; } static QString getMatch(const QString &file, const char *extension) { QString f(Misc::changeExt(file, extension)); return Misc::fExists(f) ? f : QString(); } void createAfm(const QString &file, EFileType type) { bool pfm=FILE_PFM==type, type1=FILE_SCALABLE==type && isAType1(file); if(type1 || pfm) { // pf2afm wants files with lowercase extension, so just check for lowercase! // -- when a font is installed, the extension is converted to lowercase anyway... QString afm=getMatch(file, "afm"); if(afm.isEmpty()) // No point creating if AFM already exists! { QString pfm, t1; if(type1) // Its a Type1, so look for existing PFM { pfm=getMatch(file, "pfm"); t1=file; } else // Its a PFM, so look for existing Type1 { t1=getMatch(file, "pfa"); if(t1.isEmpty()) t1=getMatch(file, "pfb"); pfm=file; } if(!t1.isEmpty() && !pfm.isEmpty()) // Do we have both Type1 and PFM? { QString rootName(t1.left(t1.length()-4)); Misc::doCmd("pf2afm", KShell::quoteArg(rootName)); // pf2afm wants name without extension... Misc::setFilePerms(QFile::encodeName(rootName+".afm")); } } } } EFileType check(const QString &file, Family &fam) { if(isAAfm(file)) return FILE_AFM; else if(isAPfm(file)) return FILE_PFM; else { // Check that file is a font via FreeType... int count=0; - FcPattern *pat=FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(file).constData()), 0, NULL, + FcPattern *pat=FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(file).constData()), 0, nullptr, &count); if(pat) { FcBool scalable; QString family, foundry; quint32 style; int index; qulonglong ws; EFileType type=(FcResultMatch!=FcPatternGetBool(pat, FC_SCALABLE, 0, &scalable) || !scalable) ? FILE_BITMAP : FILE_SCALABLE; FC::getDetails(pat, family, style, index, foundry); ws=WritingSystems::instance()->get(pat); FcPatternDestroy(pat); Style st(style, scalable, ws); st.add(File(file, foundry, index)); fam=Family(family); fam.add(st); return type; } } return FILE_INVALID; } } } diff --git a/kcms/kfontinst/kcmfontinst/ActionLabel.cpp b/kcms/kfontinst/kcmfontinst/ActionLabel.cpp index 5dfb8a09c..37d5c29aa 100644 --- a/kcms/kfontinst/kcmfontinst/ActionLabel.cpp +++ b/kcms/kfontinst/kcmfontinst/ActionLabel.cpp @@ -1,112 +1,112 @@ /* * 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 "ActionLabel.h" #include #include #include #include #include namespace KFI { // Borrowed from kolourpaint... static QMatrix matrixWithZeroOrigin(const QMatrix &matrix, int width, int height) { QRect newRect(matrix.mapRect(QRect(0, 0, width, height))); return QMatrix(matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(), matrix.dx() - newRect.left(), matrix.dy() - newRect.top()); } static QMatrix rotateMatrix(int width, int height, double angle) { QMatrix matrix; matrix.translate(width/2, height/2); matrix.rotate(angle); return matrixWithZeroOrigin(matrix, width, height); } static const int constNumIcons=8; static int theUsageCount; static QPixmap *theIcons[constNumIcons]; CActionLabel::CActionLabel(QWidget *parent) : QLabel(parent) { static const int constIconSize(48); setMinimumSize(constIconSize, constIconSize); setMaximumSize(constIconSize, constIconSize); setAlignment(Qt::AlignCenter); if(0==theUsageCount++) { QImage img(KIconLoader::global()->loadIcon("application-x-font-ttf", KIconLoader::NoGroup, 32).toImage()); double increment=360.0/constNumIcons; for(int i=0; istart(1000/constNumIcons); } void CActionLabel::stopAnimation() { itsTimer->stop(); itsCount=0; setPixmap(*theIcons[itsCount]); } void CActionLabel::rotateIcon() { if(++itsCount==constNumIcons) itsCount=0; setPixmap(*theIcons[itsCount]); } } diff --git a/kcms/kfontinst/kcmfontinst/FcQuery.h b/kcms/kfontinst/kcmfontinst/FcQuery.h index 0253a0bce..5b87921b4 100644 --- a/kcms/kfontinst/kcmfontinst/FcQuery.h +++ b/kcms/kfontinst/kcmfontinst/FcQuery.h @@ -1,70 +1,70 @@ #ifndef __FC_QUERY_H__ #define __FC_QUERY_H__ /* * 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 #include #include "Misc.h" class QProcess; namespace KFI { class CFcQuery : public QObject { Q_OBJECT public: - CFcQuery(QObject *parent) : QObject(parent), itsProc(NULL) { } + CFcQuery(QObject *parent) : QObject(parent), itsProc(nullptr) { } ~CFcQuery() override; void run(const QString &query); const QString & font() const { return itsFont; } const QString & file() const { return itsFile; } private Q_SLOTS: void procExited(); void data(); Q_SIGNALS: void finished(); private: QProcess *itsProc; QByteArray itsBuffer; QString itsFile, itsFont; }; } #endif diff --git a/kcms/kfontinst/kcmfontinst/FontFilter.cpp b/kcms/kfontinst/kcmfontinst/FontFilter.cpp index f9259bc39..72b6e460f 100644 --- a/kcms/kfontinst/kcmfontinst/FontFilter.cpp +++ b/kcms/kfontinst/kcmfontinst/FontFilter.cpp @@ -1,395 +1,395 @@ /* * 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 "FontFilter.h" #include "FontFilterProxyStyle.h" #include "FontList.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KFI { static const int constArrowPad(5); static void deselectCurrent(QActionGroup *act) { QAction *prev(act->checkedAction()); if(prev) prev->setChecked(false); } static void deselectCurrent(KSelectAction *act) { deselectCurrent(act->selectableActionGroup()); } // FIXME: Go back to using StyleSheets instead of a proxy style // once Qt has been fixed not to mess with widget font when // using StyleSheets class CFontFilterStyle : public CFontFilterProxyStyle { public: CFontFilterStyle(CFontFilter *parent, int ol) : CFontFilterProxyStyle(parent), overlap(ol) {} QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const override; int overlap; }; QRect CFontFilterStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const { if (SE_LineEditContents==element) { QRect rect(style()->subElementRect(SE_LineEditContents, option, widget)); return rect.adjusted(overlap, 0, -overlap, 0); } return CFontFilterProxyStyle::subElementRect(element, option, widget); } struct SortAction { SortAction(QAction *a) : action(a) { } bool operator<(const SortAction &o) const { return action->text().localeAwareCompare(o.action->text())<0; } QAction *action; }; static void sortActions(KSelectAction *group) { if(group->actions().count()>1) { QList actions=group->actions(); QList::ConstIterator it(actions.constBegin()), end(actions.constEnd()); QList sorted; for(; it!=end; ++it) { sorted.append(SortAction(*it)); group->removeAction(*it); } qSort(sorted); QList::ConstIterator s(sorted.constBegin()), sEnd(sorted.constEnd()); for(; s!=sEnd; ++s) group->addAction((*s).action); } } CFontFilter::CFontFilter(QWidget *parent) : KLineEdit(parent) { setClearButtonShown(true); setTrapReturnKey(true); itsMenuButton = new QLabel(this); itsMenuButton->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); itsMenuButton->setCursor(Qt::ArrowCursor); itsMenuButton->setToolTip(i18n("Set Criteria")); itsMenu=new QMenu(this); itsPixmaps[CRIT_FAMILY]=SmallIcon("draw-text"); itsPixmaps[CRIT_STYLE]=SmallIcon("format-text-bold"); itsPixmaps[CRIT_FOUNDRY]=SmallIcon("user-identity"); itsPixmaps[CRIT_FONTCONFIG]=SmallIcon("system-search"); itsPixmaps[CRIT_FILETYPE]=SmallIcon("preferences-desktop-font-installer"); itsPixmaps[CRIT_FILENAME]=SmallIcon("application-x-font-type1"); itsPixmaps[CRIT_LOCATION]=SmallIcon("folder"); itsPixmaps[CRIT_WS]=SmallIcon("character-set"); itsActionGroup=new QActionGroup(this); addAction(CRIT_FAMILY, i18n("Family"), true); addAction(CRIT_STYLE, i18n("Style"), false); KSelectAction *foundryMenu=new KSelectAction(QIcon(itsPixmaps[CRIT_FOUNDRY]), i18n("Foundry"), this); itsActions[CRIT_FOUNDRY]=foundryMenu; itsMenu->addAction(itsActions[CRIT_FOUNDRY]); foundryMenu->setData((int)CRIT_FOUNDRY); foundryMenu->setVisible(false); connect(foundryMenu, SIGNAL(triggered(QString)), SLOT(foundryChanged(QString))); addAction(CRIT_FONTCONFIG, i18n("FontConfig Match"), false); KSelectAction *ftMenu=new KSelectAction(QIcon(itsPixmaps[CRIT_FILETYPE]), i18n("File Type"), this); itsActions[CRIT_FILETYPE]=ftMenu; itsMenu->addAction(itsActions[CRIT_FILETYPE]); ftMenu->setData((int)CRIT_FILETYPE); QStringList::ConstIterator it(CFontList::fontMimeTypes.constBegin()), end(CFontList::fontMimeTypes.constEnd()); QMimeDatabase db; for(; it!=end; ++it) if((*it)!="application/vnd.kde.fontspackage") { QMimeType mime = db.mimeTypeForName(*it); KToggleAction *act=new KToggleAction(QIcon::fromTheme(mime.iconName()), mime.comment(), this); ftMenu->addAction(act); act->setChecked(false); QStringList mimes; foreach (QString pattern, mime.globPatterns()) mimes.append(pattern.remove(QStringLiteral("*."))); act->setData(mimes); } sortActions(ftMenu); connect(ftMenu, SIGNAL(triggered(QString)), SLOT(ftChanged(QString))); itsCurrentFileTypes.clear(); addAction(CRIT_FILENAME, i18n("File Name"), false); addAction(CRIT_LOCATION, i18n("File Location"), false); KSelectAction *wsMenu=new KSelectAction(QIcon(itsPixmaps[CRIT_WS]), i18n("Writing System"), this); itsActions[CRIT_WS]=wsMenu; itsMenu->addAction(itsActions[CRIT_WS]); wsMenu->setData((int)CRIT_WS); itsCurrentWs=QFontDatabase::Any; for(int i=QFontDatabase::Latin; iaddAction(wsAct); wsAct->setChecked(false); wsAct->setData(i); } sortActions(wsMenu); connect(wsMenu, SIGNAL(triggered(QString)), SLOT(wsChanged(QString))); setCriteria(CRIT_FAMILY); setStyle(new CFontFilterStyle(this, itsMenuButton->width())); } void CFontFilter::setFoundries(const QSet ¤tFoundries) { QAction *act(((KSelectAction *)itsActions[CRIT_FOUNDRY])->currentAction()); QString prev(act && act->isChecked() ? act->text() : QString()); bool changed(false); QList prevFoundries(((KSelectAction *)itsActions[CRIT_FOUNDRY])->actions()); QList::ConstIterator fIt(prevFoundries.constBegin()), fEnd(prevFoundries.constEnd()); QSet foundries(currentFoundries); // Determine which of 'foundries' are new ones, and which old ones need to be removed... for(; fIt!=fEnd; ++fIt) { if(foundries.contains((*fIt)->text())) foundries.remove((*fIt)->text()); else { ((KSelectAction *)itsActions[CRIT_FOUNDRY])->removeAction(*fIt); (*fIt)->deleteLater(); changed=true; } } if(foundries.count()) { // Add foundries to menu - replacing '&' with '&&', as '&' is taken to be // a shortcut! QSet::ConstIterator it(foundries.begin()), end(foundries.end()); for(; it!=end; ++it) { QString foundry(*it); foundry.replace("&", "&&"); ((KSelectAction *)itsActions[CRIT_FOUNDRY])->addAction(foundry); } changed=true; } if(changed) { sortActions((KSelectAction *)itsActions[CRIT_FOUNDRY]); if(!prev.isEmpty()) { act=((KSelectAction *)itsActions[CRIT_FOUNDRY])->action(prev); if(act) ((KSelectAction *)itsActions[CRIT_FOUNDRY])->setCurrentAction(act); else ((KSelectAction *)itsActions[CRIT_FOUNDRY])->setCurrentItem(0); } itsActions[CRIT_FOUNDRY]->setVisible(((KSelectAction *)itsActions[CRIT_FOUNDRY])->actions().count()); } } QSize CFontFilter::sizeHint() const { return QSize(fontMetrics().width(placeholderText())+56, KLineEdit::sizeHint().height()); } void CFontFilter::filterChanged() { QAction *act(itsActionGroup->checkedAction()); if(act) { ECriteria crit((ECriteria)act->data().toInt()); if(itsCurrentCriteria!=crit) { deselectCurrent((KSelectAction *)itsActions[CRIT_FOUNDRY]); deselectCurrent((KSelectAction *)itsActions[CRIT_FILETYPE]); deselectCurrent((KSelectAction *)itsActions[CRIT_WS]); setText(QString()); itsCurrentWs=QFontDatabase::Any; itsCurrentFileTypes.clear(); setCriteria(crit); setPlaceholderText(i18n("Type here to filter on %1", act->text().toLower())); setReadOnly(false); } } } void CFontFilter::ftChanged(const QString &ft) { deselectCurrent((KSelectAction *)itsActions[CRIT_FOUNDRY]); deselectCurrent((KSelectAction *)itsActions[CRIT_WS]); deselectCurrent(itsActionGroup); QAction *act(((KSelectAction *)itsActions[CRIT_FILETYPE])->currentAction()); if(act) itsCurrentFileTypes=act->data().toStringList(); itsCurrentCriteria=CRIT_FILETYPE; setReadOnly(true); setCriteria(itsCurrentCriteria); setText(ft); setPlaceholderText(text()); } void CFontFilter::wsChanged(const QString &writingSystemName) { deselectCurrent((KSelectAction *)itsActions[CRIT_FOUNDRY]); deselectCurrent((KSelectAction *)itsActions[CRIT_FILETYPE]); deselectCurrent(itsActionGroup); QAction *act(((KSelectAction *)itsActions[CRIT_WS])->currentAction()); if(act) itsCurrentWs=(QFontDatabase::WritingSystem)act->data().toInt(); itsCurrentCriteria=CRIT_WS; setReadOnly(true); setCriteria(itsCurrentCriteria); setText(writingSystemName); setPlaceholderText(text()); } void CFontFilter::foundryChanged(const QString &foundry) { deselectCurrent((KSelectAction *)itsActions[CRIT_WS]); deselectCurrent((KSelectAction *)itsActions[CRIT_FILETYPE]); deselectCurrent(itsActionGroup); itsCurrentCriteria=CRIT_FOUNDRY; setReadOnly(true); setText(foundry); setPlaceholderText(text()); setCriteria(itsCurrentCriteria); } void CFontFilter::addAction(ECriteria crit, const QString &text, bool on) { itsActions[crit]=new KToggleAction(QIcon(itsPixmaps[crit]), text, this); itsMenu->addAction(itsActions[crit]); itsActionGroup->addAction(itsActions[crit]); itsActions[crit]->setData((int)crit); itsActions[crit]->setChecked(on); if(on) setPlaceholderText(i18n("Type here to filter on %1", text.toLower())); connect(itsActions[crit], SIGNAL(toggled(bool)), SLOT(filterChanged())); } void CFontFilter::resizeEvent(QResizeEvent *ev) { KLineEdit::resizeEvent(ev); int frameWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth)), y((height()-itsMenuButton->height())/2); if (qApp->isLeftToRight()) itsMenuButton->move(frameWidth + 2, y); else itsMenuButton->move(size().width() - frameWidth - itsMenuButton->width() - 2, y); } void CFontFilter::mousePressEvent(QMouseEvent *ev) { if(Qt::LeftButton==ev->button() && itsMenuButton->underMouse()) - itsMenu->popup(mapToGlobal(QPoint(0, height())), 0); + itsMenu->popup(mapToGlobal(QPoint(0, height())), nullptr); else KLineEdit::mousePressEvent(ev); } void CFontFilter::setCriteria(ECriteria crit) { QPixmap arrowmap(itsPixmaps[crit].width()+constArrowPad, itsPixmaps[crit].height()); QColor bgnd(palette().color(QPalette::Active, QPalette::Base)); bgnd.setAlphaF(0.0); arrowmap.fill(bgnd); QPainter p(&arrowmap); p.drawPixmap(0, 0, itsPixmaps[crit]); QStyleOption opt; opt.state = QStyle::State_Enabled; opt.rect = QRect(arrowmap.width()-(constArrowPad+1), arrowmap.height()-(constArrowPad+1), constArrowPad, constArrowPad); style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &opt, &p, itsMenuButton); p.end(); itsMenuButton->setPixmap(arrowmap); itsMenuButton->resize(arrowmap.width(), arrowmap.height()); itsCurrentCriteria=crit; emit criteriaChanged(crit, ((qulonglong)1) << (int)itsCurrentWs, itsCurrentFileTypes); } } diff --git a/kcms/kfontinst/kcmfontinst/FontFilterProxyStyle.h b/kcms/kfontinst/kcmfontinst/FontFilterProxyStyle.h index 426909b27..7bdede487 100644 --- a/kcms/kfontinst/kcmfontinst/FontFilterProxyStyle.h +++ b/kcms/kfontinst/kcmfontinst/FontFilterProxyStyle.h @@ -1,71 +1,71 @@ /* This file is part of the KDE project Copyright (C) 2007 Fredrik Höglund This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef CFONTFILTERPROXYSTYLE_H #define CFONTFILTERPROXYSTYLE_H #include namespace KFI { class CFontFilterProxyStyle : public QStyle { public: CFontFilterProxyStyle(QWidget *parent); QStyle *style() const; void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const override; void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override; void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const override; void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const override; void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override; QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const override; SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const override; QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const override; QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const override; int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const override; void polish(QWidget *widget) override; void polish(QApplication *application) override; void polish(QPalette &palette) override; QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const override; QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const override; QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option, const QWidget *widget) const override; QPalette standardPalette() const override; int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const override; QRect subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const override; QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const override; void unpolish(QWidget *widget) override; void unpolish(QApplication *application) override; int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, - Qt::Orientation orientation, const QStyleOption* option = 0, const QWidget* widget = 0) const override; + Qt::Orientation orientation, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override; protected: QWidget *parent; }; } #endif diff --git a/kcms/kfontinst/kcmfontinst/FontInstInterface.h b/kcms/kfontinst/kcmfontinst/FontInstInterface.h index dcecdd9a4..742603b50 100644 --- a/kcms/kfontinst/kcmfontinst/FontInstInterface.h +++ b/kcms/kfontinst/kcmfontinst/FontInstInterface.h @@ -1,23 +1,23 @@ #ifndef __FONTINST_INTERFACE_H__ #define __FONTINST_INTERFACE_H__ #include "FontinstIface.h" #include "FontInst.h" namespace KFI { class FontInstInterface : public OrgKdeFontinstInterface { public: FontInstInterface() : OrgKdeFontinstInterface(OrgKdeFontinstInterface::staticInterfaceName(), - FONTINST_PATH, QDBusConnection::sessionBus(), 0L) + FONTINST_PATH, QDBusConnection::sessionBus(), nullptr) { } }; } #endif diff --git a/kcms/kfontinst/kcmfontinst/FontList.cpp b/kcms/kfontinst/kcmfontinst/FontList.cpp index 4ab29f5c9..1d3747dce 100644 --- a/kcms/kfontinst/kcmfontinst/FontList.cpp +++ b/kcms/kfontinst/kcmfontinst/FontList.cpp @@ -1,2060 +1,2060 @@ /* * 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 "FontList.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FcEngine.h" #include "Fc.h" #include "KfiConstants.h" #include "GroupList.h" #include "FontInstInterface.h" #include "XmlStrings.h" #include "Family.h" #include "Style.h" #include "File.h" namespace KFI { const QStringList CFontList::fontMimeTypes(QStringList() << "font/ttf" << "font/otf" << "application/x-font-ttf" << "application/x-font-otf" << "application/x-font-type1" << "application/x-font-pcf" << "application/x-font-bdf" << "application/vnd.kde.fontspackage"); static const int constMaxSlowed = 250; static void decompose(const QString &name, QString &family, QString &style) { int commaPos=name.lastIndexOf(','); family=-1==commaPos ? name : name.left(commaPos); style=-1==commaPos ? KFI_WEIGHT_REGULAR : name.mid(commaPos+2); } static void addFont(CFontItem *font, CJobRunner::ItemList &urls, QStringList &fontNames, QSet *fonts, QSet &usedFonts, bool getEnabled, bool getDisabled) { if(!usedFonts.contains(font) && ( (getEnabled && font->isEnabled()) || (getDisabled && !font->isEnabled()) ) ) { urls.append(CJobRunner::Item(font->url(), font->name(), !font->isEnabled())); fontNames.append(font->name()); usedFonts.insert(font); if(fonts) fonts->insert(Misc::TFont(font->family(), font->styleInfo())); } } static QString replaceEnvVar(const QString &text) { QString mod(text); int endPos(text.indexOf('/')); if(endPos==-1) endPos=text.length()-1; else endPos--; if(endPos>0) { QString envVar(text.mid(1, endPos)); const char *val=getenv(envVar.toLatin1().constData()); if(val) mod=Misc::fileSyntax(QFile::decodeName(val)+mod.mid(endPos+1)); } return mod; } // // Convert from list such as: // // Arial // Arial, Bold // Courier // Times // Times, Italic // // To: // // Arial (Regular, Bold) // Coutier // Times (Regular, Italic) QStringList CFontList::compact(const QStringList &fonts) { QString lastFamily, entry; QStringList::ConstIterator it(fonts.begin()), end(fonts.end()); QStringList compacted; QSet usedStyles; for(; it!=end; ++it) { QString family, style; decompose(*it, family, style); if(family!=lastFamily) { usedStyles.clear(); if(entry.length()) { entry+=')'; compacted.append(entry); } entry=QString(family+" ("); lastFamily=family; } if(!usedStyles.contains(style)) { usedStyles.clear(); if(entry.length() && '('!=entry[entry.length()-1]) entry+=", "; entry+=style; usedStyles.insert(style); } } if(entry.length()) { entry+=')'; compacted.append(entry); } return compacted; } QString capitaliseFoundry(const QString &foundry) { QString f(foundry.toLower()); if(f==QLatin1String("ibm")) return QLatin1String("IBM"); else if(f==QLatin1String("urw")) return QLatin1String("URW"); else if(f==QLatin1String("itc")) return QLatin1String("ITC"); else if(f==QLatin1String("nec")) return QLatin1String("NEC"); else if(f==QLatin1String("b&h")) return QLatin1String("B&H"); else if(f==QLatin1String("dec")) return QLatin1String("DEC"); else { QChar *ch(f.data()); int len(f.length()); bool isSpace(true); while(len--) { if (isSpace) *ch=ch->toUpper(); isSpace=ch->isSpace(); ++ch; } } return f; } inline bool isSysFolder(const QString §) { return i18n(KFI_KIO_FONTS_SYS)==sect || KFI_KIO_FONTS_SYS==sect; } CFontItem::CFontItem(CFontModelItem *p, const Style &s, bool sys) : CFontModelItem(p), itsStyleName(FC::createStyleName(s.value())), itsStyle(s) { refresh(); if(!Misc::root()) setIsSystem(sys); } void CFontItem::refresh() { FileCont::ConstIterator it(itsStyle.files().begin()), end(itsStyle.files().end()); itsEnabled=false; for(; it!=end; ++it) if(!Misc::isHidden(Misc::getFile((*it).path()))) { itsEnabled=true; break; } } CFamilyItem::CFamilyItem(CFontList &p, const Family &f, bool sys) - : CFontModelItem(NULL), + : CFontModelItem(nullptr), itsStatus(ENABLED), itsRealStatus(ENABLED), - itsRegularFont(NULL), + itsRegularFont(nullptr), itsParent(p) { itsName=f.name(); addFonts(f.styles(), sys); //updateStatus(); } CFamilyItem::~CFamilyItem() { qDeleteAll(itsFonts); itsFonts.clear(); } bool CFamilyItem::addFonts(const StyleCont &styles, bool sys) { StyleCont::ConstIterator it(styles.begin()), end(styles.end()); bool modified=false; for(; it!=end; ++it) { CFontItem *font=findFont((*it).value(), sys); if(!font) { // New font style! itsFonts.append(new CFontItem(this, *it, sys)); modified=true; } else { int before=(*it).files().size(); font->addFiles((*it).files()); if((*it).files().size()!=before) { modified=true; font->refresh(); } } } return modified; } CFontItem * CFamilyItem::findFont(quint32 style, bool sys) { CFontItemCont::ConstIterator fIt(itsFonts.begin()), fEnd(itsFonts.end()); for(; fIt!=fEnd; ++fIt) if((*(*fIt)).styleInfo()==style && (*(*fIt)).isSystem()==sys) return (*fIt); - return NULL; + return nullptr; } void CFamilyItem::getFoundries(QSet &foundries) const { CFontItemCont::ConstIterator it(itsFonts.begin()), end(itsFonts.end()); for(; it!=end; ++it) { FileCont::ConstIterator fIt((*it)->files().begin()), fEnd((*it)->files().end()); for(; fIt!=fEnd; ++fIt) if(!(*fIt).foundry().isEmpty()) foundries.insert(capitaliseFoundry((*fIt).foundry())); } } bool CFamilyItem::usable(const CFontItem *font, bool root) { return ( root || (font->isSystem() && itsParent.allowSys()) || (!font->isSystem() && itsParent.allowUser())); } void CFamilyItem::addFont(CFontItem *font, bool update) { itsFonts.append(font); if(update) { updateStatus(); updateRegularFont(font); } } void CFamilyItem::removeFont(CFontItem *font, bool update) { itsFonts.removeAll(font); if(update) updateStatus(); if(itsRegularFont==font) { - itsRegularFont=NULL; + itsRegularFont=nullptr; if(update) - updateRegularFont(NULL); + updateRegularFont(nullptr); } delete font; } void CFamilyItem::refresh() { updateStatus(); - itsRegularFont=NULL; - updateRegularFont(NULL); + itsRegularFont=nullptr; + updateRegularFont(nullptr); } bool CFamilyItem::updateStatus() { bool root(Misc::root()); EStatus oldStatus(itsStatus); CFontItemCont::ConstIterator it(itsFonts.begin()), end(itsFonts.end()); int en(0), dis(0), allEn(0), allDis(0); bool oldSys(isSystem()), sys(false); itsFontCount=0; for(; it!=end; ++it) if(usable(*it, root)) { if((*it)->isEnabled()) en++; else dis++; if(!sys) sys=(*it)->isSystem(); itsFontCount++; } else if((*it)->isEnabled()) allEn++; else allDis++; allEn+=en; allDis+=dis; itsStatus=en && dis ? PARTIAL : en ? ENABLED : DISABLED; itsRealStatus=allEn && allDis ? PARTIAL : allEn ? ENABLED : DISABLED; if(!root) setIsSystem(sys); return itsStatus!=oldStatus || isSystem()!=oldSys; } bool CFamilyItem::updateRegularFont(CFontItem *font) { static const quint32 constRegular=FC::createStyleVal(FC_WEIGHT_REGULAR, KFI_FC_WIDTH_NORMAL, FC_SLANT_ROMAN); CFontItem *oldFont(itsRegularFont); bool root(Misc::root()); if(font && usable(font, root)) { if(itsRegularFont) { int regDiff=abs((long)(itsRegularFont->styleInfo()-constRegular)), fontDiff=abs((long)(font->styleInfo()-constRegular)); if(fontDiffstyleInfo()-constRegular)); if(diff)), SLOT(fontList(int,QList))); } CFontList::~CFontList() { qDeleteAll(itsFamilies); itsFamilies.clear(); itsFamilyHash.clear(); } void CFontList::dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to) { Q_UNUSED(from); Q_UNUSED(to); if(name==QLatin1String(OrgKdeFontinstInterface::staticInterfaceName())) load(); } void CFontList::fontList(int pid, const QList &families) { // printf("**** fontList:%d/%d %d\n", pid, getpid(), families.count()); if(pid==getpid()) { QList::ConstIterator it(families.begin()), end(families.end()); int count(families.size()); for(int i=0; it!=end; ++it, ++i) { fontsAdded(*it); emit listingPercent(i*100/count); } emit listingPercent(100); } } void CFontList::unsetSlowUpdates() { setSlowUpdates(false); } void CFontList::load() { for(int t=0; tlist(FontInst::SYS_MASK|FontInst::USR_MASK, getpid()); } void CFontList::setSlowUpdates(bool slow) { if(itsSlowUpdates!=slow) { if(!slow) for(int i=0; i families; QDataStream ds(&encodedData, QIODevice::WriteOnly); for(; it!=end; ++it) if((*it).isValid()) { if((static_cast((*it).internalPointer()))->isFont()) { CFontItem *font=static_cast((*it).internalPointer()); families.insert(font->family()); } else { CFamilyItem *fam=static_cast((*it).internalPointer()); families.insert(fam->name()); } } ds << families; mimeData->setData(KFI_FONT_DRAG_MIME, encodedData); return mimeData; } QStringList CFontList::mimeTypes() const { QStringList types; types << "text/uri-list"; return types; } QVariant CFontList::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) switch(role) { case Qt::DisplayRole: switch(section) { case COL_FONT: return i18n("Font"); case COL_STATUS: return i18n("Status"); default: break; } break; // case Qt::DecorationRole: // if(COL_STATUS==section) // return SmallIcon("fontstatus"); // break; case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case Qt::ToolTipRole: if(COL_STATUS==section) return i18n("This column shows the status of the font family, and of the " "individual font styles."); break; case Qt::WhatsThisRole: return whatsThis(); default: break; } return QVariant(); } QModelIndex CFontList::index(int row, int column, const QModelIndex &parent) const { if(parent.isValid()) // Then font... { CFamilyItem *fam=static_cast(parent.internalPointer()); if(rowfonts().count()) return createIndex(row, column, fam->fonts().at(row)); } else // Family.... if(row(index.internalPointer()); if(mi->isFamily()) return QModelIndex(); else { CFontItem *font=static_cast(index.internalPointer()); return createIndex(itsFamilies.indexOf(((CFamilyItem *)font->parent())), 0, font->parent()); } } int CFontList::rowCount(const QModelIndex &parent) const { if(parent.isValid()) { CFontModelItem *mi=static_cast(parent.internalPointer()); if(mi->isFont()) return 0; CFamilyItem *fam=static_cast(parent.internalPointer()); return fam->fonts().count(); } else return itsFamilies.count(); } void CFontList::refresh(bool allowSys, bool allowUser) { itsAllowSys=allowSys; itsAllowUser=allowUser; CFamilyItemCont::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end()); for(; it!=end; ++it) (*it)->refresh(); } void CFontList::getFamilyStats(QSet &enabled, QSet &disabled, QSet &partial) { CFamilyItemCont::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end()); for(; it!=end; ++it) { switch((*it)->realStatus()) { case CFamilyItem::ENABLED: enabled.insert((*it)->name()); break; case CFamilyItem::PARTIAL: partial.insert((*it)->name()); break; case CFamilyItem::DISABLED: disabled.insert((*it)->name()); break; } } } void CFontList::getFoundries(QSet &foundries) const { CFamilyItemCont::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end()); for(; it!=end; ++it) (*it)->getFoundries(foundries); } QString CFontList::whatsThis() const { return i18n("

This list shows your installed fonts. The fonts are grouped by family, and the" " number in square brackets represents the number of styles in which the family is" " available. e.g.

" "
    " "
  • Times [4]" "
    • Regular
    • " "
    • Bold
    • " "
    • Bold Italic
    • " "
    • Italic
    • " "
    " "
  • " "
"); } void CFontList::fontsAdded(const KFI::Families &families) { // printf("**** FONT ADDED:%d\n", families.items.count()); if(itsSlowUpdates) storeSlowedMessage(families, MSG_ADD); else addFonts(families.items, families.isSystem && !Misc::root()); } void CFontList::fontsRemoved(const KFI::Families &families) { // printf("**** FONT REMOVED:%d\n", families.items.count()); if(itsSlowUpdates) storeSlowedMessage(families, MSG_DEL); else removeFonts(families.items, families.isSystem && !Misc::root()); } void CFontList::storeSlowedMessage(const Families &families, EMsgType type) { int folder=families.isSystem ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER; bool playOld=false; for(int i=0; iconstMaxSlowed) playOld=true; if(playOld) actionSlowedUpdates(families.isSystem); FamilyCont::ConstIterator family(families.items.begin()), fend(families.items.end()); for(; family!=fend; ++family) { FamilyCont::ConstIterator f=itsSlowedMsgs[type][folder].find(*family); if(f!=itsSlowedMsgs[type][folder].end()) { StyleCont::ConstIterator style((*family).styles().begin()), send((*family).styles().end()); for(; style!=send; ++style) { StyleCont::ConstIterator st=(*f).styles().find(*style); if(st==(*f).styles().end()) (*f).add(*style); else (*st).addFiles((*style).files()); } } else itsSlowedMsgs[type][folder].insert(*family); } } void CFontList::actionSlowedUpdates(bool sys) { int folder=sys ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER; for(int i=0; i modifiedFamilies; for(; family!=end; ++family) { if((*family).styles().count()>0) { CFamilyItem *famItem=findFamily((*family).name()); if(famItem) { int rowFrom=famItem->fonts().count(); if(famItem->addFonts((*family).styles(), sys)) { int rowTo=famItem->fonts().count(); if(rowTo!=rowFrom) { beginInsertRows(createIndex(famItem->rowNumber(), 0, famItem), rowFrom, rowTo); endInsertRows(); } modifiedFamilies.insert(famItem); } } else { famItem=new CFamilyItem(*this, *family, sys); itsFamilies.append(famItem); itsFamilyHash[famItem->name()]=famItem; modifiedFamilies.insert(famItem); } } } int famRowTo=itsFamilies.count(); if(famRowTo!=famRowFrom) { beginInsertRows(QModelIndex(), famRowFrom, famRowTo); endInsertRows(); } if(!modifiedFamilies.isEmpty()) { QSet::Iterator it(modifiedFamilies.begin()), end(modifiedFamilies.end()); for(; it!=end; ++it) (*it)->refresh(); } // if(emitLayout) // emit layoutChanged(); } void CFontList::removeFonts(const FamilyCont &families, bool sys) { // if(!itsSlowUpdates) // emit layoutAboutToBeChanged(); FamilyCont::ConstIterator family(families.begin()), end(families.end()); QSet modifiedFamilies; for(; family!=end; ++family) { if((*family).styles().count()>0) { CFamilyItem *famItem=findFamily((*family).name()); if(famItem) { StyleCont::ConstIterator it((*family).styles().begin()), end((*family).styles().end()); for(; it!=end; ++it) { CFontItem *fontItem=famItem->findFont((*it).value(), sys); if(fontItem) { int before=fontItem->files().count(); fontItem->removeFiles((*it).files()); if(fontItem->files().count()!=before) { if(fontItem->files().isEmpty()) { int row=-1; if(1!=famItem->fonts().count()) { row=fontItem->rowNumber(); beginRemoveRows(createIndex(famItem->rowNumber(), 0, famItem), row, row); } famItem->removeFont(fontItem, false); if(-1!=row) endRemoveRows(); } else fontItem->refresh(); } } } if(famItem->fonts().isEmpty()) { int row=famItem->rowNumber(); beginRemoveRows(QModelIndex(), row, row); itsFamilyHash.remove(famItem->name()); itsFamilies.removeAt(row); endRemoveRows(); } else modifiedFamilies.insert(famItem); } } } if(!modifiedFamilies.isEmpty()) { QSet::Iterator it(modifiedFamilies.begin()), end(modifiedFamilies.end()); for(; it!=end; ++it) (*it)->refresh(); } // if(!itsSlowUpdates) // emit layoutChanged(); } CFamilyItem * CFontList::findFamily(const QString &familyName) { CFamilyItemHash::Iterator it=itsFamilyHash.find(familyName); return it==itsFamilyHash.end() ? 0L : *it; } inline bool matchString(const QString &str, const QString &pattern) { return pattern.isEmpty() || -1!=str.indexOf(pattern, 0, Qt::CaseInsensitive); } CFontListSortFilterProxy::CFontListSortFilterProxy(QObject *parent, QAbstractItemModel *model) : QSortFilterProxyModel(parent), - itsGroup(NULL), + itsGroup(nullptr), itsFilterCriteria(CFontFilter::CRIT_FAMILY), itsFilterWs(0), - itsFcQuery(NULL) + itsFcQuery(nullptr) { setSourceModel(model); setSortCaseSensitivity(Qt::CaseInsensitive); setFilterKeyColumn(0); setDynamicSortFilter(false); itsTimer=new QTimer(this); connect(itsTimer, SIGNAL(timeout()), SLOT(timeout())); connect(model, SIGNAL(layoutChanged()), SLOT(invalidate())); itsTimer->setSingleShot(true); } QVariant CFontListSortFilterProxy::data(const QModelIndex &idx, int role) const { if (!idx.isValid()) return QVariant(); static const int constMaxFiles=20; QModelIndex index(mapToSource(idx)); CFontModelItem *mi=static_cast(index.internalPointer()); if(!mi) return QVariant(); switch(role) { case Qt::ToolTipRole: if(CFontFilter::CRIT_FILENAME==itsFilterCriteria || CFontFilter::CRIT_LOCATION==itsFilterCriteria || CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria) { if(mi->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); CFontItemCont::ConstIterator it(fam->fonts().begin()), end(fam->fonts().end()); FileCont allFiles; QString tip(""+fam->name()+""); bool markMatch(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria); tip+="

"; for(; it!=end; ++it) allFiles+=(*it)->files(); //qSort(allFiles); FileCont::ConstIterator fit(allFiles.begin()), fend(allFiles.end()); for(int i=0; fit!=fend && ifile()) tip+=""; else tip+=""; if(allFiles.count()>constMaxFiles) tip+=""; tip+="
"+Misc::contractHome((*fit).path())+"
"+Misc::contractHome((*fit).path())+"
"+i18n("...plus %1 more", allFiles.count()-constMaxFiles)+"

"; return tip; } else { CFontItem *font=static_cast(index.internalPointer()); QString tip(""+font->name()+""); const FileCont &files(font->files()); bool markMatch(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria); tip+="

"; //qSort(files); FileCont::ConstIterator fit(files.begin()), fend(files.end()); for(int i=0; fit!=fend && ifile()) tip+=""; else tip+=""; if(files.count()>constMaxFiles) tip+=""; tip+="
"+Misc::contractHome((*fit).path())+"
"+Misc::contractHome((*fit).path() )+"
"+i18n("...plus %1 more", files.count()-constMaxFiles)+"

"; return tip; } } break; case Qt::FontRole: if(COL_FONT==index.column() && mi->isSystem()) { QFont font; font.setItalic(true); return font; } break; case Qt::ForegroundRole: if(COL_FONT==index.column() && ( (mi->isFont() && !(static_cast(index.internalPointer()))->isEnabled()) || (mi->isFamily() && CFamilyItem::DISABLED==(static_cast(index.internalPointer()))->status())) ) return KColorScheme(QPalette::Active).foreground(KColorScheme::NegativeText).color(); break; case Qt::DisplayRole: if(COL_FONT==index.column()) { if(mi->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); return i18n("%1 [%2]", fam->name(), fam->fontCount()); } else return (static_cast(index.internalPointer()))->style(); } break; case Qt::DecorationRole: if(mi->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); switch(index.column()) { case COL_STATUS: switch(fam->status()) { case CFamilyItem::PARTIAL: return SmallIcon("dialog-ok", 0, KIconLoader::DisabledState); case CFamilyItem::ENABLED: return SmallIcon("dialog-ok"); case CFamilyItem::DISABLED: return SmallIcon("dialog-cancel"); } break; default: break; } } else if(COL_STATUS==index.column()) return SmallIcon( (static_cast(index.internalPointer()))->isEnabled() ? "dialog-ok" : "dialog-cancel", 10); break; case Qt::SizeHintRole: if(mi->isFamily()) { const int s = KIconLoader::global()->currentSize(KIconLoader::Small); return QSize(s, s + 4); } default: break; } return QVariant(); } bool CFontListSortFilterProxy::acceptFont(CFontItem *fnt, bool checkFontText) const { if(itsGroup && (CGroupListItem::ALL!=itsGroup->type() || (!filterText().isEmpty() && checkFontText))) { bool fontMatch(!checkFontText); if(!fontMatch) switch(itsFilterCriteria) { case CFontFilter::CRIT_FONTCONFIG: fontMatch=itsFcQuery ? fnt->name()==itsFcQuery->font() // || fnt->files().contains(itsFcQuery->file()) : false; break; case CFontFilter::CRIT_STYLE: fontMatch=matchString(fnt->style(), itsFilterText); break; case CFontFilter::CRIT_FOUNDRY: { FileCont::ConstIterator it(fnt->files().begin()), end(fnt->files().end()); for(; it!=end && !fontMatch; ++it) fontMatch=0==(*it).foundry().compare(itsFilterText, Qt::CaseInsensitive); break; } case CFontFilter::CRIT_FILENAME: { FileCont::ConstIterator it(fnt->files().begin()), end(fnt->files().end()); for(; it!=end && !fontMatch; ++it) { QString file(Misc::getFile((*it).path())); int pos(Misc::isHidden(file) ? 1 : 0); if(pos==file.indexOf(itsFilterText, pos, Qt::CaseInsensitive)) fontMatch=true; } break; } case CFontFilter::CRIT_LOCATION: { FileCont::ConstIterator it(fnt->files().begin()), end(fnt->files().end()); for(; it!=end && !fontMatch; ++it) if(0==Misc::getDir((*it).path()).indexOf(itsFilterText, 0, Qt::CaseInsensitive)) fontMatch=true; break; } case CFontFilter::CRIT_FILETYPE: { FileCont::ConstIterator it(fnt->files().begin()), end(fnt->files().end()); QStringList::ConstIterator mimeEnd(itsFilterTypes.constEnd()); for(; it!=end && !fontMatch; ++it) { QStringList::ConstIterator mime(itsFilterTypes.constBegin()); for(; mime!=mimeEnd; ++mime) if(Misc::checkExt((*it).path(), *mime)) fontMatch=true; } break; } case CFontFilter::CRIT_WS: fontMatch=fnt->writingSystems()&itsFilterWs; break; default: break; } return fontMatch && itsGroup->hasFont(fnt); } return true; } bool CFontListSortFilterProxy::acceptFamily(CFamilyItem *fam) const { CFontItemCont::ConstIterator it(fam->fonts().begin()), end(fam->fonts().end()); bool familyMatch(CFontFilter::CRIT_FAMILY==itsFilterCriteria && matchString(fam->name(), itsFilterText)); for(; it!=end; ++it) if(acceptFont(*it, !familyMatch)) return true; return false; } bool CFontListSortFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { QModelIndex index(sourceModel()->index(sourceRow, 0, sourceParent)); if(index.isValid()) { CFontModelItem *mi=static_cast(index.internalPointer()); if(mi->isFont()) { CFontItem *font=static_cast(index.internalPointer()); return acceptFont(font, !(CFontFilter::CRIT_FAMILY==itsFilterCriteria && matchString(font->family(), itsFilterText))); } else return acceptFamily(static_cast(index.internalPointer())); } return false; } bool CFontListSortFilterProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { if(left.isValid() && right.isValid()) { CFontModelItem *lmi=static_cast(left.internalPointer()), *rmi=static_cast(right.internalPointer()); if(lmi->isFont()isFont()) return true; if(lmi->isFont()) { CFontItem *lfi=static_cast(left.internalPointer()), *rfi=static_cast(right.internalPointer()); if(COL_STATUS==filterKeyColumn()) { if(lfi->isEnabled()isEnabled() || (lfi->isEnabled()==rfi->isEnabled() && lfi->styleInfo()styleInfo())) return true; } else if(lfi->styleInfo()styleInfo()) return true; } else { CFamilyItem *lfi=static_cast(left.internalPointer()), *rfi=static_cast(right.internalPointer()); if(COL_STATUS==filterKeyColumn()) { if(lfi->status()status() || (lfi->status()==rfi->status() && QString::localeAwareCompare(lfi->name(), rfi->name())<0)) return true; } else if(QString::localeAwareCompare(lfi->name(), rfi->name())<0) return true; } } return false; } void CFontListSortFilterProxy::setFilterGroup(CGroupListItem *grp) { if(grp!=itsGroup) { // bool wasNull=!itsGroup; itsGroup=grp; // if(!(wasNull && itsGroup && CGroupListItem::ALL==itsGroup->type())) clear(); } } void CFontListSortFilterProxy::setFilterText(const QString &text) { if(text!=itsFilterText) { // // If we are filtering on file location, then expand ~ to /home/user, etc. if (CFontFilter::CRIT_LOCATION==itsFilterCriteria && !text.isEmpty() && ('~'==text[0] || '$'==text[0])) if('~'==text[0]) itsFilterText=1==text.length() ? QDir::homePath() : QString(text).replace(0, 1, QDir::homePath()); else itsFilterText=replaceEnvVar(text); else itsFilterText=text; if(itsFilterText.isEmpty()) { itsTimer->stop(); timeout(); } else itsTimer->start(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria ? 750 : 400); } } void CFontListSortFilterProxy::setFilterCriteria(CFontFilter::ECriteria crit, qulonglong ws, const QStringList &ft) { if(crit!=itsFilterCriteria || ws!=itsFilterWs || ft!=itsFilterTypes) { itsFilterWs=ws; itsFilterCriteria=crit; itsFilterTypes=ft; if(CFontFilter::CRIT_LOCATION==itsFilterCriteria) setFilterText(itsFilterText); itsTimer->stop(); timeout(); } } void CFontListSortFilterProxy::timeout() { if(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria) { int commaPos=itsFilterText.indexOf(','); QString query(itsFilterText); if(-1!=commaPos) { QString style(query.mid(commaPos+1)); query=query.left(commaPos); query=query.trimmed(); query+=":style="; style=style.trimmed(); query+=style; } else query=query.trimmed(); if(!itsFcQuery) { itsFcQuery=new CFcQuery(this); connect(itsFcQuery, SIGNAL(finished()), SLOT(fcResults())); } itsFcQuery->run(query); } else { clear(); emit refresh(); } } void CFontListSortFilterProxy::fcResults() { if(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria) { clear(); emit refresh(); } } CFontListView::CFontListView(QWidget *parent, CFontList *model) : QTreeView(parent), itsProxy(new CFontListSortFilterProxy(this, model)), itsModel(model), itsAllowDrops(false) { setModel(itsProxy); itsModel=model; header()->setStretchLastSection(false); resizeColumnToContents(COL_STATUS); header()->setResizeMode(COL_STATUS, QHeaderView::Fixed); header()->setResizeMode(COL_FONT, QHeaderView::Stretch); setSelectionMode(QAbstractItemView::ExtendedSelection); setSelectionBehavior(QAbstractItemView::SelectRows); setSortingEnabled(true); sortByColumn(COL_FONT, Qt::AscendingOrder); setAllColumnsShowFocus(true); setAlternatingRowColors(true); setAcceptDrops(true); setDropIndicatorShown(false); setDragEnabled(true); setDragDropMode(QAbstractItemView::DragDrop); header()->setClickable(true); header()->setSortIndicatorShown(true); connect(this, SIGNAL(collapsed(QModelIndex)), SLOT(itemCollapsed(QModelIndex))); connect(header(), SIGNAL(sectionClicked(int)), SLOT(setSortColumn(int))); connect(itsProxy, SIGNAL(refresh()), SIGNAL(refresh())); connect(itsModel, SIGNAL(listingPercent(int)), SLOT(listingPercent(int))); setWhatsThis(model->whatsThis()); header()->setWhatsThis(whatsThis()); itsMenu=new QMenu(this); itsDeleteAct=itsMenu->addAction(QIcon::fromTheme("edit-delete"), i18n("Delete"), this, SIGNAL(del())); itsMenu->addSeparator(); itsEnableAct=itsMenu->addAction(QIcon::fromTheme("enablefont"), i18n("Enable"), this, SIGNAL(enable())); itsDisableAct=itsMenu->addAction(QIcon::fromTheme("disablefont"), i18n("Disable"), this, SIGNAL(disable())); if(!Misc::app(KFI_VIEWER).isEmpty()) itsMenu->addSeparator(); - itsPrintAct=Misc::app(KFI_VIEWER).isEmpty() ? 0L : itsMenu->addAction(QIcon::fromTheme("document-print"), i18n("Print..."), + itsPrintAct=Misc::app(KFI_VIEWER).isEmpty() ? nullptr : itsMenu->addAction(QIcon::fromTheme("document-print"), i18n("Print..."), this, SIGNAL(print())); - itsViewAct=Misc::app(KFI_VIEWER).isEmpty() ? 0L : itsMenu->addAction(QIcon::fromTheme("kfontview"), i18n("Open in Font Viewer"), + itsViewAct=Misc::app(KFI_VIEWER).isEmpty() ? nullptr : itsMenu->addAction(QIcon::fromTheme("kfontview"), i18n("Open in Font Viewer"), this, SLOT(view())); itsMenu->addSeparator(); itsMenu->addAction(QIcon::fromTheme("view-refresh"), i18n("Reload"), model, SLOT(load())); } void CFontListView::getFonts(CJobRunner::ItemList &urls, QStringList &fontNames, QSet *fonts, bool selected, bool getEnabled, bool getDisabled) { QModelIndexList selectedItems(selected ? selectedIndexes() : allIndexes()); QSet usedFonts; QModelIndex index; foreach(index, selectedItems) if(index.isValid()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font=static_cast(realIndex.internalPointer()); addFont(font, urls, fontNames, fonts, usedFonts, getEnabled, getDisabled); } else { CFamilyItem *fam=static_cast(realIndex.internalPointer()); for(int ch=0; chfontCount(); ++ch) { QModelIndex child(itsProxy->mapToSource(index.child(ch, 0))); if(child.isValid() && (static_cast(child.internalPointer()))->isFont()) { CFontItem *font=static_cast(child.internalPointer()); addFont(font, urls, fontNames, fonts, usedFonts, getEnabled, getDisabled); } } } } } fontNames=CFontList::compact(fontNames); } QSet CFontListView::getFiles() { QModelIndexList items(allIndexes()); QModelIndex index; QSet files; foreach(index, items) if(index.isValid()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font=static_cast(realIndex.internalPointer()); FileCont::ConstIterator it(font->files().begin()), end(font->files().end()); for(; it!=end; ++it) { QStringList assoc; files.insert((*it).path()); Misc::getAssociatedFiles((*it).path(), assoc); QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); for(; ait!=aend; ++ait) files.insert(*ait); } } } return files; } void CFontListView::getPrintableFonts(QSet &items, bool selected) { QModelIndexList selectedItems(selected ? selectedIndexes() : allIndexes()); QModelIndex index; foreach(index, selectedItems) { - CFontItem *font=NULL; + CFontItem *font=nullptr; if(index.isValid() && 0==index.column()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) font=static_cast(realIndex.internalPointer()); else { CFamilyItem *fam=static_cast(realIndex.internalPointer()); font=fam->regularFont(); } } } if(font && !font->isBitmap() && font->isEnabled()) items.insert(Misc::TFont(font->family(), font->styleInfo())); } } void CFontListView::setFilterGroup(CGroupListItem *grp) { CGroupListItem *oldGrp(itsProxy->filterGroup()); itsProxy->setFilterGroup(grp); itsAllowDrops=grp && !grp->isCustom(); if(!Misc::root()) { bool refreshStats(false); if(!grp || !oldGrp) refreshStats=true; else { // Check to see whether we have changed from listing all fonts, // listing just system or listing personal fonts. CGroupListItem::EType aType(CGroupListItem::CUSTOM==grp->type() || CGroupListItem::ALL==grp->type() || CGroupListItem::UNCLASSIFIED==grp->type() ? CGroupListItem::CUSTOM : grp->type()), bType(CGroupListItem::CUSTOM==oldGrp->type() || CGroupListItem::ALL==oldGrp->type() || CGroupListItem::UNCLASSIFIED==oldGrp->type() ? CGroupListItem::CUSTOM : oldGrp->type()); refreshStats=aType!=bType; } if(refreshStats) itsModel->refresh(!grp || !grp->isPersonal(), !grp || !grp->isSystem()); } // when switching groups, for some reason it is not always sorted. setSortingEnabled(true); } void CFontListView::listingPercent(int percent) { // when the font list is first loaded, for some reason it is not always sorted. // re-enabling sorting here seems to fix the issue - BUG 221610 if(100==percent) setSortingEnabled(true); } void CFontListView::refreshFilter() { itsProxy->clear(); } void CFontListView::filterText(const QString &text) { itsProxy->setFilterText(text); } void CFontListView::filterCriteria(int crit, qulonglong ws, const QStringList &ft) { itsProxy->setFilterCriteria((CFontFilter::ECriteria)crit, ws, ft); } void CFontListView::stats(int &enabled, int &disabled, int &partial) { enabled=disabled=partial=0; for(int i=0; irowCount(); ++i) { QModelIndex idx(itsProxy->index(i, 0, QModelIndex())); if(!idx.isValid()) break; QModelIndex sourceIdx(itsProxy->mapToSource(idx)); if(!sourceIdx.isValid()) break; if((static_cast(sourceIdx.internalPointer()))->isFamily()) switch((static_cast(sourceIdx.internalPointer()))->status()) { case CFamilyItem::ENABLED: enabled++; break; case CFamilyItem::DISABLED: disabled++; break; case CFamilyItem::PARTIAL: partial++; break; } } } void CFontListView::selectedStatus(bool &enabled, bool &disabled) { QModelIndexList selected(selectedIndexes()); QModelIndex index; enabled=disabled=false; foreach(index, selected) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFamily()) { switch((static_cast(realIndex.internalPointer()))->status()) { case CFamilyItem::ENABLED: enabled=true; break; case CFamilyItem::DISABLED: disabled=true; break; case CFamilyItem::PARTIAL: enabled=true; disabled=true; break; } } else { if((static_cast(realIndex.internalPointer()))->isEnabled()) enabled=true; else disabled=true; } } if(enabled && disabled) break; } } QModelIndexList CFontListView::allFonts() { QModelIndexList rv; int rowCount(itsProxy->rowCount()); for(int i=0; iindex(i, 0, QModelIndex())); int childRowCount(itsProxy->rowCount(idx)); for(int j=0; jindex(j, 0, idx)); if(child.isValid()) rv.append(itsProxy->mapToSource(child)); } } return rv; } void CFontListView::selectFirstFont() { if(0==selectedIndexes().count()) for(int i=0; iindex(0, i, QModelIndex())); if(idx.isValid()) selectionModel()->select(idx, QItemSelectionModel::Select); } } void CFontListView::setSortColumn(int col) { if(col!=itsProxy->filterKeyColumn()) { itsProxy->setFilterKeyColumn(col); itsProxy->clear(); } } void CFontListView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { QAbstractItemView::selectionChanged(selected, deselected); if(itsModel->slowUpdates()) return; emit itemsSelected(getSelectedItems()); } QModelIndexList CFontListView::getSelectedItems() { // // Go through current selection, and for any 'font' items that are selected, // ensure 'family' item is not... QModelIndexList selectedItems(selectedIndexes()), deselectList; QModelIndex index; QSet selectedFamilies; bool en(false), dis(false); foreach(index, selectedItems) if(index.isValid()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font=static_cast(realIndex.internalPointer()); if(font->isEnabled()) en=true; else dis=true; if(!selectedFamilies.contains(font->parent())) { selectedFamilies.insert(font->parent()); for(int i=0; imapFromSource( itsModel->createIndex(font->parent()->rowNumber(), i, font->parent()))); } } else { switch((static_cast(realIndex.internalPointer()))->status()) { case CFamilyItem::ENABLED: en=true; break; case CFamilyItem::DISABLED: dis=true; break; case CFamilyItem::PARTIAL: en=dis=true; break; } } } } if(deselectList.count()) foreach(index, deselectList) selectionModel()->select(index, QItemSelectionModel::Deselect); QModelIndexList sel; QSet pointers; selectedItems=selectedIndexes(); foreach(index, selectedItems) { QModelIndex idx(itsProxy->mapToSource(index)); if(!pointers.contains(idx.internalPointer())) { pointers.insert(idx.internalPointer()); sel.append(idx); } } return sel; } void CFontListView::itemCollapsed(const QModelIndex &idx) { if(idx.isValid()) { QModelIndex index(itsProxy->mapToSource(idx)); if(index.isValid() && (static_cast(index.internalPointer()))->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); CFontItemCont::ConstIterator it(fam->fonts().begin()), end(fam->fonts().end()); for(; it!=end; ++it) for(int i=0; iselect(itsProxy->mapFromSource(itsModel->createIndex((*it)->rowNumber(), i, *it)), QItemSelectionModel::Deselect); } } } static bool isScalable(const QString &str) { QByteArray cFile(QFile::encodeName(str)); return Misc::checkExt(cFile, "ttf") || Misc::checkExt(cFile, "otf") || Misc::checkExt(cFile, "ttc") || Misc::checkExt(cFile, "pfa") || Misc::checkExt(cFile, "pfb"); } void CFontListView::view() { // Number of fonts user has selected, before we ask if they really want to view them all... static const int constMaxBeforePrompt=10; QModelIndexList selectedItems(selectedIndexes()); QModelIndex index; QSet fonts; foreach(index, selectedItems) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font(static_cast(realIndex.internalPointer())); fonts.insert(font); } else { CFontItem *font((static_cast(realIndex.internalPointer()))->regularFont()); if(font) fonts.insert(font); } } } if(fonts.count() && (fonts.count()::ConstIterator it(fonts.begin()), end(fonts.end()); QStringList args; for(; it!=end; ++it) { QString file; int index(0); if(!(*it)->isEnabled()) { // For a disabled font, we need to find the first scalable font entry in its file list... FileCont::ConstIterator fit((*it)->files().begin()), fend((*it)->files().end()); for(; fit!=fend; ++fit) if(isScalable((*fit).path())) { file=(*fit).path(); index=(*fit).index(); break; } if(file.isEmpty()) { file=(*it)->fileName(); index=(*it)->index(); } } args << FC::encode((*it)->family(), (*it)->styleInfo(), file, index).url(); } QProcess::startDetached(Misc::app(KFI_VIEWER), args); } } QModelIndexList CFontListView::allIndexes() { QModelIndexList rv; int rowCount(itsProxy->rowCount()); for(int i=0; iindex(i, 0, QModelIndex())); int childRowCount(itsProxy->rowCount(idx)); rv.append(idx); for(int j=0; jindex(j, 0, idx)); if(child.isValid()) rv.append(child); } } return rv; } void CFontListView::startDrag(Qt::DropActions supportedActions) { QModelIndexList indexes(selectedIndexes()); if (indexes.count()) { QMimeData *data = model()->mimeData(indexes); if (!data) return; QModelIndex index(itsProxy->mapToSource(indexes.first())); const char *icon="application-x-font-pcf"; if(index.isValid()) { CFontItem *font=(static_cast(index.internalPointer()))->isFont() ? static_cast(index.internalPointer()) : (static_cast(index.internalPointer()))->regularFont(); if(font && !font->isBitmap()) // if("application/x-font-type1"==font->mimetype()) // icon="application-x-font-type1"; // else icon="application-x-font-ttf"; } QPoint hotspot; QPixmap pix(DesktopIcon(icon, KIconLoader::SizeMedium)); hotspot.setX(0); // pix.width()/2); hotspot.setY(0); // pix.height()/2); QDrag *drag = new QDrag(this); drag->setPixmap(pix); drag->setMimeData(data); drag->setHotSpot(hotspot); drag->start(supportedActions); } } void CFontListView::dragEnterEvent(QDragEnterEvent *event) { if(itsAllowDrops && event->mimeData()->hasFormat("text/uri-list")) // "application/x-kde-urilist" ?? event->acceptProposedAction(); } void CFontListView::dropEvent(QDropEvent *event) { if(itsAllowDrops && event->mimeData()->hasFormat("text/uri-list")) { event->acceptProposedAction(); QList urls(event->mimeData()->urls()); QList::ConstIterator it(urls.begin()), end(urls.end()); QSet kurls; QMimeDatabase db; for (; it!=end; ++it) { QMimeType mime = db.mimeTypeForUrl(*it); foreach (const QString &fontMime, CFontList::fontMimeTypes) { if (mime.inherits(fontMime)) { kurls.insert(*it); break; } } } if(kurls.count()) emit fontsDropped(kurls); } } void CFontListView::contextMenuEvent(QContextMenuEvent *ev) { bool valid(indexAt(ev->pos()).isValid()); itsDeleteAct->setEnabled(valid); bool en(false), dis(false); QModelIndexList selectedItems(selectedIndexes()); QModelIndex index; foreach(index, selectedItems) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { if((static_cast(realIndex.internalPointer())->isEnabled())) en=true; else dis=true; } else { switch((static_cast(realIndex.internalPointer()))->status()) { case CFamilyItem::ENABLED: en=true; break; case CFamilyItem::DISABLED: dis=true; break; case CFamilyItem::PARTIAL: en=dis=true; break; } } } if(en && dis) break; } itsEnableAct->setEnabled(dis); itsDisableAct->setEnabled(en); if(itsPrintAct) itsPrintAct->setEnabled(en|dis); if(itsViewAct) itsViewAct->setEnabled(en|dis); itsMenu->popup(ev->globalPos()); } bool CFontListView::viewportEvent(QEvent *event) { executeDelayedItemsLayout(); return QTreeView::viewportEvent(event); } } diff --git a/kcms/kfontinst/kcmfontinst/FontList.h b/kcms/kfontinst/kcmfontinst/FontList.h index 367c6dd07..49b8d7705 100644 --- a/kcms/kfontinst/kcmfontinst/FontList.h +++ b/kcms/kfontinst/kcmfontinst/FontList.h @@ -1,382 +1,382 @@ #ifndef __FONT_LIST_H__ #define __FONT_LIST_H__ /* * 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 #include #include #include #include #include #include #include #include #include #include #include "Misc.h" #include "JobRunner.h" #include "FontFilter.h" #include "FcQuery.h" #include "File.h" #include "Style.h" #include "Family.h" #include "FontInst.h" class KConfigGroup; class KFileItem; class KFileItemList; class QMenu; class QPixmap; class QMimeData; class QTimer; class QPoint; #define KFI_FONT_DRAG_MIME "kfontinst/fontlist" namespace KFI { class CFontItem; class CFontItem; class CFamilyItem; class CGroupListItem; class Style; enum EColumns { COL_FONT, COL_STATUS, NUM_COLS }; typedef QList CFamilyItemCont; typedef QList CFontItemCont; typedef QHash CFamilyItemHash; class CFontList : public QAbstractItemModel { Q_OBJECT private: enum EMsgType { MSG_ADD, MSG_DEL, NUM_MSGS_TYPES }; public: static const QStringList fontMimeTypes; public: static QStringList compact(const QStringList &fonts); - CFontList(QWidget *parent=0); + CFontList(QWidget *parent=nullptr); ~CFontList() override; QVariant data(const QModelIndex &index, int role) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; Qt::DropActions supportedDropActions() const override; QMimeData * mimeData(const QModelIndexList &indexes) const override; QStringList mimeTypes() const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; int row(const CFamilyItem *fam) const { return itsFamilies.indexOf((CFamilyItem *)fam); } void forceNewPreviews(); const CFamilyItemCont & families() const { return itsFamilies; } - QModelIndex createIndex(int row, int column, void *data = 0) const + QModelIndex createIndex(int row, int column, void *data = nullptr) const { return QAbstractItemModel::createIndex(row, column, data); } - bool hasFamily(const QString &family) { return NULL!=findFamily(family); } + bool hasFamily(const QString &family) { return nullptr!=findFamily(family); } void refresh(bool allowSys, bool allowUser); bool allowSys() const { return itsAllowSys; } bool allowUser() const { return itsAllowUser; } void getFamilyStats(QSet &enabled, QSet &disabled, QSet &partial); void getFoundries(QSet &foundries) const; QString whatsThis() const; void setSlowUpdates(bool slow); bool slowUpdates() const { return itsSlowUpdates; } Q_SIGNALS: void listingPercent(int p); public Q_SLOTS: void unsetSlowUpdates(); void load(); private Q_SLOTS: void dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to); void fontList(int pid, const QList &families); void fontsAdded(const KFI::Families &families); void fontsRemoved(const KFI::Families &families); private: void storeSlowedMessage(const Families &families, EMsgType type); void actionSlowedUpdates(bool sys); void addFonts(const FamilyCont &families, bool sys); void removeFonts(const FamilyCont &families, bool sys); CFamilyItem * findFamily(const QString &familyName); private: CFamilyItemCont itsFamilies; CFamilyItemHash itsFamilyHash; bool itsBlockSignals, itsAllowSys, itsAllowUser, itsSlowUpdates; static int theirPreviewSize; FamilyCont itsSlowedMsgs[NUM_MSGS_TYPES][FontInst::FOLDER_COUNT]; }; class CFontModelItem { public: CFontModelItem(CFontModelItem *p) : itsParent(p), itsIsSystem(false) { } virtual ~CFontModelItem() { } CFontModelItem * parent() const { return itsParent; } - bool isFamily() const { return NULL==itsParent; } - bool isFont() const { return NULL!=itsParent; } + bool isFamily() const { return nullptr==itsParent; } + bool isFont() const { return nullptr!=itsParent; } bool isSystem() const { return itsIsSystem; } void setIsSystem(bool sys) { itsIsSystem=sys; } virtual int rowNumber() const = 0; protected: CFontModelItem *itsParent; bool itsIsSystem; }; class CFamilyItem : public CFontModelItem { public: enum EStatus { ENABLED, PARTIAL, DISABLED }; CFamilyItem(CFontList &p, const Family &f, bool sys); ~CFamilyItem() override; bool operator==(const CFamilyItem &other) const { return itsName==other.itsName; } bool addFonts(const StyleCont &styles, bool sys); const QString & name() const { return itsName; } const CFontItemCont & fonts() const { return itsFonts; } void addFont(CFontItem *font, bool update=true); void removeFont(CFontItem *font, bool update); void refresh(); bool updateStatus(); bool updateRegularFont(CFontItem *font); CFontItem * findFont(quint32 style, bool sys); int rowNumber() const override { return itsParent.row(this); } int row(const CFontItem *font) const { return itsFonts.indexOf((CFontItem *)font); } EStatus status() const { return itsStatus; } EStatus realStatus() const { return itsRealStatus; } CFontItem * regularFont() { return itsRegularFont; } int fontCount() const { return itsFontCount; } void getFoundries(QSet &foundries) const; bool slowUpdates() const { return itsParent.slowUpdates(); } private: bool usable(const CFontItem *font, bool root); private: QString itsName; CFontItemCont itsFonts; int itsFontCount; EStatus itsStatus, itsRealStatus; CFontItem *itsRegularFont; // 'RegularFont' is font nearest to 'Regular' style, and used for previews. CFontList &itsParent; }; class CFontItem : public CFontModelItem { public: CFontItem(CFontModelItem *p, const Style &s, bool sys); ~CFontItem() override { } void refresh(); QString name() const { return family()+QString::fromLatin1(", ")+itsStyleName; } bool isEnabled() const { return itsEnabled; } bool isHidden() const { return !itsEnabled; } bool isBitmap() const { return !itsStyle.scalable(); } const QString & fileName() const { return (*itsStyle.files().begin()).path(); } const QString & style() const { return itsStyleName; } quint32 styleInfo() const { return itsStyle.value(); } int index() const { return (*itsStyle.files().begin()).index(); } const QString & family() const { return (static_cast(parent()))->name(); } int rowNumber() const override { return (static_cast(parent()))->row(this); } const FileCont & files() const { return itsStyle.files(); } qulonglong writingSystems() const { return itsStyle.writingSystems(); } QUrl url() const { return CJobRunner::encode(family(), styleInfo(), isSystem()); } void removeFile(const File &f){ itsStyle.remove(f); } void removeFiles(const FileCont &f){ itsStyle.removeFiles(f); } void addFile(const File &f) { itsStyle.add(f); } void addFiles(const FileCont &f) { itsStyle.addFiles(f); } private: QString itsStyleName; Style itsStyle; bool itsEnabled; }; class CFontListSortFilterProxy : public QSortFilterProxyModel { Q_OBJECT public: CFontListSortFilterProxy(QObject *parent, QAbstractItemModel *model); ~CFontListSortFilterProxy() override { } QVariant data(const QModelIndex &idx, int role) const override; bool acceptFont(CFontItem *fnt, bool checkFontText) const; bool acceptFamily(CFamilyItem *fam) const; bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; void setFilterGroup(CGroupListItem *grp); CGroupListItem * filterGroup() { return itsGroup; } void setFilterText(const QString &text); void setFilterCriteria(CFontFilter::ECriteria crit, qulonglong ws, const QStringList &ft); private Q_SLOTS: void timeout(); void fcResults(); Q_SIGNALS: void refresh(); private: QString filterText() const { return CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria ? (itsFcQuery ? itsFcQuery->font() : QString()) : itsFilterText; } private: CGroupListItem *itsGroup; QString itsFilterText; CFontFilter::ECriteria itsFilterCriteria; qulonglong itsFilterWs; QStringList itsFilterTypes; QTimer *itsTimer; CFcQuery *itsFcQuery; }; class CFontListView : public QTreeView { Q_OBJECT public: CFontListView(QWidget *parent, CFontList *model); ~CFontListView() override { } void getFonts(CJobRunner::ItemList &urls, QStringList &fontNames, QSet *fonts, bool selected, bool getEnabled=true, bool getDisabled=true); QSet getFiles(); void getPrintableFonts(QSet &items, bool selected); void setFilterGroup(CGroupListItem *grp); void stats(int &enabled, int &disabled, int &partial); void selectedStatus(bool &enabled, bool &disabled); QModelIndexList allFonts(); void selectFirstFont(); QModelIndexList getSelectedItems(); Q_SIGNALS: void del(); void print(); void enable(); void disable(); void fontsDropped(const QSet &); void itemsSelected(const QModelIndexList &); void refresh(); void reload(); public Q_SLOTS: void listingPercent(int percent); void refreshFilter(); void filterText(const QString &text); void filterCriteria(int crit, qulonglong ws, const QStringList &ft); private Q_SLOTS: void setSortColumn(int col); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override; void itemCollapsed(const QModelIndex &index); void view(); private: QModelIndexList allIndexes(); void startDrag(Qt::DropActions supportedActions) override; void dragEnterEvent(QDragEnterEvent *event) override; void dropEvent(QDropEvent *event) override; void contextMenuEvent(QContextMenuEvent *ev) override; bool viewportEvent(QEvent *event) override; private: CFontListSortFilterProxy *itsProxy; CFontList *itsModel; QMenu *itsMenu; QAction *itsDeleteAct, *itsEnableAct, *itsDisableAct, *itsPrintAct, *itsViewAct; bool itsAllowDrops; }; } #endif diff --git a/kcms/kfontinst/kcmfontinst/GroupList.cpp b/kcms/kfontinst/kcmfontinst/GroupList.cpp index 720588a94..ae259f2e6 100644 --- a/kcms/kfontinst/kcmfontinst/GroupList.cpp +++ b/kcms/kfontinst/kcmfontinst/GroupList.cpp @@ -1,1026 +1,1026 @@ /* * 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 "GroupList.h" #include "FontList.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FcEngine.h" #include "Misc.h" #include "KfiConstants.h" namespace KFI { #define GROUPS_DOC "groups" #define GROUP_TAG "group" #define NAME_ATTR "name" #define FAMILY_TAG "family" enum EGroupColumns { COL_GROUP_NAME, NUM_GROUP_COLS }; CGroupListItem::CGroupListItem(const QString &name) : itsName(name), itsType(CUSTOM), itsHighlighted(false), itsStatus(CFamilyItem::ENABLED) { itsData.validated=false; } CGroupListItem::CGroupListItem(EType type, CGroupList *p) : itsType(type), itsHighlighted(false), itsStatus(CFamilyItem::ENABLED) { switch(itsType) { case ALL: itsName=i18n("All Fonts"); break; case PERSONAL: itsName=i18n("Personal Fonts"); break; case SYSTEM: itsName=i18n("System Fonts"); break; default: itsName=i18n("Unclassified"); } itsData.parent=p; } bool CGroupListItem::hasFont(const CFontItem *fnt) const { switch(itsType) { case CUSTOM: return itsFamilies.contains(fnt->family()); case PERSONAL: return !fnt->isSystem(); case SYSTEM: return fnt->isSystem(); case ALL: return true; case UNCLASSIFIED: { QList::ConstIterator it(itsData.parent->itsGroups.begin()), end(itsData.parent->itsGroups.end()); for(; it!=end; ++it) if((*it)->isCustom() && (*it)->families().contains(fnt->family())) return false; return true; } default: return false; } return false; } void CGroupListItem::updateStatus(QSet &enabled, QSet &disabled, QSet &partial) { QSet families(itsFamilies); if(0!=families.intersect(partial).count()) itsStatus=CFamilyItem::PARTIAL; else { families=itsFamilies; bool haveEnabled(0!=families.intersect(enabled).count()); families=itsFamilies; bool haveDisabled(0!=families.intersect(disabled).count()); if(haveEnabled && haveDisabled) itsStatus=CFamilyItem::PARTIAL; else if(haveEnabled && !haveDisabled) itsStatus=CFamilyItem::ENABLED; else itsStatus=CFamilyItem::DISABLED; } } bool CGroupListItem::load(QDomElement &elem) { if(elem.hasAttribute(NAME_ATTR)) { itsName=elem.attribute(NAME_ATTR); addFamilies(elem); return true; } return false; } bool CGroupListItem::addFamilies(QDomElement &elem) { int b4(itsFamilies.count()); for(QDomNode n=elem.firstChild(); !n.isNull(); n=n.nextSibling()) { QDomElement ent=n.toElement(); if(FAMILY_TAG==ent.tagName()) itsFamilies.insert(ent.text()); } return b4!=itsFamilies.count(); } void CGroupListItem::save(QTextStream &str) { str << " <" GROUP_TAG " " NAME_ATTR "=\"" << Misc::encodeText(itsName, str) << "\">" << endl; if(itsFamilies.count()) { QSet::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end()); for(; it!=end; ++it) str << " <" FAMILY_TAG ">" << Misc::encodeText(*it, str) << "" << endl; } str << " " << endl; } CGroupList::CGroupList(QWidget *parent) : QAbstractItemModel(parent), itsTimeStamp(0), itsModified(false), itsParent(parent), itsSortOrder(Qt::AscendingOrder) { itsSpecialGroups[CGroupListItem::ALL]=new CGroupListItem(CGroupListItem::ALL, this); itsGroups.append(itsSpecialGroups[CGroupListItem::ALL]); if(Misc::root()) itsSpecialGroups[CGroupListItem::PERSONAL]= itsSpecialGroups[CGroupListItem::SYSTEM]=NULL; else { itsSpecialGroups[CGroupListItem::PERSONAL]=new CGroupListItem(CGroupListItem::PERSONAL, this); itsGroups.append(itsSpecialGroups[CGroupListItem::PERSONAL]); itsSpecialGroups[CGroupListItem::SYSTEM]=new CGroupListItem(CGroupListItem::SYSTEM, this); itsGroups.append(itsSpecialGroups[CGroupListItem::SYSTEM]); } itsSpecialGroups[CGroupListItem::UNCLASSIFIED]= new CGroupListItem(CGroupListItem::UNCLASSIFIED, this); // Locate groups.xml file - normall will be ~/.config/fontgroups.xml QString path(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/'); if(!Misc::dExists(path)) Misc::createDir(path); itsFileName=path+'/'+KFI_GROUPS_FILE; rescan(); } CGroupList::~CGroupList() { save(); qDeleteAll(itsGroups); itsGroups.clear(); } int CGroupList::columnCount(const QModelIndex &) const { return NUM_GROUP_COLS; } void CGroupList::update(const QModelIndex &unHighlight, const QModelIndex &highlight) { if(unHighlight.isValid()) { CGroupListItem *grp=static_cast(unHighlight.internalPointer()); if(grp) grp->setHighlighted(false); emit dataChanged(unHighlight, unHighlight); } if(highlight.isValid()) { CGroupListItem *grp=static_cast(highlight.internalPointer()); if(grp) grp->setHighlighted(true); emit dataChanged(highlight, highlight); } } void CGroupList::updateStatus(QSet &enabled, QSet &disabled, QSet &partial) { QList::Iterator it(itsGroups.begin()), end(itsGroups.end()); for(; it!=end; ++it) if((*it)->isCustom()) (*it)->updateStatus(enabled, disabled, partial); emit layoutChanged(); } inline QColor midColour(const QColor &a, const QColor &b) { return QColor((a.red()+b.red())>>1, (a.green()+b.green())>>1, (a.blue()+b.blue())>>1); } QVariant CGroupList::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); CGroupListItem *grp=static_cast(index.internalPointer()); if(grp) switch(index.column()) { case COL_GROUP_NAME: switch(role) { case Qt::FontRole: if(CGroupListItem::SYSTEM==grp->type()) { QFont font; font.setItalic(true); return font; } break; case Qt::SizeHintRole: { const int s = KIconLoader::global()->currentSize(KIconLoader::Small); return QSize(s, s + 4); } case Qt::EditRole: case Qt::DisplayRole: return grp->name(); case Qt::DecorationRole: if(grp->highlighted()) switch(grp->type()) { case CGroupListItem::ALL: // Removing from a group return SmallIcon("list-remove"); case CGroupListItem::PERSONAL: // Copying/moving case CGroupListItem::SYSTEM: // Copying/moving return SmallIcon(Qt::LeftToRight==QApplication::layoutDirection() ? "go-next" : "go-previous"); case CGroupListItem::CUSTOM: // Adding to a group return SmallIcon("list-add"); default: break; } else switch(grp->type()) { case CGroupListItem::ALL: return SmallIcon("preferences-desktop-font"); case CGroupListItem::PERSONAL: return SmallIcon("user-identity"); case CGroupListItem::SYSTEM: return SmallIcon("computer"); case CGroupListItem::UNCLASSIFIED: return SmallIcon("fontstatus"); case CGroupListItem::CUSTOM: if(0==grp->families().count()) return SmallIcon("image-missing"); switch(grp->status()) { case CFamilyItem::PARTIAL: return SmallIcon("dialog-ok", 0, KIconLoader::DisabledState); case CFamilyItem::ENABLED: return SmallIcon("dialog-ok"); case CFamilyItem::DISABLED: return SmallIcon("dialog-cancel"); } break; } default: break; } break; } return QVariant(); } bool CGroupList::setData(const QModelIndex &index, const QVariant &value, int role) { if(Qt::EditRole==role && index.isValid()) { QString name(value.toString().trimmed()); if(!name.isEmpty()) { CGroupListItem *grp=static_cast(index.internalPointer()); if(grp && grp->isCustom() && grp->name()!=name && !exists(name, false)) { grp->setName(name); itsModified=true; save(); sort(0, itsSortOrder); return true; } } } return false; } Qt::ItemFlags CGroupList::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemIsEnabled; CGroupListItem *grp=static_cast(index.internalPointer()); return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled | (grp && grp->type()==CGroupListItem::CUSTOM ? Qt::ItemIsEditable : Qt::NoItemFlags); } QVariant CGroupList::headerData(int section, Qt::Orientation orientation, int role) const { if (Qt::Horizontal==orientation && COL_GROUP_NAME==section) switch(role) { case Qt::DisplayRole: return i18n("Group"); case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case Qt::WhatsThisRole: return whatsThis(); default: break; } return QVariant(); } QModelIndex CGroupList::index(int row, int column, const QModelIndex &parent) const { if(!parent.isValid()) { CGroupListItem *grp=itsGroups.value(row); if(grp) return createIndex(row, column, grp); } return QModelIndex(); } QModelIndex CGroupList::parent(const QModelIndex &) const { return QModelIndex(); } int CGroupList::rowCount(const QModelIndex &) const { return itsGroups.count(); } void CGroupList::rescan() { save(); load(); sort(0, itsSortOrder); } void CGroupList::load() { time_t ts=Misc::getTimeStamp(itsFileName); if(!ts || ts!=itsTimeStamp) { clear(); itsTimeStamp=ts; if(load(itsFileName)) itsModified=false; } } bool CGroupList::load(const QString &file) { QFile f(file); bool rv(false); if(f.open(QIODevice::ReadOnly)) { QDomDocument doc; if(doc.setContent(&f)) for(QDomNode n=doc.documentElement().firstChild(); !n.isNull(); n=n.nextSibling()) { QDomElement e=n.toElement(); if(GROUP_TAG==e.tagName() && e.hasAttribute(NAME_ATTR)) { QString name(e.attribute(NAME_ATTR)); CGroupListItem *item=find(name); if(!item) { item=new CGroupListItem(name); if(!itsGroups.contains(itsSpecialGroups[CGroupListItem::UNCLASSIFIED])) itsGroups.append(itsSpecialGroups[CGroupListItem::UNCLASSIFIED]); itsGroups.append(item); rv=true; } if(item->addFamilies(e)) rv=true; } } } return rv; } bool CGroupList::save() { - if(itsModified && save(itsFileName, NULL)) + if(itsModified && save(itsFileName, nullptr)) { itsTimeStamp=Misc::getTimeStamp(itsFileName); return true; } return false; } bool CGroupList::save(const QString &fileName, CGroupListItem *grp) { QSaveFile file(fileName); if (file.open(QIODevice::WriteOnly)) { QTextStream str(&file); str << "<" GROUPS_DOC ">" << endl; if(grp) grp->save(str); else { QList::Iterator it(itsGroups.begin()), end(itsGroups.end()); for(; it!=end; ++it) if((*it)->isCustom()) (*it)->save(str); } str << "" << endl; itsModified=false; return file.commit(); } return false; } void CGroupList::merge(const QString &file) { if(load(file)) { itsModified=true; sort(0, itsSortOrder); } } void CGroupList::clear() { beginResetModel(); itsGroups.removeFirst(); // Remove all if(itsSpecialGroups[CGroupListItem::SYSTEM]) { itsGroups.removeFirst(); // Remove personal itsGroups.removeFirst(); // Remove system } if(itsGroups.contains(itsSpecialGroups[CGroupListItem::UNCLASSIFIED])) itsGroups.removeFirst(); // Remove unclassif... qDeleteAll(itsGroups); itsGroups.clear(); itsGroups.append(itsSpecialGroups[CGroupListItem::ALL]); if(itsSpecialGroups[CGroupListItem::SYSTEM]) { itsGroups.append(itsSpecialGroups[CGroupListItem::PERSONAL]); itsGroups.append(itsSpecialGroups[CGroupListItem::SYSTEM]); } // Don't add 'Unclassif' until we have some user groups endResetModel(); } QModelIndex CGroupList::index(CGroupListItem::EType t) { return createIndex(t, 0, itsSpecialGroups[t]); } void CGroupList::createGroup(const QString &name) { if(!exists(name)) { if(!itsGroups.contains(itsSpecialGroups[CGroupListItem::UNCLASSIFIED])) itsGroups.append(itsSpecialGroups[CGroupListItem::UNCLASSIFIED]); itsGroups.append(new CGroupListItem(name)); itsModified=true; save(); sort(0, itsSortOrder); } } bool CGroupList::removeGroup(const QModelIndex &idx) { if(idx.isValid()) { CGroupListItem *grp=static_cast(idx.internalPointer()); if(grp && grp->isCustom() && KMessageBox::Yes==KMessageBox::warningYesNo(itsParent, i18n("

Do you really want to remove \'%1\'?

" "

This will only remove the group, and not " "the actual fonts.

", grp->name()), i18n("Remove Group"), KGuiItem(i18n("Remove"), "list-remove", i18n("Remove group")))) { itsModified=true; itsGroups.removeAll(grp); int stdGroups=1 +// All (itsSpecialGroups[CGroupListItem::SYSTEM] ? 2 : 0)+ // Personal, System 1; // Unclassified if(stdGroups==itsGroups.count() && itsGroups.contains(itsSpecialGroups[CGroupListItem::UNCLASSIFIED])) itsGroups.removeAll(itsSpecialGroups[CGroupListItem::UNCLASSIFIED]); delete grp; save(); sort(0, itsSortOrder); return true; } } return false; } void CGroupList::removeFromGroup(const QModelIndex &group, const QSet &families) { if(group.isValid()) { CGroupListItem *grp=static_cast(group.internalPointer()); if(grp && grp->isCustom()) { QSet::ConstIterator it(families.begin()), end(families.end()); bool update(false); for(; it!=end; ++it) if(removeFromGroup(grp, *it)) update=true; if(update) emit refresh(); } } } QString CGroupList::whatsThis() const { return i18n("

Font Groups

This list displays the font groups available on your system. " "There are 2 main types of font groups:" "

  • Standard are special groups used by the font manager.
      %1
  • " "
  • Custom are groups created by you. To add a font family to one of " "these groups simply drag it from the list of fonts, and drop " "onto the desired group. To remove a family from the group, drag " "the font onto the \"All Fonts\" group.
  • " "

", Misc::root() ? i18n("
  • All Fonts contains all the fonts installed on your system.
  • " "
  • Unclassified contains all fonts that have not yet been placed " "within a \"Custom\" group.
  • ") : i18n("
  • All Fonts contains all the fonts installed on your system - " "both \"System\" and \"Personal\".
  • " "
  • System contains all fonts that are installed system-wide (i.e. " "available to all users).
  • " "
  • Personal contains your personal fonts.
  • " "
  • Unclassified contains all fonts that have not yet been placed " "within a \"Custom\" group.
  • ")); } void CGroupList::addToGroup(const QModelIndex &group, const QSet &families) { if(group.isValid()) { CGroupListItem *grp=static_cast(group.internalPointer()); if(grp && grp->isCustom()) { QSet::ConstIterator it(families.begin()), end(families.end()); bool update(false); for(; it!=end; ++it) if(!grp->hasFamily(*it)) { grp->addFamily(*it); update=true; itsModified=true; } if(update) emit refresh(); } } } void CGroupList::removeFamily(const QString &family) { QList::ConstIterator it(itsGroups.begin()), end(itsGroups.end()); for(; it!=end; ++it) removeFromGroup(*it, family); } bool CGroupList::removeFromGroup(CGroupListItem *grp, const QString &family) { if(grp && grp->isCustom() && grp->hasFamily(family)) { grp->removeFamily(family); itsModified=true; return true; } return false; } static bool groupNameLessThan(const CGroupListItem *f1, const CGroupListItem *f2) { return f1 && f2 && (f1->type()type() || (f1->type()==f2->type() && QString::localeAwareCompare(f1->name(), f2->name())<0)); } static bool groupNameGreaterThan(const CGroupListItem *f1, const CGroupListItem *f2) { return f1 && f2 && (f1->type()type() || (f1->type()==f2->type() && QString::localeAwareCompare(f1->name(), f2->name())>0)); } void CGroupList::sort(int, Qt::SortOrder order) { itsSortOrder=order; qSort(itsGroups.begin(), itsGroups.end(), Qt::AscendingOrder==order ? groupNameLessThan : groupNameGreaterThan); emit layoutChanged(); } Qt::DropActions CGroupList::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList CGroupList::mimeTypes() const { QStringList types; types << KFI_FONT_DRAG_MIME; return types; } CGroupListItem * CGroupList::find(const QString &name) { QList::ConstIterator it(itsGroups.begin()), end(itsGroups.end()); for(; it!=end; ++it) if((*it)->name()==name) return (*it); - return NULL; + return nullptr; } bool CGroupList::exists(const QString &name, bool showDialog) { - if(NULL!=find(name)) + if(nullptr!=find(name)) { if(showDialog) KMessageBox::error(itsParent, i18n("A group named \'%1\' already " "exists.", name)); return true; } return false; } class CGroupListViewDelegate : public QStyledItemDelegate { public: CGroupListViewDelegate(QObject *p) : QStyledItemDelegate(p) { } ~CGroupListViewDelegate() override { } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const override { CGroupListItem *grp=static_cast(idx.internalPointer()); QStyleOptionViewItem opt(option); if(grp && grp->isUnclassified()) opt.rect.adjust(0, 0, 0, -1); QStyledItemDelegate::paint(painter, opt, idx); if(grp && grp->isUnclassified()) { opt.rect.adjust(2, 0, -2, 1); painter->setPen(QApplication::palette().color(QPalette::Text)); painter->drawLine(opt.rect.bottomLeft(), opt.rect.bottomRight()); } } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &idx) const override { QSize sz(QStyledItemDelegate::sizeHint(option, idx)); CGroupListItem *grp=static_cast(idx.internalPointer()); if(grp && grp->isUnclassified()) sz.setHeight(sz.height()+1); return sz; } static bool isCloseEvent(QKeyEvent *event) { return Qt::Key_Tab==event->key() || Qt::Key_Backtab==event->key() || Qt::Key_Enter==event->key() || Qt::Key_Return==event->key(); } bool eventFilter(QObject *editor, QEvent *event) override { if(editor && event && QEvent::KeyPress==event->type() && isCloseEvent(static_cast(event)) && qobject_cast(editor)) { QString text=static_cast(editor)->text().trimmed(); if(!text.isEmpty() && !static_cast(static_cast(parent())->model())->exists(text, false)) { emit commitData(static_cast(editor)); emit closeEditor(static_cast(editor)); return true; } } return false; } }; CGroupListView::CGroupListView(QWidget *parent, CGroupList *model) : QTreeView(parent) { setModel(model); setItemDelegate(new CGroupListViewDelegate(this)); sortByColumn(COL_GROUP_NAME, Qt::AscendingOrder); setSelectionMode(QAbstractItemView::SingleSelection); setSortingEnabled(true); setAllColumnsShowFocus(true); setAlternatingRowColors(true); setAcceptDrops(true); setDragDropMode(QAbstractItemView::DropOnly); setDropIndicatorShown(true); setDragEnabled(false); header()->setSortIndicatorShown(true); setRootIsDecorated(false); itsMenu=new QMenu(this); itsDeleteAct=itsMenu->addAction(QIcon::fromTheme("list-remove"), i18n("Remove"), this, SIGNAL(del())); itsMenu->addSeparator(); itsEnableAct=itsMenu->addAction(QIcon::fromTheme("enablefont"), i18n("Enable"), this, SIGNAL(enable())); itsDisableAct=itsMenu->addAction(QIcon::fromTheme("disablefont"), i18n("Disable"), this, SIGNAL(disable())); itsMenu->addSeparator(); itsRenameAct=itsMenu->addAction(QIcon::fromTheme("edit-rename"), i18n("Rename..."), this, SLOT(rename())); if(!Misc::app(KFI_PRINTER).isEmpty()) { itsMenu->addSeparator(); itsPrintAct=itsMenu->addAction(QIcon::fromTheme("document-print"), i18n("Print..."), this, SIGNAL(print())); } else itsPrintAct= nullptr; itsMenu->addSeparator(); itsExportAct=itsMenu->addAction(QIcon::fromTheme("document-export"), i18n("Export..."), this, SIGNAL(zip())); setWhatsThis(model->whatsThis()); header()->setWhatsThis(whatsThis()); connect(this, SIGNAL(addFamilies(QModelIndex,QSet)), model, SLOT(addToGroup(QModelIndex,QSet))); connect(this, SIGNAL(removeFamilies(QModelIndex,QSet)), model, SLOT(removeFromGroup(QModelIndex,QSet))); } CGroupListItem::EType CGroupListView::getType() { QModelIndexList selectedItems(selectedIndexes()); if(selectedItems.count() && selectedItems.last().isValid()) { CGroupListItem *grp=static_cast(selectedItems.last().internalPointer()); return grp->type(); } return CGroupListItem::ALL; } void CGroupListView::controlMenu(bool del, bool en, bool dis, bool p, bool exp) { itsDeleteAct->setEnabled(del); itsRenameAct->setEnabled(del); itsEnableAct->setEnabled(en); itsDisableAct->setEnabled(dis); if(itsPrintAct) itsPrintAct->setEnabled(p); itsExportAct->setEnabled(exp); } void CGroupListView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { QModelIndexList deselectedItems(deselected.indexes()); QAbstractItemView::selectionChanged(selected, deselected); QModelIndexList selectedItems(selectedIndexes()); if(0==selectedItems.count() && 1==deselectedItems.count()) selectionModel()->select(deselectedItems.last(), QItemSelectionModel::Select); else emit itemSelected(selectedItems.count() ? selectedItems.last() : QModelIndex()); } void CGroupListView::rename() { QModelIndex index(currentIndex()); if(index.isValid()) edit(index); } void CGroupListView::emitMoveFonts() { emit moveFonts(); } void CGroupListView::contextMenuEvent(QContextMenuEvent *ev) { if(indexAt(ev->pos()).isValid()) itsMenu->popup(ev->globalPos()); } void CGroupListView::dragEnterEvent(QDragEnterEvent *event) { if(event->mimeData()->hasFormat(KFI_FONT_DRAG_MIME)) event->acceptProposedAction(); } void CGroupListView::dragMoveEvent(QDragMoveEvent *event) { if(event->mimeData()->hasFormat(KFI_FONT_DRAG_MIME)) { QModelIndex index(indexAt(event->pos())); if(index.isValid()) { if(COL_GROUP_NAME!=index.column()) index=((CGroupList *)model())->createIdx(index.row(), COL_GROUP_NAME, index.internalPointer()); CGroupListItem *dest=static_cast(index.internalPointer()); CGroupListItem::EType type=getType(); if(dest) if(!selectedIndexes().contains(index)) { bool ok(true); if(dest->isCustom()) emit info(i18n("Add to \"%1\".", dest->name())); else if(CGroupListItem::CUSTOM==type && dest->isAll()) emit info(i18n("Remove from current group.")); else if(!Misc::root() && dest->isPersonal() && CGroupListItem::SYSTEM==type) emit info(i18n("Move to personal folder.")); else if(!Misc::root() && dest->isSystem() && CGroupListItem::PERSONAL==type) emit info(i18n("Move to system folder.")); else ok=false; if(ok) { drawHighlighter(index); event->acceptProposedAction(); return; } } } event->ignore(); drawHighlighter(QModelIndex()); emit info(QString()); } } void CGroupListView::dragLeaveEvent(QDragLeaveEvent *) { drawHighlighter(QModelIndex()); emit info(QString()); } void CGroupListView::dropEvent(QDropEvent *event) { emit info(QString()); drawHighlighter(QModelIndex()); if(event->mimeData()->hasFormat(KFI_FONT_DRAG_MIME)) { event->acceptProposedAction(); QSet families; QByteArray encodedData(event->mimeData()->data(KFI_FONT_DRAG_MIME)); QDataStream ds(&encodedData, QIODevice::ReadOnly); QModelIndex from(selectedIndexes().last()), to(indexAt(event->pos())); ds >> families; // Are we moving/copying, removing a font from the current group? if(to.isValid() && from.isValid()) { if( ((static_cast(from.internalPointer()))->isSystem() && (static_cast(to.internalPointer()))->isPersonal()) || ((static_cast(from.internalPointer()))->isPersonal() && (static_cast(to.internalPointer()))->isSystem())) QTimer::singleShot(0, this, SLOT(emitMoveFonts())); else if((static_cast(from.internalPointer()))->isCustom() && !(static_cast(to.internalPointer()))->isCustom()) emit removeFamilies(from, families); else emit addFamilies(to, families); } if(isUnclassified()) emit unclassifiedChanged(); } } void CGroupListView::drawHighlighter(const QModelIndex &idx) { if(itsCurrentDropItem!=idx) { ((CGroupList *)model())->update(itsCurrentDropItem, idx); itsCurrentDropItem=idx; } } bool CGroupListView::viewportEvent(QEvent *event) { executeDelayedItemsLayout(); return QTreeView::viewportEvent(event); } } diff --git a/kcms/kfontinst/kcmfontinst/JobRunner.cpp b/kcms/kfontinst/kcmfontinst/JobRunner.cpp index 5a70f8267..3326c291f 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")); } 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(0L) + itsTempDir(nullptr) { setModal(true); - if(NULL==parent && 0!=xid) + 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", NULL}, - *pfm[]={"pfm", "PFM", "Pfm", NULL}; + 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) qSort(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 "KCmFontInst.h" #include "KfiConstants.h" #include "PrintDialog.h" #include "FcEngine.h" #include "FontPreview.h" #include "FontsPackage.h" #include "Misc.h" #include "FontList.h" #include "DuplicatesDialog.h" #include "FontFilter.h" #include "PreviewSelectAction.h" #include "PreviewList.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 #define CFG_GROUP "Main Settings" #define CFG_PREVIEW_SPLITTER_SIZES "PreviewSplitterSizes" #define CFG_GROUP_SPLITTER_SIZES "GroupSplitterSizes" #define CFG_FONT_SIZE "FontSize" K_PLUGIN_FACTORY(FontInstallFactory, registerPlugin(); ) K_EXPORT_PLUGIN(FontInstallFactory("fontinst")) namespace KFI { static QString partialIcon(bool load=true) { QString name = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/kfi/partial.png"; if(Misc::fExists(name)) { if(!load) QFile::remove(name); } else if(load) { QString pth; QPixmap pix=KIconLoader::global()->loadIcon("dialog-ok", KIconLoader::Small, KIconLoader::SizeSmall, KIconLoader::DisabledState); pix.save(name, "PNG"); } return name; } class CPushButton : public QPushButton { public: CPushButton(const KGuiItem &item, QWidget *parent) : QPushButton(parent) { KGuiItem::assign(this, item); theirHeight=qMax(theirHeight, QPushButton::sizeHint().height()); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } QSize sizeHint() const override { QSize sh(QPushButton::sizeHint()); sh.setHeight(theirHeight); if(sh.width()addAppDir(KFI_NAME); KAboutData *about = new KAboutData(QStringLiteral("fontinst"), i18n("KDE Font Manager"), QStringLiteral("1.0"), QString(), KAboutLicense::GPL, i18n("(C) Craig Drummond, 2000 - 2009")); about->addAuthor(i18n("Craig Drummond"), i18n("Developer and maintainer"), QStringLiteral("craig@kde.org")); setAboutData(about); KConfigGroup cg(&itsConfig, CFG_GROUP); itsGroupSplitter=new QSplitter(this); itsGroupSplitter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); QWidget *groupWidget=new QWidget(itsGroupSplitter), *fontWidget=new QWidget(itsGroupSplitter); itsPreviewSplitter=new QSplitter(fontWidget); itsPreviewSplitter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); QWidget *toolbarWidget=new QWidget(this), *fontControlWidget=new QWidget(fontWidget); CToolBar *toolbar=new CToolBar(toolbarWidget); QGridLayout *groupsLayout=new QGridLayout(groupWidget); QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::TopToBottom, this), *toolbarLayout=new QBoxLayout(QBoxLayout::LeftToRight, toolbarWidget), *fontsLayout=new QBoxLayout(QBoxLayout::TopToBottom, fontWidget), *fontControlLayout=new QBoxLayout(QBoxLayout::LeftToRight, fontControlWidget); toolbarLayout->setMargin(0); mainLayout->setMargin(0); groupsLayout->setMargin(0); fontsLayout->setMargin(0); fontControlLayout->setMargin(0); // Toolbar... duplicateFontsAct=new QAction(QIcon::fromTheme("system-search"), i18n("Scan for Duplicate Fonts..."), this); // validateFontsAct=new QAction(QIcon::fromTheme("checkmark"), i18n("Validate Fonts..."), this); toolbar->addAction(duplicateFontsAct); // toolbar->addAction(validateFontsAct); toolbar->setToolButtonStyle(Qt::ToolButtonFollowStyle); itsFilter=new CFontFilter(toolbarWidget); // Details - Groups... itsGroupList=new CGroupList(groupWidget); itsGroupListView=new CGroupListView(groupWidget, itsGroupList); QPushButton *createGroup=new CPushButton(KGuiItem(QString(), "list-add", i18n("Create a new group")), groupWidget); itsDeleteGroupControl=new CPushButton(KGuiItem(QString(), "edit-delete", i18n("Remove group")), groupWidget); itsEnableGroupControl=new CPushButton(KGuiItem(QString(), "enablefont", i18n("Enable all disabled fonts in the current group")), groupWidget); itsDisableGroupControl=new CPushButton(KGuiItem(QString(), "disablefont", i18n("Disable all enabled fonts in the current group")), groupWidget); groupsLayout->addWidget(itsGroupListView, 0, 0, 1, 5); groupsLayout->addWidget(createGroup, 1, 0); groupsLayout->addWidget(itsDeleteGroupControl, 1, 1); groupsLayout->addWidget(itsEnableGroupControl, 1, 2); groupsLayout->addWidget(itsDisableGroupControl, 1, 3); groupsLayout->addItem(new QSpacerItem(itsDisableGroupControl->width(), groupsLayout->spacing(), QSizePolicy::Expanding, QSizePolicy::Fixed), 1, 4); itsPreviewWidget = new QWidget(this); QBoxLayout *previewWidgetLayout = new QBoxLayout(QBoxLayout::TopToBottom, itsPreviewWidget); previewWidgetLayout->setMargin(0); previewWidgetLayout->setSpacing(0); // Preview QFrame *previewFrame=new QFrame(itsPreviewWidget); QBoxLayout *previewFrameLayout=new QBoxLayout(QBoxLayout::LeftToRight, previewFrame); previewFrameLayout->setMargin(0); previewFrameLayout->setSpacing(0); previewFrame->setFrameShape(QFrame::StyledPanel); previewFrame->setFrameShadow(QFrame::Sunken); previewFrame->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); itsPreview=new CFontPreview(previewFrame); itsPreview->setWhatsThis(i18n("This displays a preview of the selected font.")); itsPreview->setContextMenuPolicy(Qt::CustomContextMenu); previewFrameLayout->addWidget(itsPreview); previewWidgetLayout->addWidget(previewFrame); itsPreview->engine()->readConfig(itsConfig); // List-style preview... itsPreviewList = new CPreviewListView(itsPreview->engine(), itsPreviewWidget); previewWidgetLayout->addWidget(itsPreviewList); itsPreviewList->setVisible(false); // Font List... itsFontList=new CFontList(fontWidget); itsFontListView=new CFontListView(itsPreviewSplitter, itsFontList); itsFontListView->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); itsAddFontControl=new CPushButton(KGuiItem(i18n("Install from File..."), "document-import", i18n("Install fonts from a local file")), fontControlWidget); itsGetNewFontsControl=new CPushButton(KGuiItem(i18n("Get New Fonts..."), "get-hot-new-stuff", i18n("Download new fonts")), fontControlWidget); itsDeleteFontControl=new CPushButton(KGuiItem(i18n("Delete"), "edit-delete", i18n("Delete all selected fonts")), fontControlWidget); itsPreviewSplitter->addWidget(itsPreviewWidget); itsPreviewSplitter->setCollapsible(1, true); itsStatusLabel = new QLabel(fontControlWidget); itsStatusLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight); itsListingProgress=new CProgressBar(fontControlWidget, itsStatusLabel->height()); itsListingProgress->setRange(0, 100); // Layout widgets... toolbarLayout->addWidget(toolbar); toolbarLayout->addItem(new QSpacerItem(toolbarLayout->spacing(), 2, QSizePolicy::MinimumExpanding, QSizePolicy::Fixed)); toolbarLayout->addWidget(itsFilter); mainLayout->addWidget(toolbarWidget); mainLayout->addWidget(itsGroupSplitter); fontControlLayout->addWidget(itsDeleteFontControl); fontControlLayout->addWidget(itsStatusLabel); fontControlLayout->addItem(new QSpacerItem(0, itsListingProgress->height()+4, QSizePolicy::Fixed, QSizePolicy::Fixed)); fontControlLayout->addWidget(itsListingProgress); fontControlLayout->addWidget(itsAddFontControl); fontControlLayout->addWidget(itsGetNewFontsControl); fontsLayout->addWidget(itsPreviewSplitter); fontsLayout->addWidget(fontControlWidget); // Set size of widgets... itsPreviewSplitter->setChildrenCollapsible(false); itsGroupSplitter->setChildrenCollapsible(false); itsGroupSplitter->setStretchFactor(0, 0); itsGroupSplitter->setStretchFactor(1, 1); itsPreviewSplitter->setStretchFactor(0, 1); itsPreviewSplitter->setStretchFactor(1, 0); // Set sizes for 3 views... QList defaultSizes; defaultSizes+=300; defaultSizes+=220; itsPreviewSplitter->setSizes(cg.readEntry(CFG_PREVIEW_SPLITTER_SIZES, defaultSizes)); itsPreviewHidden=itsPreviewSplitter->sizes().at(1)<8; defaultSizes.clear(); defaultSizes+=110; defaultSizes+=350; itsGroupSplitter->setSizes(cg.readEntry(CFG_GROUP_SPLITTER_SIZES, defaultSizes)); // Preview widget pop-up menu itsPreviewMenu = new QMenu(itsPreview); QAction *zoomIn=KStandardAction::create(KStandardAction::ZoomIn, itsPreview, SLOT(zoomIn()), this), *zoomOut=KStandardAction::create(KStandardAction::ZoomOut, itsPreview, SLOT(zoomOut()), this); itsPreviewMenu->addAction(zoomIn); itsPreviewMenu->addAction(zoomOut); itsPreviewMenu->addSeparator(); CPreviewSelectAction *prevSel=new CPreviewSelectAction(itsPreviewMenu); itsPreviewMenu->addAction(prevSel); QAction *changeTextAct=new QAction(QIcon::fromTheme("edit-rename"), i18n("Change Preview Text..."), this); itsPreviewMenu->addAction(changeTextAct), itsPreviewListMenu = new QMenu(itsPreviewList); itsPreviewListMenu->addAction(changeTextAct), // Connect signals... connect(itsPreview, SIGNAL(atMax(bool)), zoomIn, SLOT(setDisabled(bool))); connect(itsPreview, SIGNAL(atMin(bool)), zoomOut, SLOT(setDisabled(bool))); connect(prevSel, SIGNAL(range(QList)), itsPreview, SLOT(setUnicodeRange(QList))); connect(changeTextAct, SIGNAL(triggered(bool)), SLOT(changeText())); connect(itsFilter, SIGNAL(textChanged(QString)), itsFontListView, SLOT(filterText(QString))); connect(itsFilter, SIGNAL(criteriaChanged(int,qulonglong,QStringList)), itsFontListView, SLOT(filterCriteria(int,qulonglong,QStringList))); connect(itsGroupListView, SIGNAL(del()), SLOT(removeGroup())); connect(itsGroupListView, SIGNAL(print()), SLOT(printGroup())); connect(itsGroupListView, SIGNAL(enable()), SLOT(enableGroup())); connect(itsGroupListView, SIGNAL(disable()), SLOT(disableGroup())); connect(itsGroupListView, SIGNAL(moveFonts()), SLOT(moveFonts())); connect(itsGroupListView, SIGNAL(zip()), SLOT(zipGroup())); connect(itsGroupListView, SIGNAL(itemSelected(QModelIndex)), SLOT(groupSelected(QModelIndex))); connect(itsGroupListView, SIGNAL(info(QString)), SLOT(showInfo(QString))); connect(itsGroupList, SIGNAL(refresh()), SLOT(refreshFontList())); connect(itsFontList, SIGNAL(listingPercent(int)), SLOT(listingPercent(int))); connect(itsFontList, SIGNAL(layoutChanged()), SLOT(setStatusBar())); connect(itsFontListView, SIGNAL(del()), SLOT(deleteFonts())); connect(itsFontListView, SIGNAL(print()), SLOT(print())); connect(itsFontListView, SIGNAL(enable()), SLOT(enableFonts())); connect(itsFontListView, SIGNAL(disable()), SLOT(disableFonts())); connect(itsFontListView, SIGNAL(fontsDropped(QSet)), SLOT(addFonts(QSet))); connect(itsFontListView, SIGNAL(itemsSelected(QModelIndexList)), SLOT(fontsSelected(QModelIndexList))); connect(itsFontListView, SIGNAL(refresh()), SLOT(setStatusBar())); connect(itsGroupListView, SIGNAL(unclassifiedChanged()), itsFontListView, SLOT(refreshFilter())); connect(createGroup, SIGNAL(clicked()), SLOT(addGroup())); connect(itsDeleteGroupControl, SIGNAL(clicked()), SLOT(removeGroup())); connect(itsEnableGroupControl, SIGNAL(clicked()), SLOT(enableGroup())); connect(itsDisableGroupControl, SIGNAL(clicked()), SLOT(disableGroup())); connect(itsAddFontControl, SIGNAL(clicked()), SLOT(addFonts())); connect(itsGetNewFontsControl, SIGNAL(clicked()), SLOT(downloadFonts())); connect(itsDeleteFontControl, SIGNAL(clicked()), SLOT(deleteFonts())); connect(duplicateFontsAct, SIGNAL(triggered(bool)), SLOT(duplicateFonts())); //connect(validateFontsAct, SIGNAL(triggered(bool)), SLOT(validateFonts())); connect(itsPreview, SIGNAL(customContextMenuRequested(QPoint)), SLOT(previewMenu(QPoint))); connect(itsPreviewList, SIGNAL(showMenu(QPoint)), SLOT(previewMenu(QPoint))); connect(itsPreviewSplitter, SIGNAL(splitterMoved(int,int)), SLOT(splitterMoved())); selectMainGroup(); itsFontList->load(); } CKCmFontInst::~CKCmFontInst() { KConfigGroup cg(&itsConfig, CFG_GROUP); cg.writeEntry(CFG_PREVIEW_SPLITTER_SIZES, itsPreviewSplitter->sizes()); cg.writeEntry(CFG_GROUP_SPLITTER_SIZES, itsGroupSplitter->sizes()); delete itsTempDir; partialIcon(false); } QString CKCmFontInst::quickHelp() const { return Misc::root() ? i18n("

    Font Installer

    This module allows you to" " install TrueType, Type1, and Bitmap" " fonts.

    You may also install fonts using Konqueror:" " type fonts:/ into Konqueror's location bar" " and this will display your installed fonts. To install a" " font, simply copy one into the folder.

    ") : i18n("

    Font Installer

    This module allows you to" " install TrueType, Type1, and Bitmap" " fonts.

    You may also install fonts using Konqueror:" " type fonts:/ into Konqueror's location bar" " and this will display your installed fonts. To install a" " font, simply copy it into the appropriate folder - " " \"%1\" for fonts available to just yourself, or " " \"%2\" for system-wide fonts (available to all).

    ", i18n(KFI_KIO_FONTS_USER), i18n(KFI_KIO_FONTS_SYS)); } void CKCmFontInst::previewMenu(const QPoint &pos) { if(itsPreviewList->isHidden()) itsPreviewMenu->popup(itsPreview->mapToGlobal(pos)); else itsPreviewListMenu->popup(itsPreviewList->mapToGlobal(pos)); } void CKCmFontInst::splitterMoved() { if(itsPreviewWidget->width()>8 && itsPreviewHidden) { itsPreviewHidden=false; fontsSelected(itsFontListView->getSelectedItems()); } else if(!itsPreviewHidden && itsPreviewWidget->width()<8) itsPreviewHidden=true; } void CKCmFontInst::fontsSelected(const QModelIndexList &list) { if(!itsPreviewHidden) { if(list.count()) { if(list.count()<2) { CFontModelItem *mi=static_cast(list.last().internalPointer()); CFontItem *font=mi->parent() ? static_cast(mi) : (static_cast(mi))->regularFont(); if(font) itsPreview->showFont(font->isEnabled() ? font->family() : font->fileName(), font->styleInfo(), font->index()); } else itsPreviewList->showFonts(list); } itsPreviewList->setVisible(list.count()>1); itsPreview->parentWidget()->setVisible(list.count()<2); } itsDeleteFontControl->setEnabled(list.count()); } void CKCmFontInst::addFonts() { QFileDialog dlg(this, i18n("Add Fonts")); dlg.setFileMode(QFileDialog::ExistingFiles); dlg.setMimeTypeFilters(CFontList::fontMimeTypes); QList list; if (dlg.exec() == QDialog::Accepted) list = dlg.selectedUrls(); if(list.count()) { QSet urls; QList::Iterator it(list.begin()), end(list.end()); for(; it!=end; ++it) { if(KFI_KIO_FONTS_PROTOCOL!=(*it).scheme()) // Do not try to install from fonts:/ !!! { auto job = KIO::mostLocalUrl(*it); KJobWidgets::setWindow(job, this); job->exec(); QUrl url = job->mostLocalUrl(); if(url.isLocalFile()) { QString file(url.toLocalFile()); if(Misc::isPackage(file)) // If its a package we need to unzip 1st... urls+=FontsPackage::extract(url.toLocalFile(), &itsTempDir); else if(!Misc::isMetrics(url)) urls.insert(url); } else if(!Misc::isMetrics(url)) urls.insert(url); } } if(urls.count()) addFonts(urls); delete itsTempDir; - itsTempDir=NULL; + itsTempDir=nullptr; } } void CKCmFontInst::groupSelected(const QModelIndex &index) { - CGroupListItem *grp=NULL; + CGroupListItem *grp=nullptr; if(index.isValid()) grp=static_cast(index.internalPointer()); else return; itsFontListView->setFilterGroup(grp); setStatusBar(); // // Check fonts listed within group are still valid! if(grp->isCustom() && !grp->validated()) { QSet remList; QSet::Iterator it(grp->families().begin()), end(grp->families().end()); for(; it!=end; ++it) if(!itsFontList->hasFamily(*it)) remList.insert(*it); it=remList.begin(); end=remList.end(); for(; it!=end; ++it) itsGroupList->removeFromGroup(grp, *it); grp->setValidated(); } itsGetNewFontsControl->setEnabled(grp->isPersonal() || grp->isAll()); } void CKCmFontInst::print(bool all) { // // In order to support printing of newly installed/enabled fonts, the actual printing // is carried out by the kfontinst helper app. This way we know Qt's font list will be // up to date. if((!itsPrintProc || QProcess::NotRunning==itsPrintProc->state()) && !Misc::app(KFI_PRINTER).isEmpty()) { QSet fonts; itsFontListView->getPrintableFonts(fonts, !all); if(fonts.count()) { CPrintDialog dlg(this); KConfigGroup cg(&itsConfig, CFG_GROUP); if(dlg.exec(cg.readEntry(CFG_FONT_SIZE, 1))) { static const int constSizes[]={0, 12, 18, 24, 36, 48}; QSet::ConstIterator it(fonts.begin()), end(fonts.end()); QTemporaryFile tmpFile; bool useFile(fonts.count()>16), startProc(true); QStringList args; if(!itsPrintProc) itsPrintProc=new QProcess(this); else itsPrintProc->kill(); QString title = QGuiApplication::applicationDisplayName(); if (title.isEmpty()) title = QCoreApplication::applicationName(); // // If we have lots of fonts to print, pass kfontinst a temporary groups file to print // instead of passing font by font... if(useFile) { if(tmpFile.open()) { QTextStream str(&tmpFile); for(; it!=end; ++it) str << (*it).family << endl << (*it).styleInfo << endl; args << "--embed" << QString().sprintf("0x%x", (unsigned int)window()->winId()) << "--qwindowtitle" << title << "--qwindowicon" << "preferences-desktop-font-installer" << "--size" << QString().setNum(constSizes[dlg.chosenSize() < 6 ? dlg.chosenSize() : 2]) << "--listfile" << tmpFile.fileName() << "--deletefile"; } else { KMessageBox::error(this, i18n("Failed to save list of fonts to print.")); startProc=false; } } else { args << "--embed" << QString().sprintf("0x%x", (unsigned int)window()->winId()) << "--qwindowtitle" << title << "--qwindowicon" << "preferences-desktop-font-installer" << "--size" << QString().setNum(constSizes[dlg.chosenSize()<6 ? dlg.chosenSize() : 2]); for(; it!=end; ++it) args << "--pfont" << QString((*it).family.toUtf8()+','+QString().setNum((*it).styleInfo)); } if(startProc) { itsPrintProc->start(Misc::app(KFI_PRINTER), args); if(itsPrintProc->waitForStarted(1000)) { if(useFile) tmpFile.setAutoRemove(false); } else KMessageBox::error(this, i18n("Failed to start font printer.")); } cg.writeEntry(CFG_FONT_SIZE, dlg.chosenSize()); } } else KMessageBox::information(this, i18n("There are no printable fonts.\n" "You can only print non-bitmap and enabled fonts."), i18n("Cannot Print")); } } void CKCmFontInst::deleteFonts() { CJobRunner::ItemList urls; QStringList fontNames; QSet fonts; itsDeletedFonts.clear(); itsFontListView->getFonts(urls, fontNames, &fonts, true); if(urls.isEmpty()) KMessageBox::information(this, i18n("You did not select anything to delete."), i18n("Nothing to Delete")); else { QSet::ConstIterator it(fonts.begin()), end(fonts.end()); bool doIt=false; for(; it!=end; ++it) itsDeletedFonts.insert((*it).family); switch(fontNames.count()) { case 0: break; case 1: doIt = KMessageBox::Yes==KMessageBox::warningYesNo(this, i18n("

    Do you really want to " "delete

    \'%1\'?

    ", fontNames.first()), i18n("Delete Font"), KStandardGuiItem::del()); break; default: doIt = KMessageBox::Yes==KMessageBox::warningYesNoList(this, i18np("Do you really want to delete this font?", "Do you really want to delete these %1 fonts?", fontNames.count()), fontNames, i18n("Delete Fonts"), KStandardGuiItem::del()); } if(doIt) { itsStatusLabel->setText(i18n("Deleting font(s)...")); doCmd(CJobRunner::CMD_DELETE, urls); } } } void CKCmFontInst::moveFonts() { CJobRunner::ItemList urls; QStringList fontNames; itsDeletedFonts.clear(); - itsFontListView->getFonts(urls, fontNames, NULL, true); + itsFontListView->getFonts(urls, fontNames, nullptr, true); if(urls.isEmpty()) KMessageBox::information(this, i18n("You did not select anything to move."), i18n("Nothing to Move")); else { bool doIt=false; switch(fontNames.count()) { case 0: break; case 1: doIt = KMessageBox::Yes==KMessageBox::warningYesNo(this, i18n("

    Do you really want to " "move

    \'%1\'

    from %2 to %3?

    ", fontNames.first(), itsGroupListView->isSystem() ? i18n(KFI_KIO_FONTS_SYS) : i18n(KFI_KIO_FONTS_USER), itsGroupListView->isSystem() ? i18n(KFI_KIO_FONTS_USER) : i18n(KFI_KIO_FONTS_SYS)), i18n("Move Font"), KGuiItem(i18n("Move"))); break; default: doIt = KMessageBox::Yes==KMessageBox::warningYesNoList(this, i18np("

    Do you really want to move this font from %2 to %3?

    ", "

    Do you really want to move these %1 fonts from %2 to %3?

    ", fontNames.count(), itsGroupListView->isSystem() ? i18n(KFI_KIO_FONTS_SYS) : i18n(KFI_KIO_FONTS_USER), itsGroupListView->isSystem() ? i18n(KFI_KIO_FONTS_USER) : i18n(KFI_KIO_FONTS_SYS)), fontNames, i18n("Move Fonts"), KGuiItem(i18n("Move"))); } if(doIt) { itsStatusLabel->setText(i18n("Moving font(s)...")); doCmd(CJobRunner::CMD_MOVE, urls, !itsGroupListView->isSystem()); } } } void CKCmFontInst::zipGroup() { QModelIndex idx(itsGroupListView->currentIndex()); if(idx.isValid()) { CGroupListItem *grp=static_cast(idx.internalPointer()); if(grp) { QFileDialog dlg(this, i18n("Export Group")); dlg.setAcceptMode(QFileDialog::AcceptSave); dlg.setDirectoryUrl(QUrl::fromLocalFile(grp->name())); dlg.setMimeTypeFilters(QStringList() << QStringLiteral("application/zip")); QString fileName; if (dlg.exec() == QDialog::Accepted) fileName = dlg.selectedFiles().value(0); if(!fileName.isEmpty()) { KZip zip(fileName); if(zip.open(QIODevice::WriteOnly)) { QSet files; files=itsFontListView->getFiles(); if(files.count()) { QMap map=Misc::getFontFileMap(files); QMap::ConstIterator it(map.constBegin()), end(map.constEnd()); for(; it!=end; ++it) zip.addLocalFile(it.value(), it.key()); zip.close(); } else KMessageBox::error(this, i18n("No files?")); } else KMessageBox::error(this, i18n("Failed to open %1 for writing", fileName)); } } } } void CKCmFontInst::enableFonts() { toggleFonts(true); } void CKCmFontInst::disableFonts() { toggleFonts(false); } void CKCmFontInst::addGroup() { bool ok; QString name(QInputDialog::getText(this, i18n("Create New Group"), i18n("Please enter the name of the new group:"), QLineEdit::Normal, i18n("New Group"), &ok)); if(ok && !name.isEmpty()) itsGroupList->createGroup(name); } void CKCmFontInst::removeGroup() { if(itsGroupList->removeGroup(itsGroupListView->currentIndex())) selectMainGroup(); } void CKCmFontInst::enableGroup() { toggleGroup(true); } void CKCmFontInst::disableGroup() { toggleGroup(false); } void CKCmFontInst::changeText() { bool status; QString oldStr(itsPreview->engine()->getPreviewString()), newStr(QInputDialog::getText(this, i18n("Preview Text"), i18n("Please enter new text:"), QLineEdit::Normal, oldStr, &status)); if(status && oldStr!=newStr) { itsPreview->engine()->setPreviewString(newStr); itsPreview->showFont(); itsPreviewList->refreshPreviews(); } } void CKCmFontInst::duplicateFonts() { CDuplicatesDialog(this, itsFontList).exec(); } //void CKCmFontInst::validateFonts() //{ //} void CKCmFontInst::downloadFonts() { KNS3::DownloadDialog *newStuff = new KNS3::DownloadDialog("kfontinst.knsrc", this); newStuff->exec(); if(newStuff->changedEntries().count()) // We have new fonts, so need to reconfigure fontconfig... { // Ask dbus helper for the current fonts folder name... // We then sym-link our knewstuff3 download folder into the fonts folder... QString destFolder=CJobRunner::folderName(false); if(!destFolder.isEmpty()) { destFolder+="kfontinst"; if(!QFile::exists(destFolder)) { QFile _file(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "kfontinst"); _file.link(destFolder); } } doCmd(CJobRunner::CMD_UPDATE, CJobRunner::ItemList()); } delete newStuff; } void CKCmFontInst::print() { print(false); } void CKCmFontInst::printGroup() { print(true); } void CKCmFontInst::listingPercent(int p) { if(0==p) { showInfo(i18n("Scanning font list...")); itsListingProgress->show(); } else if(100==p && p!=itsListingProgress->value()) { removeDeletedFontsFromGroups(); QSet foundries; itsFontList->getFoundries(foundries); itsFilter->setFoundries(foundries); refreshFamilies(); itsListingProgress->hide(); itsFontListView->selectFirstFont(); } itsListingProgress->setValue(p); } void CKCmFontInst::refreshFontList() { itsFontListView->refreshFilter(); refreshFamilies(); } void CKCmFontInst::refreshFamilies() { QSet enabledFamilies, disabledFamilies, partialFamilies; itsFontList->getFamilyStats(enabledFamilies, disabledFamilies, partialFamilies); itsGroupList->updateStatus(enabledFamilies, disabledFamilies, partialFamilies); setStatusBar(); } void CKCmFontInst::showInfo(const QString &info) { if(info.isEmpty()) if(itsLastStatusBarMsg.isEmpty()) setStatusBar(); else { itsStatusLabel->setText(itsLastStatusBarMsg); itsLastStatusBarMsg=QString(); } else { if(itsLastStatusBarMsg.isEmpty()) itsLastStatusBarMsg=itsStatusLabel->text(); itsStatusLabel->setText(info); } } void CKCmFontInst::setStatusBar() { if(itsFontList->slowUpdates()) return; int enabled=0, disabled=0, partial=0; bool selectedEnabled=false, selectedDisabled=false; itsStatusLabel->setToolTip(QString()); if(0==itsFontList->families().count()) itsStatusLabel->setText(i18n("No fonts")); else { itsFontListView->stats(enabled, disabled, partial); itsFontListView->selectedStatus(selectedEnabled, selectedDisabled); QString text(i18np("1 Font", "%1 Fonts", enabled+disabled+partial)); if(disabled||partial) { text+=QString(" (%2").arg(KIconLoader::global()->iconPath("dialog-ok", -KIconLoader::SizeSmall)).arg(enabled) +QString(" %2").arg(KIconLoader::global()->iconPath("dialog-cancel", -KIconLoader::SizeSmall)).arg(disabled); if(partial) text+=QString(" %2").arg(partialIcon()).arg(partial); text+=QLatin1Char(')'); itsStatusLabel->setToolTip(partial ? i18n("" "" "" "" "" "
    Enabled:%1
    Disabled:%2
    Partially enabled:%3
    Total:%4
    ", enabled, disabled, partial, enabled+disabled+partial) : i18n("" "" "" "" "
    Enabled:%1
    Disabled:%2
    Total:%3
    ", enabled, disabled, enabled+disabled)); } itsStatusLabel->setText(disabled||partial ? "

    "+text+"

    " : text); } CGroupListItem::EType type(itsGroupListView->getType()); bool isStd(CGroupListItem::CUSTOM==type); itsAddFontControl->setEnabled(CGroupListItem::ALL==type||CGroupListItem::UNCLASSIFIED==type|| CGroupListItem::PERSONAL==type||CGroupListItem::SYSTEM==type); itsDeleteGroupControl->setEnabled(isStd); itsEnableGroupControl->setEnabled(disabled||partial); itsDisableGroupControl->setEnabled(isStd && (enabled||partial)); itsGroupListView->controlMenu(itsDeleteGroupControl->isEnabled(), itsEnableGroupControl->isEnabled(), itsDisableGroupControl->isEnabled(), enabled||partial, enabled||disabled); itsDeleteFontControl->setEnabled(selectedEnabled||selectedDisabled); } void CKCmFontInst::addFonts(const QSet &src) { if(src.count() && !itsGroupListView->isCustom()) { bool system; if(Misc::root()) system=true; else { switch(itsGroupListView->getType()) { case CGroupListItem::ALL: case CGroupListItem::UNCLASSIFIED: switch(KMessageBox::questionYesNoCancel(this, i18n("Do you wish to install the font(s) for personal use " "(only available to you), or " "system-wide (available to all users)?"), i18n("Where to Install"), KGuiItem(i18n(KFI_KIO_FONTS_USER)), KGuiItem(i18n(KFI_KIO_FONTS_SYS)))) { case KMessageBox::Yes: system=false; break; case KMessageBox::No: system=true; break; default: case KMessageBox::Cancel: return; } break; case CGroupListItem::PERSONAL: system=false; break; case CGroupListItem::SYSTEM: system=true; break; default: return; } } QSet copy; QSet::ConstIterator it, end(src.end()); // // Check if font has any associated AFM or PFM file... itsStatusLabel->setText(i18n("Looking for any associated files...")); if(!itsProgress) { itsProgress = new QProgressDialog(this); itsProgress->setWindowTitle(i18n("Scanning Files...")); itsProgress->setLabelText(i18n("Looking for additional files to install...")); itsProgress->setModal(true); itsProgress->setAutoReset(true); itsProgress->setAutoClose(true); } - itsProgress->setCancelButton(0); + itsProgress->setCancelButton(nullptr); itsProgress->setMinimumDuration(500); itsProgress->setRange(0, src.size()); itsProgress->setValue(0); int steps=src.count()<200 ? 1 : src.count()/10; for(it=src.begin(); it!=end; ++it) { QList associatedUrls; itsProgress->setLabelText(i18n("Looking for files associated with %1", (*it).url())); itsProgress->setValue(itsProgress->value()+1); if(1==steps || 0==(itsProgress->value()%steps)) { bool dialogVisible(itsProgress->isVisible()); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); if(dialogVisible && !itsProgress->isVisible()) // User closed dialog! re-open!!! itsProgress->show(); } CJobRunner::getAssociatedUrls(*it, associatedUrls, false, this); copy.insert(*it); QList::Iterator aIt(associatedUrls.begin()), aEnd(associatedUrls.end()); for(; aIt!=aEnd; ++aIt) copy.insert(*aIt); } itsProgress->close(); CJobRunner::ItemList installUrls; end=copy.end(); for(it=copy.begin(); it!=end; ++it) installUrls.append(*it); itsStatusLabel->setText(i18n("Installing font(s)...")); doCmd(CJobRunner::CMD_INSTALL, installUrls, system); } } void CKCmFontInst::removeDeletedFontsFromGroups() { if(itsDeletedFonts.count()) { QSet::Iterator it(itsDeletedFonts.begin()), end(itsDeletedFonts.end()); for(; it!=end; ++it) if(!itsFontList->hasFamily(*it)) itsGroupList->removeFamily(*it); itsDeletedFonts.clear(); } } void CKCmFontInst::selectGroup(CGroupListItem::EType grp) { QModelIndex current(itsGroupListView->currentIndex()); if(current.isValid()) { CGroupListItem *grpItem=static_cast(current.internalPointer()); if(grpItem && grp==grpItem->type()) return; else itsGroupListView->selectionModel()->select(current, QItemSelectionModel::Deselect); } QModelIndex idx(itsGroupList->index(grp)); itsGroupListView->selectionModel()->select(idx, QItemSelectionModel::Select); itsGroupListView->setCurrentIndex(idx); groupSelected(idx); itsFontListView->refreshFilter(); setStatusBar(); } void CKCmFontInst::toggleGroup(bool enable) { QModelIndex idx(itsGroupListView->currentIndex()); if(idx.isValid()) { CGroupListItem *grp=static_cast(idx.internalPointer()); if(grp) toggleFonts(enable, grp->name()); } } void CKCmFontInst::toggleFonts(bool enable, const QString &grp) { CJobRunner::ItemList urls; QStringList fonts; - itsFontListView->getFonts(urls, fonts, NULL, grp.isEmpty(), !enable, enable); + itsFontListView->getFonts(urls, fonts, nullptr, grp.isEmpty(), !enable, enable); if(urls.isEmpty()) KMessageBox::information(this, enable ? i18n("You did not select anything to enable.") : i18n("You did not select anything to disable."), enable ? i18n("Nothing to Enable") : i18n("Nothing to Disable")); else toggleFonts(urls, fonts, enable, grp); } void CKCmFontInst::toggleFonts(CJobRunner::ItemList &urls, const QStringList &fonts, bool enable, const QString &grp) { bool doIt=false; switch(fonts.count()) { case 0: break; case 1: doIt = KMessageBox::Yes==KMessageBox::warningYesNo(this, grp.isEmpty() ? enable ? i18n("

    Do you really want to " "enable

    \'%1\'?

    ", fonts.first()) : i18n("

    Do you really want to " "disable

    \'%1\'?

    ", fonts.first()) : enable ? i18n("

    Do you really want to " "enable

    \'%1\', " "contained within group \'%2\'?

    ", fonts.first(), grp) : i18n("

    Do you really want to " "disable

    \'%1\', " "contained within group \'%2\'?

    ", fonts.first(), grp), enable ? i18n("Enable Font") : i18n("Disable Font"), enable ? KGuiItem(i18n("Enable"), "enablefont", i18n("Enable Font")) : KGuiItem(i18n("Disable"), "disablefont", i18n("Disable Font"))); break; default: doIt = KMessageBox::Yes==KMessageBox::warningYesNoList(this, grp.isEmpty() ? enable ? i18np("Do you really want to enable this font?", "Do you really want to enable these %1 fonts?", urls.count()) : i18np("Do you really want to disable this font?", "Do you really want to disable these %1 fonts?", urls.count()) : enable ? i18np("

    Do you really want to enable this font " "contained within group \'%2\'?

    ", "

    Do you really want to enable these %1 fonts " "contained within group \'%2\'?

    ", urls.count(), grp) : i18np("

    Do you really want to disable this font " "contained within group \'%2\'?

    ", "

    Do you really want to disable these %1 fonts " "contained within group \'%2\'?

    ", urls.count(), grp), fonts, enable ? i18n("Enable Fonts") : i18n("Disable Fonts"), enable ? KGuiItem(i18n("Enable"), "enablefont", i18n("Enable Fonts")) : KGuiItem(i18n("Disable"), "disablefont", i18n("Disable Fonts"))); } if(doIt) { if(enable) itsStatusLabel->setText(i18n("Enabling font(s)...")); else itsStatusLabel->setText(i18n("Disabling font(s)...")); doCmd(enable ? CJobRunner::CMD_ENABLE : CJobRunner::CMD_DISABLE, urls); } } void CKCmFontInst::selectMainGroup() { selectGroup(/*Misc::root() ? */CGroupListItem::ALL/* : CGroupListItem::PERSONAL*/); } void CKCmFontInst::doCmd(CJobRunner::ECommand cmd, const CJobRunner::ItemList &urls, bool system) { itsFontList->setSlowUpdates(true); CJobRunner runner(this); connect(&runner, SIGNAL(configuring()), itsFontList, SLOT(unsetSlowUpdates())); runner.exec(cmd, urls, system); itsFontList->setSlowUpdates(false); refreshFontList(); if(CJobRunner::CMD_DELETE==cmd) itsFontListView->clearSelection(); CFcEngine::setDirty(); setStatusBar(); delete itsTempDir; - itsTempDir=NULL; + itsTempDir=nullptr; itsFontListView->repaint(); removeDeletedFontsFromGroups(); } } #include "KCmFontInst.moc" diff --git a/kcms/kfontinst/kcmfontinst/KCmFontInst.h b/kcms/kfontinst/kcmfontinst/KCmFontInst.h index 5c5e01d37..04cd3123a 100644 --- a/kcms/kfontinst/kcmfontinst/KCmFontInst.h +++ b/kcms/kfontinst/kcmfontinst/KCmFontInst.h @@ -1,145 +1,145 @@ #ifndef __KCM_FONT_INST_H__ #define __KCM_FONT_INST_H__ /* * 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 "GroupList.h" #include "JobRunner.h" #include #include #include #include #include class QPushButton; class QProgressDialog; class QTemporaryDir; class KToggleAction; class KActionMenu; class QAction; class QLabel; class QMenu; class QProcess; class QSplitter; class QComboBox; namespace KFI { class CFontFilter; class CFontList; class CFontPreview; class CUpdateDialog; class CFontListView; class CProgressBar; class CPreviewListView; class CKCmFontInst : public KCModule { Q_OBJECT public: - explicit CKCmFontInst(QWidget *parent=NULL, const QVariantList &list=QVariantList()); + explicit CKCmFontInst(QWidget *parent=nullptr, const QVariantList &list=QVariantList()); ~CKCmFontInst() override; public Q_SLOTS: QString quickHelp() const override; void previewMenu(const QPoint &pos); void splitterMoved(); void fontsSelected(const QModelIndexList &list); void groupSelected(const QModelIndex &index); void addFonts(); void deleteFonts(); void moveFonts(); void zipGroup(); void enableFonts(); void disableFonts(); void addGroup(); void removeGroup(); void enableGroup(); void disableGroup(); void changeText(); void duplicateFonts(); void downloadFonts(); void print(); void printGroup(); void listingPercent(int p); void refreshFontList(); void refreshFamilies(); void showInfo(const QString &info); void setStatusBar(); void addFonts(const QSet &src); private: void removeDeletedFontsFromGroups(); void selectGroup(CGroupListItem::EType grp); void print(bool all); void toggleGroup(bool enable); void toggleFonts(bool enable, const QString &grp=QString()); void toggleFonts(CJobRunner::ItemList &urls, const QStringList &fonts, bool enable, const QString &grp); void selectMainGroup(); void doCmd(CJobRunner::ECommand cmd, const CJobRunner::ItemList &urls, bool system=false); private: QSplitter *itsGroupSplitter, *itsPreviewSplitter; CFontPreview *itsPreview; CPreviewListView *itsPreviewList; KConfig itsConfig; QLabel *itsStatusLabel; CProgressBar *itsListingProgress; CFontList *itsFontList; CFontListView *itsFontListView; CGroupList *itsGroupList; CGroupListView *itsGroupListView; QPushButton *itsDeleteGroupControl, *itsEnableGroupControl, *itsDisableGroupControl, *itsAddFontControl, *itsGetNewFontsControl, *itsDeleteFontControl; CFontFilter *itsFilter; QString itsLastStatusBarMsg; KIO::Job *itsJob; QProgressDialog *itsProgress; CUpdateDialog *itsUpdateDialog; QTemporaryDir *itsTempDir; QProcess *itsPrintProc; QSet itsDeletedFonts; QList itsModifiedUrls; CJobRunner *itsRunner; QMenu *itsPreviewMenu, *itsPreviewListMenu; QAction *duplicateFontsAct; QWidget *itsPreviewWidget; bool itsPreviewHidden; }; } #endif diff --git a/kcms/kfontinst/kio/FontInstInterface.cpp b/kcms/kfontinst/kio/FontInstInterface.cpp index be36a4241..6f3ce70a2 100644 --- a/kcms/kfontinst/kio/FontInstInterface.cpp +++ b/kcms/kfontinst/kio/FontInstInterface.cpp @@ -1,178 +1,178 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2009 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 "FontInstInterface.h" #include "FontinstIface.h" #include "FontInst.h" #include #include #include #include #include "config-fontinst.h" #include "debug.h" #define KFI_DBUG qCDebug(KCM_KFONTINST_KIO) << '(' << time(NULL) << ')' namespace KFI { FontInstInterface::FontInstInterface() : itsInterface(new OrgKdeFontinstInterface(OrgKdeFontinstInterface::staticInterfaceName(), FONTINST_PATH, - QDBusConnection::sessionBus(), 0L)) + QDBusConnection::sessionBus(), nullptr)) , itsActive(false) { KFI_DBUG; FontInst::registerTypes(); 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(itsInterface, SIGNAL(status(int,int)), SLOT(status(int,int))); connect(itsInterface, SIGNAL(fontList(int,QList)), SLOT(fontList(int,QList))); connect(itsInterface, SIGNAL(fontStat(int,KFI::Family)), SLOT(fontStat(int,KFI::Family))); if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(OrgKdeFontinstInterface::staticInterfaceName())) QProcess::startDetached(QLatin1String(KFONTINST_LIB_EXEC_DIR"/fontinst"), QStringList()); } FontInstInterface::~FontInstInterface() { KFI_DBUG; } int FontInstInterface::install(const QString &file, bool toSystem) { KFI_DBUG; itsInterface->install(file, true, toSystem, getpid(), true); return waitForResponse(); } int FontInstInterface::uninstall(const QString &name, bool fromSystem) { KFI_DBUG; itsInterface->uninstall(name, fromSystem, getpid(), true); return waitForResponse(); } int FontInstInterface::reconfigure() { KFI_DBUG; itsInterface->reconfigure(getpid(), false); return waitForResponse(); } Families FontInstInterface::list(bool system) { KFI_DBUG; Families rv; itsInterface->list(system ? FontInst::SYS_MASK : FontInst::USR_MASK, getpid()); if(FontInst::STATUS_OK==waitForResponse()) { rv=itsFamilies; itsFamilies=Families(); } return rv; } Family FontInstInterface::statFont(const QString &file, bool system) { KFI_DBUG; Family rv; itsInterface->statFont(file, system ? FontInst::SYS_MASK : FontInst::USR_MASK, getpid()); if(FontInst::STATUS_OK==waitForResponse()) { rv=*itsFamilies.items.begin(); itsFamilies=Families(); } return rv; } QString FontInstInterface::folderName(bool sys) { if(!itsInterface) return QString(); QDBusPendingReply reply=itsInterface->folderName(sys); reply.waitForFinished(); return reply.isError() ? QString() : reply.argumentAt<0>(); } int FontInstInterface::waitForResponse() { KFI_DBUG; itsStatus=FontInst::STATUS_OK; itsFamilies=Families(); itsActive=true; itsEventLoop.exec(); KFI_DBUG << "Loop finished"; return itsStatus; } void FontInstInterface::dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to) { if(itsActive && to.isEmpty() && !from.isEmpty() && name==QLatin1String(OrgKdeFontinstInterface::staticInterfaceName())) { KFI_DBUG << "Service died :-("; itsStatus=FontInst::STATUS_SERVICE_DIED; itsEventLoop.quit(); } } void FontInstInterface::status(int pid, int value) { if(itsActive && pid==getpid()) { KFI_DBUG << "Status:" << value; itsStatus=value; itsEventLoop.quit(); } } void FontInstInterface::fontList(int pid, const QList &families) { if(itsActive && pid==getpid()) { KFI_DBUG; itsFamilies=1==families.count() ? *families.begin() : Families(); itsStatus=1==families.count() ? (int)FontInst::STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST; itsEventLoop.quit(); } } void FontInstInterface::fontStat(int pid, const KFI::Family &font) { if(itsActive && pid==getpid()) { KFI_DBUG; itsFamilies=Families(font, false); itsStatus=font.styles().count()>0 ? (int)FontInst::STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST; itsEventLoop.quit(); } } } diff --git a/kcms/kfontinst/kio/KioFonts.cpp b/kcms/kfontinst/kio/KioFonts.cpp index 3f1ccc38a..aba101e4d 100644 --- a/kcms/kfontinst/kio/KioFonts.cpp +++ b/kcms/kfontinst/kio/KioFonts.cpp @@ -1,821 +1,821 @@ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "KioFonts.h" #include "KfiConstants.h" #include "FontInstInterface.h" #include "FontInst.h" #include "Fc.h" #include "Misc.h" #include "XmlStrings.h" #include "Family.h" #include "Style.h" #include "File.h" #include "debug.h" #define MAX_IPC_SIZE (1024*32) #define KFI_DBUG qCDebug(KCM_KFONTINST_KIO) << '(' << time(NULL) << ')' static const int constReconfigTimeout = 10; extern "C" { Q_DECL_EXPORT int kdemain(int argc, char **argv) { if (argc != 4) { fprintf(stderr, "Usage: kio_" KFI_KIO_FONTS_PROTOCOL " protocol domain-socket1 domain-socket2\n"); exit(-1); } QCoreApplication app(argc, argv); QCoreApplication::setApplicationName("kio_" KFI_KIO_FONTS_PROTOCOL); KFI::CKioFonts slave(argv[2], argv[3]); slave.dispatchLoop(); return 0; } } namespace KFI { inline bool isSysFolder(const QString &folder) { return i18n(KFI_KIO_FONTS_SYS)==folder || KFI_KIO_FONTS_SYS==folder; } inline bool isUserFolder(const QString &folder) { return i18n(KFI_KIO_FONTS_USER)==folder || KFI_KIO_FONTS_USER==folder; } static CKioFonts::EFolder getFolder(const QStringList &list) { if(list.size()>0) { QString folder=list[0]; if(isSysFolder(folder)) return CKioFonts::FOLDER_SYS; else if(isUserFolder(folder)) return CKioFonts::FOLDER_USER; return CKioFonts::FOLDER_UNKNOWN; } return CKioFonts::FOLDER_ROOT; } static int getSize(const QString &file) { QT_STATBUF buff; QByteArray f(QFile::encodeName(file)); if(-1!=QT_LSTAT(f.constData(), &buff)) { if (S_ISLNK(buff.st_mode)) { char buffer2[1000]; int n=readlink(f.constData(), buffer2, 999); if(n!= -1) buffer2[n]='\0'; if(-1==QT_STAT(f.constData(), &buff)) return -1; } return buff.st_size; } return -1; } static bool writeAll(int fd, const char *buf, size_t len) { while(len>0) { ssize_t written=write(fd, buf, len); if (written<0 && EINTR!=errno) return false; buf+=written; len-=written; } return true; } static bool isScalable(const QString &str) { return Misc::checkExt(str, "ttf") || Misc::checkExt(str, "otf") || Misc::checkExt(str, "ttc") || Misc::checkExt(str, "pfa") || Misc::checkExt(str, "pfb"); } static const char * const constExtensions[]= {".ttf", KFI_FONTS_PACKAGE, ".otf", ".pfa", ".pfb", ".ttc", - ".pcf", ".pcf.gz", ".bdf", ".bdf.gz", NULL }; + ".pcf", ".pcf.gz", ".bdf", ".bdf.gz", nullptr }; static QString removeKnownExtension(const QUrl &url) { QString fname(url.fileName()); int pos; for(int i=0; constExtensions[i]; ++i) if(-1!=(pos=fname.lastIndexOf(QString::fromLatin1(constExtensions[i]), -1, Qt::CaseInsensitive))) return fname.left(pos); return fname; } CKioFonts::CKioFonts(const QByteArray &pool, const QByteArray &app) : KIO::SlaveBase(KFI_KIO_FONTS_PROTOCOL, pool, app) , itsInterface(new FontInstInterface()) , itsTempDir(nullptr) { KFI_DBUG; } CKioFonts::~CKioFonts() { KFI_DBUG; delete itsInterface; delete itsTempDir; } void CKioFonts::listDir(const QUrl &url) { KFI_DBUG << url; QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), QString::SkipEmptyParts)); EFolder folder=Misc::root() ? FOLDER_SYS : getFolder(pathList); KIO::UDSEntry entry; int size=0; switch(folder) { case FOLDER_ROOT: KFI_DBUG << "List root folder"; size=2; totalSize(2); createUDSEntry(entry, FOLDER_SYS); listEntry(entry); createUDSEntry(entry, FOLDER_USER); listEntry(entry); break; case FOLDER_SYS: case FOLDER_USER: size=listFolder(entry, folder); break; default: break; } if(FOLDER_UNKNOWN!=folder) { finished(); } else error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString()); } void CKioFonts::put(const QUrl &url, int /*permissions*/, KIO::JobFlags /*flags*/) { KFI_DBUG << url; QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), QString::SkipEmptyParts)); EFolder folder(getFolder(pathList)); if(!Misc::root() && FOLDER_ROOT==folder) error(KIO::ERR_SLAVE_DEFINED, i18n("Can only install fonts to either \"%1\" or \"%2\".", i18n(KFI_KIO_FONTS_USER), i18n(KFI_KIO_FONTS_SYS))); else if(Misc::isPackage(url.fileName())) error(KIO::ERR_SLAVE_DEFINED, i18n("You cannot install a fonts package directly.\n" "Please extract %1, and install the components individually.", url.toDisplayString())); else { if(!itsTempDir) { itsTempDir=new QTemporaryDir(QDir::tempPath() + QString::fromLatin1("/kio_fonts_")+QString::number(getpid())); itsTempDir->setAutoRemove(true); } QString tempFile(itsTempDir->filePath(url.fileName())); QFile dest(tempFile); if (dest.open(QIODevice::WriteOnly)) { int result; // Loop until we got 0 (end of data) do { QByteArray buffer; dataReq(); // Request for data result = readData(buffer); if(result > 0 && !writeAll(dest.handle(), buffer.constData(), buffer.size())) { if(ENOSPC==errno) // disk full { error(KIO::ERR_DISK_FULL, dest.fileName()); result = -2; // means: remove dest file } else { error(KIO::ERR_COULD_NOT_WRITE, dest.fileName()); result = -1; } } } while(result>0); if (result<0) { dest.close(); ::exit(255); } handleResp(itsInterface->install(tempFile, Misc::root() || FOLDER_SYS==folder), url.fileName(), tempFile, FOLDER_SYS==folder); QFile::remove(tempFile); } else error(EACCES==errno ? KIO::ERR_WRITE_ACCESS_DENIED : KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest.fileName()); } } void CKioFonts::get(const QUrl &url) { KFI_DBUG << url; QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), QString::SkipEmptyParts)); EFolder folder(getFolder(pathList)); Family family(getFont(url, folder)); if(!family.name().isEmpty() && 1==family.styles().count()) { StyleCont::ConstIterator style(family.styles().begin()); FileCont::ConstIterator it((*style).files().begin()), end((*style).files().end()); // // The thumbnail job always downloads non-local files to /tmp/... and passes this file name to // the thumbnail creator. However, in the case of fonts which are split among many files, this // wont work. Therefore, when the thumbnail code asks for the font to download, just return // the family and style info for enabled fonts, and the filename for disabled fonts. This way // the font-thumbnail creator can read this and just ask Xft/fontconfig for the font data. if("1"==metaData("thumbnail")) { QByteArray array; QTextStream stream(&array, QIODevice::WriteOnly); emit mimeType("text/plain"); bool hidden(true); for(; it!=end && hidden; ++it) if(!Misc::isHidden(Misc::getFile((*it).path()))) hidden=false; if(hidden) { // // OK, its a disabled font - if possible try to return the location of the font file // itself. bool found=false; it=(*style).files().begin(); end=(*style).files().end(); for(; it!=end && hidden; ++it) if(isScalable((*it).path())) { KFI_DBUG << "hasMetaData(\"thumbnail\"), so return FILE: " << (*it).path() << " / " << (*it).index(); stream << KFI_PATH_KEY << (*it).path() << endl << KFI_FACE_KEY << (*it).index() << endl; found=true; break; } if(!found) { KFI_DBUG << "hasMetaData(\"thumbnail\"), so return Url: " << url; stream << url.toDisplayString(); } } else { KFI_DBUG << "hasMetaData(\"thumbnail\"), so return DETAILS: " << family.name() << " / " << (*style).value(); stream << KFI_NAME_KEY << family.name() << endl << KFI_STYLE_KEY << (*style).value() << endl; } totalSize(array.size()); data(array); processedSize(array.size()); data(QByteArray()); processedSize(array.size()); finished(); KFI_DBUG << "Finished thumbnail..."; return; } QSet files; QString realPath; QT_STATBUF buff; bool multiple=false; for(; it!=end; ++it) { QStringList assoc; files.insert((*it).path()); Misc::getAssociatedFiles((*it).path(), assoc); QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); for(; ait!=aend; ++ait) files.insert(*ait); } if(1==files.count()) realPath=(*files.begin()); else // Font is made up of multiple files - so create .zip of them all! { QTemporaryFile tmpFile; if(tmpFile.open()) { KZip zip(tmpFile.fileName()); tmpFile.setAutoRemove(false); realPath=tmpFile.fileName(); if(zip.open(QIODevice::WriteOnly)) { QMap map=Misc::getFontFileMap(files); QMap::ConstIterator it(map.constBegin()), end(map.constEnd()); for(; it!=end; ++it) zip.addLocalFile(it.value(), it.key()); multiple=true; zip.close(); } } } QByteArray realPathC(QFile::encodeName(realPath)); KFI_DBUG << "real: " << realPathC; if (-2==QT_STAT(realPathC.constData(), &buff)) error(EACCES==errno ? KIO::ERR_ACCESS_DENIED : KIO::ERR_DOES_NOT_EXIST, url.toDisplayString()); else if (S_ISDIR(buff.st_mode)) error(KIO::ERR_IS_DIRECTORY, url.toDisplayString()); else if (!S_ISREG(buff.st_mode)) error(KIO::ERR_CANNOT_OPEN_FOR_READING, url.toDisplayString()); else { int fd = QT_OPEN(realPathC.constData(), O_RDONLY); if (fd < 0) error(KIO::ERR_CANNOT_OPEN_FOR_READING, url.toDisplayString()); else { // Determine the mimetype of the file to be retrieved, and emit it. // This is mandatory in all slaves (for KRun/BrowserRun to work). // This code can be optimized by using QFileInfo instead of buff above // and passing it to mimeTypeForFile() instead of realPath. QMimeDatabase db; emit mimeType(db.mimeTypeForFile(realPath).name()); totalSize(buff.st_size); KIO::filesize_t processed=0; char buffer[MAX_IPC_SIZE]; QByteArray array; while(1) { int n=::read(fd, buffer, MAX_IPC_SIZE); if (-1==n) { if (EINTR==errno) continue; error(KIO::ERR_COULD_NOT_READ, url.toDisplayString()); ::close(fd); if(multiple) ::unlink(realPathC); return; } if (0==n) break; // Finished array=array.fromRawData(buffer, n); data(array); array.clear(); processed+=n; processedSize(processed); } data(QByteArray()); ::close(fd); processedSize(buff.st_size); finished(); } } if(multiple) ::unlink(realPathC); } else error(KIO::ERR_COULD_NOT_READ, url.toDisplayString()); } void CKioFonts::copy(const QUrl &, const QUrl &, int, KIO::JobFlags) { error(KIO::ERR_SLAVE_DEFINED, i18n("Cannot copy fonts")); } void CKioFonts::rename(const QUrl &, const QUrl &, KIO::JobFlags) { error(KIO::ERR_SLAVE_DEFINED, i18n("Cannot move fonts")); } void CKioFonts::del(const QUrl &url, bool isFile) { KFI_DBUG << url; QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), QString::SkipEmptyParts)); EFolder folder(getFolder(pathList)); QString name(removeKnownExtension(url)); if(!isFile) error(KIO::ERR_SLAVE_DEFINED, i18n("Only fonts may be deleted.")); else if(!Misc::root() && FOLDER_ROOT==folder) error(KIO::ERR_SLAVE_DEFINED, i18n("Can only remove fonts from either \"%1\" or \"%2\".", i18n(KFI_KIO_FONTS_USER), i18n(KFI_KIO_FONTS_SYS))); else if(!name.isEmpty()) handleResp(itsInterface->uninstall(name, Misc::root() || FOLDER_SYS==folder), name); else error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString()); } void CKioFonts::statFont(const QUrl &url) { KFI_DBUG << url; QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), QString::SkipEmptyParts)); EFolder folder=getFolder(pathList); KIO::UDSEntry entry; bool ok=true; switch(pathList.count()) { case 0: createUDSEntry(entry, FOLDER_ROOT); break; case 1: if(Misc::root()) ok=createStatEntry(entry, url, FOLDER_SYS); else if(FOLDER_SYS==folder || FOLDER_USER==folder) createUDSEntry(entry, folder); else { error(KIO::ERR_SLAVE_DEFINED, i18n("Please specify \"%1\" or \"%2\".", i18n(KFI_KIO_FONTS_USER), i18n(KFI_KIO_FONTS_SYS))); return; } break; default: ok=createStatEntry(entry, url, folder); } if(ok) { statEntry(entry); finished(); } else { error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString()); return; } } void CKioFonts::special(const QByteArray &a) { if(a.size()) error(KIO::ERR_UNSUPPORTED_ACTION, i18n("No special methods supported.")); else { setTimeoutSpecialCommand(-1); itsInterface->reconfigure(); } } int CKioFonts::listFolder(KIO::UDSEntry &entry, EFolder folder) { KFI_DBUG << folder; int styleCount(0); KFI::Families families(itsInterface->list(FOLDER_SYS==folder)); FamilyCont::ConstIterator family(families.items.begin()), end(families.items.end()); KFI_DBUG << "Num families:" << families.items.count(); for(; family!=end; ++family) { StyleCont::ConstIterator styleIt((*family).styles().begin()), styleEnd((*family).styles().end()); styleCount+=(*family).styles().count(); for(; styleIt!=styleEnd; ++styleIt) { createUDSEntry(entry, folder, *family, *styleIt); listEntry(entry); } } totalSize(styleCount); return styleCount; } QString CKioFonts::getUserName(uid_t uid) { if (!itsUserCache.contains(uid)) { struct passwd *user = getpwuid(uid); if(user) itsUserCache.insert(uid, QString::fromLatin1(user->pw_name)); else return QString::number(uid); } return itsUserCache[uid]; } QString CKioFonts::getGroupName(gid_t gid) { if (!itsGroupCache.contains(gid)) { struct group *grp = getgrgid(gid); if(grp) itsGroupCache.insert(gid, QString::fromLatin1(grp->gr_name)); else return QString::number(gid); } return itsGroupCache[gid]; } bool CKioFonts::createStatEntry(KIO::UDSEntry &entry, const QUrl &url, EFolder folder) { Family fam(getFont(url, folder)); if(!fam.name().isEmpty() && 1==fam.styles().count()) { createUDSEntry(entry, folder, fam, *fam.styles().begin()); return true; } return false; } void CKioFonts::createUDSEntry(KIO::UDSEntry &entry, EFolder folder) { KFI_DBUG << QString(FOLDER_SYS==folder ? i18n(KFI_KIO_FONTS_SYS) : i18n(KFI_KIO_FONTS_USER)); entry.clear(); entry.insert(KIO::UDSEntry::UDS_NAME, FOLDER_ROOT==folder || Misc::root() ? i18n("Fonts") : FOLDER_SYS==folder ? i18n(KFI_KIO_FONTS_SYS) : i18n(KFI_KIO_FONTS_USER)); entry.insert(KIO::UDSEntry::UDS_ACCESS, !Misc::root() && FOLDER_SYS==folder ? 0444 : 0744); entry.insert(KIO::UDSEntry::UDS_USER, Misc::root() || FOLDER_SYS==folder ? QString::fromLatin1("root") : getUserName(getuid())); entry.insert(KIO::UDSEntry::UDS_GROUP, Misc::root() || FOLDER_SYS==folder ? QString::fromLatin1("root") : getGroupName(getgid())); entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1("inode/directory")); } bool CKioFonts::createUDSEntry(KIO::UDSEntry &entry, EFolder folder, const Family &family, const Style &style) { int size=0; QString name(FC::createName(family.name(), style.value())); FileCont::ConstIterator file(style.files().begin()), fileEnd(style.files().end()); QList files; bool hidden=true, haveExtraFiles=false; KFI_DBUG << name; for(; file!=fileEnd; ++file) { size+=getSize((*file).path()); // TODO: Make scalable a property of the file? // Then isScalable() is not needed!!! if(isScalable((*file).path())) files.prepend(*file); else files.append(*file); if(hidden && !Misc::isHidden(Misc::getFile((*file).path()))) hidden=false; QStringList assoc; Misc::getAssociatedFiles((*file).path(), assoc); QStringList::ConstIterator oit(assoc.constBegin()), oend(assoc.constEnd()); if(!haveExtraFiles && !assoc.isEmpty()) haveExtraFiles=true; for(; oit!=oend; ++oit) size+=getSize(*oit); } entry.clear(); entry.insert(KIO::UDSEntry::UDS_NAME, name); entry.insert(KIO::UDSEntry::UDS_SIZE, size); entry.insert(UDS_EXTRA_FC_STYLE, style.value()); QList::ConstIterator it(files.constBegin()), end(files.constEnd()); for(; it!=end; ++it) { QByteArray cPath(QFile::encodeName((*it).path())); QT_STATBUF buff; if(-1!=QT_LSTAT(cPath, &buff)) { QString fileName(Misc::getFile((*it).path())), mt; int dotPos(fileName.lastIndexOf('.')); QString extension(-1==dotPos ? QString() : fileName.mid(dotPos)); if(QString::fromLatin1(".gz")==extension) { dotPos=fileName.lastIndexOf('.', dotPos-1); extension=-1==dotPos ? QString() : fileName.mid(dotPos); } if(QString::fromLatin1(".ttf")==extension || QString::fromLatin1(".ttc")==extension) mt="application/x-font-ttf"; else if(QString::fromLatin1(".otf")==extension) mt="application/x-font-otf"; else if(QString::fromLatin1(".pfa")==extension || QString::fromLatin1(".pfb")==extension) mt="application/x-font-type1"; else if(QString::fromLatin1(".pcf.gz")==extension || QString::fromLatin1(".pcf")==extension) mt="application/x-font-pcf"; else if(QString::fromLatin1(".bdf.gz")==extension || QString::fromLatin1(".bdf")==extension) mt="application/x-font-bdf"; else { // File extension check failed, use QMimeDatabase to read contents... QMimeDatabase db; QMimeType mime = db.mimeTypeForFile((*it).path()); QStringList patterns = mime.globPatterns(); mt = mime.name(); if(patterns.size()>0) extension=(*patterns.begin()).remove("*"); } entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, buff.st_mode&S_IFMT); entry.insert(KIO::UDSEntry::UDS_ACCESS, buff.st_mode&07777); entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, buff.st_mtime); entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, buff.st_atime); entry.insert(KIO::UDSEntry::UDS_USER, getUserName(buff.st_uid)); entry.insert(KIO::UDSEntry::UDS_GROUP, getGroupName(buff.st_gid)); entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, mt); if(hidden) { entry.insert(KIO::UDSEntry::UDS_HIDDEN, 1); entry.insert(UDS_EXTRA_FILE_NAME, (*it).path()); entry.insert(UDS_EXTRA_FILE_FACE, (*it).path()); } QString path(QString::fromLatin1("/")); if(!Misc::root()) { path+=FOLDER_SYS==folder ? i18n(KFI_KIO_FONTS_SYS) : i18n(KFI_KIO_FONTS_USER); path+=QString::fromLatin1("/"); } path+=name; if(files.count()>1 || haveExtraFiles) path+=QString::fromLatin1(KFI_FONTS_PACKAGE); else path+=extension; QUrl url(QUrl::fromLocalFile(path)); url.setScheme(KFI_KIO_FONTS_PROTOCOL); entry.insert(KIO::UDSEntry::UDS_URL, url.url()); return true; } } return false; } Family CKioFonts::getFont(const QUrl &url, EFolder folder) { QString name(removeKnownExtension(url)); KFI_DBUG << url << name; return itsInterface->statFont(name, FOLDER_SYS==folder); } void CKioFonts::handleResp(int resp, const QString &file, const QString &tempFile, bool destIsSystem) { switch(resp) { case FontInst::STATUS_NO_SYS_CONNECTION: error(KIO::ERR_SLAVE_DEFINED, i18n("Failed to start the system daemon")); break; case FontInst::STATUS_SERVICE_DIED: error(KIO::ERR_SLAVE_DEFINED, i18n("Backend died")); break; case FontInst::STATUS_BITMAPS_DISABLED: error(KIO::ERR_SLAVE_DEFINED, i18n("%1 is a bitmap font, and these have been disabled on your system.", file)); break; case FontInst::STATUS_ALREADY_INSTALLED: error(KIO::ERR_SLAVE_DEFINED, i18n("%1 contains the font %2, which is already installed on your system.", file, FC::getName(tempFile))); break; case FontInst::STATUS_NOT_FONT_FILE: error(KIO::ERR_SLAVE_DEFINED, i18n("%1 is not a font.", file)); break; case FontInst::STATUS_PARTIAL_DELETE: error(KIO::ERR_SLAVE_DEFINED, i18n("Could not remove all files associated with %1", file)); break; case KIO::ERR_FILE_ALREADY_EXIST: { QString name(Misc::modifyName(file)), destFolder(Misc::getDestFolder(itsInterface->folderName(destIsSystem), name)); error(KIO::ERR_SLAVE_DEFINED, i18n("%1 already exists.", destFolder+name)); break; } case FontInst::STATUS_OK: finished(); break; default: error(resp, file); } if(FontInst::STATUS_OK==resp) setTimeoutSpecialCommand(constReconfigTimeout); } } diff --git a/kcms/kfontinst/lib/Fc.cpp b/kcms/kfontinst/lib/Fc.cpp index 7a0a82789..83d8c1dbf 100644 --- a/kcms/kfontinst/lib/Fc.cpp +++ b/kcms/kfontinst/lib/Fc.cpp @@ -1,653 +1,653 @@ /* * 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 "Fc.h" #include #include // // KDE font chooser always seems to use Italic - for both Oblique, and Italic. So I guess // the fonts:/ should do too - so as to appear more unified. // // ditto with respect to Medium/Regular #define KFI_HAVE_OBLIQUE // Do we differentiate between Italic and Oblique when comparing slants? #define KFI_DISPLAY_OBLIQUE // Do we want to list "Oblique"? Or always use Italic? #define KFI_HAVE_MEDIUM_WEIGHT // Do we differentiate between Medium and Regular weights when comparing weights? #define KFI_DISPLAY_MEDIUM // Do we want to list "Medium"? Or always use Regular? namespace KFI { namespace FC { #define FC_PROTOCOL QString::fromLatin1("fontconfig") #define FC_STYLE_QUERY QString::fromLatin1("style") #define FC_FILE_QUERY QString::fromLatin1("file") #define FC_INDEX_QUERY QString::fromLatin1("index") QUrl encode(const QString &name, quint32 style, const QString &file, int index) { QUrl url(QUrl::fromLocalFile(name)); url.setScheme(FC_PROTOCOL); url.addQueryItem(FC_STYLE_QUERY, QString::number(style)); if(!file.isEmpty()) url.addQueryItem(FC_FILE_QUERY, file); if(index>0) url.addQueryItem(FC_INDEX_QUERY, QString::number(index)); return url; } Misc::TFont decode(const QUrl &url) { QUrlQuery query(url); return FC_PROTOCOL==url.scheme() ? Misc::TFont(url.path(), query.queryItemValue(FC_STYLE_QUERY).toUInt()) : Misc::TFont(QString(), 0); } QString getFile(const QUrl &url) { QUrlQuery query(url); return FC_PROTOCOL==url.scheme() ? query.queryItemValue(FC_FILE_QUERY) : QString(); } int getIndex(const QUrl &url) { QUrlQuery query(url); return FC_PROTOCOL==url.scheme() ? query.queryItemValue(FC_INDEX_QUERY).toInt() : 0; } int weight(int w) { if(KFI_NULL_SETTING==w) #ifdef KFI_HAVE_MEDIUM_WEIGHT return FC_WEIGHT_MEDIUM; #else return FC_WEIGHT_REGULAR; #endif if(w>16; width=(styleInfo&0x00FF00)>>8; slant=(styleInfo&0x0000FF); } quint32 styleValFromStr(const QString &style) { if(style.isEmpty()) return KFI_NO_STYLE_INFO; else { quint32 val; QTextStream(const_cast(&style), QIODevice::ReadOnly) >> val; return val; } } QString getFcString(FcPattern *pat, const char *val, int index) { QString rv; FcChar8 *fcStr; if(FcResultMatch==FcPatternGetString(pat, val, index, &fcStr)) rv=QString::fromUtf8((char *)fcStr); return rv; } // // TODO: How correct is this? // Qt/Gtk seem to prefer font family names with FAMILY_LANG=="en" // ...so if possible, use that. Else, use the first non "xx" lang. QString getFcLangString(FcPattern *pat, const char *val, const char *valLang) { QString rv; int langIndex=-1; for(int i=0; true; ++i) { QString lang=getFcString(pat, valLang, i); if(lang.isEmpty()) break; else if(QString::fromLatin1("en")==lang) return getFcString(pat, val, i); else if(QString::fromLatin1("xx")!=lang && -1==langIndex) langIndex=i; } return getFcString(pat, val, langIndex>0 ? langIndex : 0); } int getFcInt(FcPattern *pat, const char *val, int index, int def) { int rv; if (FcResultMatch==FcPatternGetInteger(pat, val, index, &rv)) return rv; return def; } QString getName(const QString &file) { int count=0; - FcPattern *pat=FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(file).constData()), 0, NULL, + FcPattern *pat=FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(file).constData()), 0, nullptr, &count); QString name(i18n("Unknown")); if(pat) { name=FC::createName(pat); FcPatternDestroy(pat); } return name; } void getDetails(FcPattern *pat, QString &family, quint32 &styleVal, int &index, QString &foundry) { int weight=getFcInt(pat, FC_WEIGHT, 0, KFI_NULL_SETTING), width= #ifdef KFI_FC_NO_WIDTHS KFI_NULL_SETTING, #else getFcInt(pat, FC_WIDTH, 0, KFI_NULL_SETTING), #endif slant=getFcInt(pat, FC_SLANT, 0, KFI_NULL_SETTING); index=getFcInt(pat, FC_INDEX, 0, 0); // #ifdef KFI_USE_TRANSLATED_FAMILY_NAME family=getFcLangString(pat, FC_FAMILY, FC_FAMILYLANG); // #else // family=getFcString(pat, FC_FAMILY, 0); // #endif styleVal=createStyleVal(weight, width, slant); foundry=getFcString(pat, FC_FOUNDRY, 0); } QString createName(FcPattern *pat) { QString family, foundry; quint32 styleVal; int index; getDetails(pat, family, styleVal, index, foundry); return createName(family, styleVal); } QString createName(const QString &family, quint32 styleInfo) { int weight, width, slant; decomposeStyleVal(styleInfo, weight, width, slant); return createName(family, weight, width, slant); } QString createName(const QString &family, int weight, int width, int slant) { return family+QString::fromLatin1(", ")+createStyleName(weight, width, slant); } QString createStyleName(quint32 styleInfo) { int weight, width, slant; decomposeStyleVal(styleInfo, weight, width, slant); return createStyleName(weight, width, slant); } QString createStyleName(int weight, int width, int slant) { // //CPD: TODO: the names *need* to match up with kfontchooser's... // : Removing KFI_DISPLAY_OBLIQUE and KFI_DISPLAY_MEDIUM help this. // However, I have at least one bad font: // Rockwell Extra Bold. Both fontconfig, and kcmshell fonts list family // as "Rockwell Extra Bold" -- good (well at least they match). *But* fontconfig // is returning the weight "Extra Bold", and kcmshell fonts is using "Bold" :-( // QString name, weightString, widthString, slantString; #ifndef KFI_FC_NO_WIDTHS if(KFI_NULL_SETTING!=width) widthString=widthStr(width); #endif if(KFI_NULL_SETTING!=slant) slantString=slantStr(slant); // // If weight is "Regular", we only want to display it if slant and width are empty. if(KFI_NULL_SETTING!=weight) { weightString=weightStr(weight, !slantString.isEmpty() || !widthString.isEmpty()); if(!weightString.isEmpty()) name=weightString; } #ifndef KFI_FC_NO_WIDTHS if(!widthString.isEmpty()) { if(!name.isEmpty()) name+=QChar(' '); name+=widthString; } #endif if(!slantString.isEmpty()) { if(!name.isEmpty()) name+=QChar(' '); name+=slantString; } return name; } QString weightStr(int w, bool emptyNormal) { switch(weight(w)) { case FC_WEIGHT_THIN: return i18n(KFI_WEIGHT_THIN); case FC_WEIGHT_EXTRALIGHT: return i18n(KFI_WEIGHT_EXTRALIGHT); case FC_WEIGHT_LIGHT: return i18n(KFI_WEIGHT_LIGHT); case FC_WEIGHT_MEDIUM: #ifdef KFI_DISPLAY_MEDIUM return i18n(KFI_WEIGHT_MEDIUM); #endif case FC_WEIGHT_REGULAR: return emptyNormal ? QString() : i18n(KFI_WEIGHT_REGULAR); case FC_WEIGHT_DEMIBOLD: return i18n(KFI_WEIGHT_DEMIBOLD); case FC_WEIGHT_BOLD: return i18n(KFI_WEIGHT_BOLD); case FC_WEIGHT_EXTRABOLD: return i18n(KFI_WEIGHT_EXTRABOLD); default: return i18n(KFI_WEIGHT_BLACK); } } QString widthStr(int w, bool emptyNormal) { switch(width(w)) { case KFI_FC_WIDTH_ULTRACONDENSED: return i18n(KFI_WIDTH_ULTRACONDENSED); case KFI_FC_WIDTH_EXTRACONDENSED: return i18n(KFI_WIDTH_EXTRACONDENSED); case KFI_FC_WIDTH_CONDENSED: return i18n(KFI_WIDTH_CONDENSED); case KFI_FC_WIDTH_SEMICONDENSED: return i18n(KFI_WIDTH_SEMICONDENSED); case KFI_FC_WIDTH_NORMAL: return emptyNormal ? QString() : i18n(KFI_WIDTH_NORMAL); case KFI_FC_WIDTH_SEMIEXPANDED: return i18n(KFI_WIDTH_SEMIEXPANDED); case KFI_FC_WIDTH_EXPANDED: return i18n(KFI_WIDTH_EXPANDED); case KFI_FC_WIDTH_EXTRAEXPANDED: return i18n(KFI_WIDTH_EXTRAEXPANDED); default: return i18n(KFI_WIDTH_ULTRAEXPANDED); } } QString slantStr(int s, bool emptyNormal) { switch(slant(s)) { case FC_SLANT_OBLIQUE: #ifdef KFI_DISPLAY_OBLIQUE return i18n(KFI_SLANT_OBLIQUE); #endif case FC_SLANT_ITALIC: return i18n(KFI_SLANT_ITALIC); default: return emptyNormal ? QString() : i18n(KFI_SLANT_ROMAN); } } QString spacingStr(int s) { switch(spacing(s)) { case FC_MONO: return i18n(KFI_SPACING_MONO); case FC_CHARCELL: return i18n(KFI_SPACING_CHARCELL); default: return i18n(KFI_SPACING_PROPORTIONAL); } } bool bitmapsEnabled() { // // On some systems, such as KUbuntu, fontconfig is configured to ignore all bitmap fonts. // The following check tries to get a list of installed bitmaps, if it an empty list is returned // it is assumed that bitmaps are disabled. static bool enabled(false); static bool checked(false); // Do not keep on checking! if(!checked) { - FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, (void *)0); - FcPattern *pat = FcPatternBuild(NULL, FC_SCALABLE, FcTypeBool, FcFalse, NULL); - FcFontSet *set = FcFontList(0, pat, os); + FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, (void *)nullptr); + FcPattern *pat = FcPatternBuild(nullptr, FC_SCALABLE, FcTypeBool, FcFalse, NULL); + FcFontSet *set = FcFontList(nullptr, pat, os); FcPatternDestroy(pat); FcObjectSetDestroy(os); if (set) { if(set->nfont) enabled=true; FcFontSetDestroy(set); } checked=true; } return enabled; } } } diff --git a/kcms/kfontinst/lib/FcEngine.cpp b/kcms/kfontinst/lib/FcEngine.cpp index 62d628e82..6efaface5 100644 --- a/kcms/kfontinst/lib/FcEngine.cpp +++ b/kcms/kfontinst/lib/FcEngine.cpp @@ -1,1564 +1,1564 @@ /* * 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 "FcEngine.h" #include #include #include #include #include #include #include #include #include #include "File.h" #include #include #include #include //#define KFI_FC_DEBUG #define KFI_PREVIEW_GROUP "KFontInst Preview Settings" #define KFI_PREVIEW_STRING_KEY "String" namespace KFI { bool CFcEngine::theirFcDirty(true); const int CFcEngine::constScalableSizes[]={8, 10, 12, 24, 36, 48, 64, 72, 96, 0 }; const int CFcEngine::constDefaultAlphaSize=24; static int fcToQtWeight(int weight) { switch(weight) { case FC_WEIGHT_THIN: return 0; case FC_WEIGHT_EXTRALIGHT: return QFont::Light>>1; case FC_WEIGHT_LIGHT: return QFont::Light; default: case FC_WEIGHT_REGULAR: return QFont::Normal; case FC_WEIGHT_MEDIUM: #ifdef KFI_HAVE_MEDIUM_WEIGHT return (QFont::Normal+QFont::DemiBold)>>1; #endif return QFont::Normal; case FC_WEIGHT_DEMIBOLD: return QFont::DemiBold; case FC_WEIGHT_BOLD: return QFont::Bold; case FC_WEIGHT_EXTRABOLD: return (QFont::Bold+QFont::Black)>>1; case FC_WEIGHT_BLACK: return QFont::Black; } } #ifndef KFI_FC_NO_WIDTHS static int fcToQtWidth(int weight) { switch(weight) { case KFI_FC_WIDTH_ULTRACONDENSED: return QFont::UltraCondensed; case KFI_FC_WIDTH_EXTRACONDENSED: return QFont::ExtraCondensed; case KFI_FC_WIDTH_CONDENSED: return QFont::Condensed; case KFI_FC_WIDTH_SEMICONDENSED: return QFont::SemiCondensed; default: case KFI_FC_WIDTH_NORMAL: return QFont::Unstretched; case KFI_FC_WIDTH_SEMIEXPANDED: return QFont::SemiExpanded; case KFI_FC_WIDTH_EXPANDED: return QFont::Expanded; case KFI_FC_WIDTH_EXTRAEXPANDED: return QFont::ExtraExpanded; case KFI_FC_WIDTH_ULTRAEXPANDED: return QFont::UltraExpanded; } } #endif static bool fcToQtSlant(int slant) { return FC_SLANT_ROMAN==slant ? false : true; } inline bool equal(double d1, double d2) { return (fabs(d1 - d2) < 0.0001); } inline bool equalWeight(int a, int b) { return a==b || FC::weight(a)==FC::weight(b); } #ifndef KFI_FC_NO_WIDTHS inline bool equalWidth(int a, int b) { return a==b || FC::width(a)==FC::width(b); } #endif inline bool equalSlant(int a, int b) { return a==b || FC::slant(a)==FC::slant(b); } static void closeFont(XftFont *&font) { if(font) XftFontClose(QX11Info::display(), font); font= nullptr; } class CFcEngine::Xft { public: struct Pix { Pix() : currentW(0), currentH(0), allocatedW(0), allocatedH(0) { } static int getSize(int s) { static const int constBlockSize=64; return ((s/constBlockSize)+(s%constBlockSize ? 1 : 0))*constBlockSize; } bool allocate(int w, int h) { int requiredW=getSize(w), requiredH=getSize(h); currentW=w; currentH=h; if(requiredW!=allocatedW || requiredH!=allocatedH) { free(); if(w && h) { allocatedW=requiredW; allocatedH=requiredH; x11=XCreatePixmap(QX11Info::display(), RootWindow(QX11Info::display(), 0), allocatedW, allocatedH, DefaultDepth(QX11Info::display(), 0)); return true; } } return false; } void free() { if(allocatedW && allocatedH) { XFreePixmap(QX11Info::display(), x11); allocatedW=allocatedH=0; } } int currentW, currentH, allocatedW, allocatedH; Pixmap x11; }; Xft(); ~Xft(); bool init(const QColor &txt, const QColor &bgnd, int w, int h); void freeColors(); bool drawChar32Centre(XftFont *xftFont, quint32 ch, int w, int h) const; bool drawChar32(XftFont *xftFont, quint32 ch,int &x, int &y, int w, int h, int fontHeight, QRect &r) const; bool drawString(XftFont *xftFont, const QString &text, int x, int &y, int h) const; void drawString(const QString &text, int x, int &y, int h) const; bool drawGlyph(XftFont *xftFont, FT_UInt i, int &x, int &y, int w, int h, int fontHeight,bool oneLine, QRect &r) const; bool drawAllGlyphs(XftFont *xftFont, int fontHeight, int &x, int &y, int w, int h, bool oneLine=false, int max=-1, QRect *used= nullptr) const; bool drawAllChars(XftFont *xftFont, int fontHeight, int &x, int &y, int w, int h, bool oneLine=false, int max=-1, QRect *used= nullptr) const; QImage toImage(int w, int h) const; private: XftDraw *itsDraw; XftColor itsTxtColor, itsBgndColor; Pix itsPix; QImage::Format imageFormat; }; CFcEngine::Xft::Xft() { itsDraw= nullptr; itsTxtColor.color.alpha=0x0000; init(Qt::black, Qt::white, 64, 64); } CFcEngine::Xft::~Xft() { freeColors(); if(itsDraw) { XftDrawDestroy(itsDraw); itsDraw= nullptr; } } bool CFcEngine::Xft::init(const QColor &txt, const QColor &bnd, int w, int h) { if(itsDraw && (txt.red()<<8 != itsTxtColor.color.red || txt.green()<<8 != itsTxtColor.color.green || txt.blue()<<8 != itsTxtColor.color.blue || bnd.red()<<8 != itsBgndColor.color.red || bnd.green()<<8 != itsBgndColor.color.green || bnd.blue()<<8 != itsBgndColor.color.blue)) freeColors(); if(0x0000==itsTxtColor.color.alpha) { XRenderColor xrenderCol; Visual *visual=DefaultVisual(QX11Info::display(), 0); Colormap colorMap=DefaultColormap(QX11Info::display(), 0); xrenderCol.red=bnd.red()<<8; xrenderCol.green=bnd.green()<<8; xrenderCol.blue=bnd.green()<<8; xrenderCol.alpha=0xFFFF; XftColorAllocValue(QX11Info::display(), visual, colorMap, &xrenderCol, &itsBgndColor); xrenderCol.red=txt.red()<<8; xrenderCol.green=txt.green()<<8; xrenderCol.blue=txt.green()<<8; xrenderCol.alpha=0xFFFF; XftColorAllocValue(QX11Info::display(), visual, colorMap, &xrenderCol, &itsTxtColor); } XVisualInfo defaultVinfo; defaultVinfo.depth = DefaultDepth(QX11Info::display(), 0); // normal/failsafe imageFormat = QImage::Format_RGB32; // 24bit switch (defaultVinfo.depth) { case 32: imageFormat = QImage::Format_ARGB32_Premultiplied; break; case 30: imageFormat = QImage::Format_RGB30; break; case 16: imageFormat = QImage::Format_RGB16; break; case 8: imageFormat = QImage::Format_Grayscale8; break; default: break; } if (defaultVinfo.depth == 30 || defaultVinfo.depth == 32) { // detect correct format int num_vinfo = 0; defaultVinfo.visual = DefaultVisual(QX11Info::display(), 0); defaultVinfo.screen = 0; defaultVinfo.visualid = XVisualIDFromVisual(defaultVinfo.visual); XVisualInfo *vinfo = XGetVisualInfo(QX11Info::display(), VisualIDMask|VisualScreenMask|VisualDepthMask, &defaultVinfo, &num_vinfo); for (int i = 0; i < num_vinfo; ++i) { if (vinfo[i].visual == defaultVinfo.visual) { if (defaultVinfo.depth == 30) { if (vinfo[i].red_mask == 0x3ff) imageFormat = QImage::Format_BGR30; else if (vinfo[i].blue_mask == 0x3ff) imageFormat = QImage::Format_RGB30; } else if (defaultVinfo.depth == 32) { if (vinfo[i].blue_mask == 0xff) imageFormat = QImage::Format_ARGB32_Premultiplied; else if (vinfo[i].red_mask == 0x3ff) imageFormat = QImage::Format_A2BGR30_Premultiplied; else if (vinfo[i].blue_mask == 0x3ff) imageFormat = QImage::Format_A2RGB30_Premultiplied; } break; } } XFree(vinfo); } if(itsPix.allocate(w, h) && itsDraw) XftDrawChange(itsDraw, itsPix.x11); if(!itsDraw) itsDraw=XftDrawCreate(QX11Info::display(), itsPix.x11, DefaultVisual(QX11Info::display(), 0), DefaultColormap(QX11Info::display(), 0)); if(itsDraw) XftDrawRect(itsDraw, &itsBgndColor, 0, 0, w, h); return itsDraw; } void CFcEngine::Xft::freeColors() { XftColorFree(QX11Info::display(), DefaultVisual(QX11Info::display(), 0), DefaultColormap(QX11Info::display(), 0), &itsTxtColor); XftColorFree(QX11Info::display(), DefaultVisual(QX11Info::display(), 0), DefaultColormap(QX11Info::display(), 0), &itsBgndColor); itsTxtColor.color.alpha=0x0000; } bool CFcEngine::Xft::drawChar32Centre(XftFont *xftFont, quint32 ch, int w, int h) const { if(XftCharExists(QX11Info::display(), xftFont, ch)) { XGlyphInfo extents; XftTextExtents32(QX11Info::display(), xftFont, &ch, 1, &extents); int rx(((w-extents.width)/2)+extents.x), ry(((h-extents.height)/2)+(extents.y)); XftDrawString32(itsDraw, &itsTxtColor, xftFont, rx, ry, &ch, 1); return true; } return false; } static const int constBorder=2; bool CFcEngine::Xft::drawChar32(XftFont *xftFont, quint32 ch, int &x, int &y, int w, int h, int fontHeight, QRect &r) const { r=QRect(); if(XftCharExists(QX11Info::display(), xftFont, ch)) { XGlyphInfo extents; XftTextExtents32(QX11Info::display(), xftFont, &ch, 1, &extents); if(extents.x>0) x+=extents.x; if(x+extents.width+constBorder>w) { x=0; if(extents.x>0) x+=extents.x; y+=fontHeight+constBorder; } if(y0) { y+=extents.height; return true; } return false; } void CFcEngine::Xft::drawString(const QString &text, int x, int &y, int h) const { QFont qt(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); XftFont *xftFont=XftFontOpen(QX11Info::display(), 0, FC_FAMILY, FcTypeString, (const FcChar8 *)(qt.family().toUtf8().data()), FC_WEIGHT, FcTypeInteger, qt.bold() ? FC_WEIGHT_BOLD : FC_WEIGHT_REGULAR, FC_SLANT, FcTypeInteger, qt.italic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN, FC_SIZE, FcTypeDouble, (double)qt.pointSize(), NULL); if(xftFont) { drawString(xftFont, text, x, y, h); closeFont(xftFont); } } bool CFcEngine::Xft::drawGlyph(XftFont *xftFont, FT_UInt i, int &x, int &y, int w, int h, int fontHeight, bool oneLine, QRect &r) const { XGlyphInfo extents; XftGlyphExtents(QX11Info::display(), xftFont, &i, 1, &extents); if(0==extents.width || 0==extents.height) { r=QRect(0, 0, 0, 0); return true; } if(x+extents.width+2>w) { if(oneLine) return false; x=0; y+=fontHeight+2; } if(ynum_glyphs && y0) { if(used) { if(used->isEmpty()) *used=r; else *used=used->united(r); } if(max>0 && ++drawn>=max) break; } } else break; if(oneLine) x=0; XftUnlockFace(xftFont); } } return rv; } bool CFcEngine::Xft::drawAllChars(XftFont *xftFont, int fontHeight, int &x, int &y, int w, int h, bool oneLine, int max, QRect *used) const { bool rv(false); if(xftFont) { FT_Face face=XftLockFace(xftFont); if(face) { int space(fontHeight/10), drawn(0); QRect r; if(!space) space=1; rv=true; y+=fontHeight; FT_Select_Charmap(face, FT_ENCODING_UNICODE); for(int cmap=0; cmapnum_charmaps; ++cmap) if(face->charmaps[cmap] && FT_ENCODING_ADOBE_CUSTOM==face->charmaps[cmap]->encoding) { FT_Select_Charmap(face, FT_ENCODING_ADOBE_CUSTOM); break; } for(unsigned int i=1; i<65535 && y0) { if(used) { if(used->isEmpty()) *used=r; else *used=used->united(r); } if(max>0 && ++drawn>=max) break; } } else break; } } if(oneLine) x=0; XftUnlockFace(xftFont); } } return rv; } void cleanupXImage(void *data) { xcb_image_destroy((xcb_image_t*)data); } QImage CFcEngine::Xft::toImage(int w, int h) const { if (!XftDrawPicture(itsDraw)) { return QImage(); } xcb_image_t *xImage = xcb_image_get(QX11Info::connection(), itsPix.x11, 0, 0, itsPix.currentW, itsPix.currentH, ~0, XCB_IMAGE_FORMAT_Z_PIXMAP); if (!xImage) { return QImage(); } return QImage(xImage->data, xImage->width, xImage->height, xImage->stride, imageFormat, &cleanupXImage, xImage); } inline int point2Pixel(int point) { return (point*QX11Info::appDpiX()+36)/72; } static bool hasStr(XftFont *font, QString &str) { unsigned int slen=str.length(), ch; for(ch=0; chcharset, str[ch].unicode())) return false; return true; } static QString usableStr(XftFont *font, QString &str) { unsigned int slen=str.length(), ch; QString newStr; for(ch=0; chcharset, str[ch].unicode())) newStr+=str[ch]; return newStr; } static bool isFileName(const QString &name, quint32 style) { return QChar('/')==name[0] || KFI_NO_STYLE_INFO==style; } static void setTransparentBackground(QImage &img, const QColor &col) { // Convert background to transparent, and text to correct colour... img=img.convertToFormat(QImage::Format_ARGB32); for(int x=0; xh) { origHeight=h; h=bSize+8; } } if(xft()->init(needAlpha ? Qt::black : txt, needAlpha ? Qt::white : bgnd, constInitialWidth, h)) { XftFont *xftFont=getFont(fSize); QString text(itsPreviewString); if(xftFont) { bool rv=false; int usedWidth=0; if(hasStr(xftFont, text) || hasStr(xftFont, text=text.toUpper()) || hasStr(xftFont, text=text.toLower())) { XGlyphInfo extents; const FcChar16 *str=(FcChar16 *)(text.utf16()); XftTextExtents16(QX11Info::display(), xftFont, str, text.length(), &extents); int y=(h-extents.height)/2; rv=xft()->drawString(xftFont, text, constOffset, y, h); usedWidth=extents.width; } else { int x=constOffset, y=constOffset; QRect used; rv=xft()->drawAllGlyphs(xftFont, fSize, x, y, constInitialWidth, h, true, text.length(), &used); if(rv) usedWidth=used.width(); } if(rv) { img=xft()->toImage(constInitialWidth, h); if(!img.isNull()) { if(origHeight) { int width=(int)((usedWidth*(double)(((double)h)/((double)origHeight)))+0.5); img=img.scaledToHeight(origHeight, Qt::SmoothTransformation) .copy(0, 0, width+(2*constOffset)init(needAlpha ? Qt::black : txt, needAlpha ? Qt::white : bgnd, w, h)) { bool rv=false; if(hasStr(xftFont, text) || hasStr(xftFont, text=text.toUpper()) || hasStr(xftFont, text=text.toLower())) { XGlyphInfo extents; const FcChar16 *str=(FcChar16 *)(text.utf16()); XftTextExtents16(QX11Info::display(), xftFont, str, text.length(), &extents); int x=0, y=0; rv=xft()->drawString(xftFont, text, x, y, h); } else { int x=0, y=0; QRect used; rv=xft()->drawAllGlyphs(xftFont, h, x, y, w, h, true, text.length(), &used); } if(rv) { img=xft()->toImage(w, h); if(!img.isNull()) { img=img.copy(0, 0, w, h); if(needAlpha) setTransparentBackground(img, txt); } } } closeFont(xftFont); } } } return img; } QImage CFcEngine::draw(const QString &name, quint32 style, int faceNo, const QColor &txt, const QColor &bgnd, int w, int h, bool thumb, const QList &range, QList *chars) { QImage img; const qreal dpr = qApp->devicePixelRatio(); w = w * dpr; h = h * dpr; bool rv=false; if(chars) chars->clear(); if(!name.isEmpty() && ((name==itsName && style==itsStyle && File::equalIndex(faceNo, itsIndex)) || parse(name, style, faceNo)) ) { // // We allow kio_thumbnail to cache our thumbs. Normal is 128x128, and large is 256x256 // ...if kio_thumbnail asks us for a bigger size, then it is probably the file info dialog, in // which case treat it as a normal preview... if(thumb && (h>256 || w!=h)) thumb=false; int x=0, y=0; getSizes(); if(itsSizes.size()) { int imgWidth(thumb && itsScalable ? w*4 : w), imgHeight(thumb && itsScalable ? h*4 : h); bool needAlpha(bgnd.alpha()<255); if(xft()->init(needAlpha ? Qt::black : txt, needAlpha ? Qt::white : bgnd, imgWidth, imgHeight)) { - XftFont *xftFont=NULL; + XftFont *xftFont=nullptr; int line1Pos(0), line2Pos(0); QRect used(0, 0, 0, 0); if(thumb) { QString text(itsScalable ? i18nc("First letter of the alphabet (in upper then lower case)", "Aa") : i18nc("All letters of the alphabet (in upper/lower case pairs), followed by numbers", "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789")); // // Calculate size of text... int fSize=h; if(!itsScalable) // Then need to get nearest size... { int bSize=0; for(int s=0; s=(text.length()/2)) break; } if(itsScalable ? valid.length()!=text.length() : valid.length()<(text.length()/2)) xft()->drawAllChars(xftFont, fSize, x, y, imgWidth, imgHeight, true, - itsScalable ? 2 : -1, itsScalable ? &used : NULL); + itsScalable ? 2 : -1, itsScalable ? &used : nullptr); else { QVector ucs4(valid.toUcs4()); QRect r; for(int ch=0; chdrawChar32(xftFont, ucs4[ch], x, y, imgWidth, imgHeight, fSize, r)) { if(used.isEmpty()) used=r; else used=used.united(r); } else break; } closeFont(xftFont); } } else if(0==range.count()) { QString lowercase(getLowercaseLetters()), uppercase(getUppercaseLetters()), punctuation(getPunctuation()); drawName(x, y, h); y+=4; line1Pos=y; y+=8; xftFont=getFont(alphaSize()); if(xftFont) { bool lc(hasStr(xftFont, lowercase)), uc(hasStr(xftFont, uppercase)), drawGlyphs=!lc && !uc; if(drawGlyphs) y-=8; else { QString validPunc(usableStr(xftFont, punctuation)); bool punc(validPunc.length()>=(punctuation.length()/2)); if(lc) xft()->drawString(xftFont, lowercase, x, y, h); if(uc) xft()->drawString(xftFont, uppercase, x, y, h); if(punc) xft()->drawString(xftFont, validPunc, x, y, h); if(lc || uc || punc) line2Pos=y+2; y+=8; } QString previewString(getPreviewString()); if(!drawGlyphs) { if(!lc && uc) previewString=previewString.toUpper(); if(!uc && lc) previewString=previewString.toLower(); } closeFont(xftFont); for(int s=0; sascent+xftFont->descent; rv=true; if(drawGlyphs) xft()->drawAllChars(xftFont, fontHeight, x, y, w, h, itsSizes.count()>1); else xft()->drawString(xftFont, previewString, x, y, h); closeFont(xftFont); } } } else if(1==range.count() && (range.first().null() || 0==range.first().to)) { if(range.first().null()) { drawName(x, y, h); if((xftFont=getFont(alphaSize()))) { int fontHeight=xftFont->ascent+xftFont->descent; xft()->drawAllGlyphs(xftFont, fontHeight, x, y, w, h, false); rv=true; closeFont(xftFont); } } else if((xftFont=getFont(int(imgWidth*0.85)))) { rv=xft()->drawChar32Centre(xftFont, (*(range.begin())).from, imgWidth, imgHeight); closeFont(xftFont); } } else { QList::ConstIterator it(range.begin()), end(range.end()); if((xftFont=getFont(alphaSize()))) { rv=true; drawName(x, y, h); y+=alphaSize(); bool stop=false; int fontHeight=xftFont->ascent+xftFont->descent, xOrig(x), yOrig(y); QRect r; for(it=range.begin(); it!=end && !stop; ++it) for(quint32 c=(*it).from; c<=(*it).to && !stop; ++c) { if(xft()->drawChar32(xftFont, c, x, y, w, h, fontHeight, r)) { if(chars && !r.isEmpty()) chars->append(TChar(r, c)); } else stop=true; } if(x==xOrig && y==yOrig) { // No characters found within the selected range... xft()->drawString(i18n("No characters found."), x, y, h); rv=true; } closeFont(xftFont); } } if(rv) { img=xft()->toImage(imgWidth, imgHeight); if(!img.isNull() && line1Pos) { QPainter p(&img); p.setPen(txt); p.drawLine(0, line1Pos, w-1, line1Pos); if(line2Pos) p.drawLine(0, line2Pos, w-1, line2Pos); } if(!img.isNull()) { if(itsScalable && !used.isEmpty() && (used.width(){}[]"); //krazy:exclude=i18ncheckarg } #ifdef KFI_USE_TRANSLATED_FAMILY_NAME // // Try to get the 'string' that matches the users KDE locale.. QString CFcEngine::getFcLangString(FcPattern *pat, const char *val, const char *valLang) { QString rv; QStringList kdeLangs=KLocale::global()->languageList(), fontLangs; QStringList::ConstIterator it(kdeLangs.begin()), end(kdeLangs.end()); // Create list of langs that this font's 'val' is encoded in... for(int i=0; true; ++i) { QString lang=getFcString(pat, valLang, i); if(lang.isEmpty()) break; else fontLangs.append(lang); } // Now go through the user's KDE locale, and try to find a font match... for(; it!=end; ++it) { int index=fontLangs.findIndex(*it); if(-1!=index) { rv=getFcString(pat, val, index); if(!rv.isEmpty()) break; } } if(rv.isEmpty()) rv=getFcString(pat, val, 0); return rv; } #endif QFont CFcEngine::getQFont(const QString &family, quint32 style, int size) { int weight, width, slant; FC::decomposeStyleVal(style, weight, width, slant); QFont font(family, size, fcToQtWeight(weight), fcToQtSlant(slant)); #ifndef KFI_FC_NO_WIDTHS font.setStretch(fcToQtWidth(width)); #endif return font; } bool CFcEngine::parse(const QString &name, quint32 style, int face) { if(name.isEmpty()) return false; reinit(); itsName=name; itsStyle=style; itsSizes.clear(); itsInstalled=!isFileName(name, style); if(!itsInstalled) { int count; FcPattern *pat=FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(itsName).data()), - face<1 ? 0 : face, NULL, &count); + face<1 ? 0 : face, nullptr, &count); if(!pat) return false; itsDescriptiveName=FC::createName(pat); FcPatternDestroy(pat); } else itsDescriptiveName=FC::createName(itsName, itsStyle); itsIndex=face<1 ? 0 : face; if(!itsInstalled) // Then add to fontconfig's list, so that Xft can display it... addFontFile(itsName); return true; } XftFont * CFcEngine::queryFont() { static const int constQuerySize=8; #ifdef KFI_FC_DEBUG qDebug(); #endif XftFont *f=getFont(constQuerySize); if(f && !isCorrect(f, true)) closeFont(f); if(itsInstalled && !f) { // Perhaps it is a newly installed font? If so try re-initialising fontconfig... theirFcDirty=true; reinit(); f=getFont(constQuerySize); // This time don't bother checking family - we've re-inited fc anyway, so things should be // up to date... And for "Symbol" Fc returns "Standard Symbols L", so wont match anyway! if(f && !isCorrect(f, false)) closeFont(f); } #ifdef KFI_FC_DEBUG qDebug() << "ret" << (int)f; #endif return f; } XftFont * CFcEngine::getFont(int size) { - XftFont *f=NULL; + XftFont *f=nullptr; #ifdef KFI_FC_DEBUG qDebug() << itsName << ' ' << itsStyle << ' ' << size; #endif if(itsInstalled) { int weight, width, slant; FC::decomposeStyleVal(itsStyle, weight, width, slant); #ifndef KFI_FC_NO_WIDTHS if(KFI_NULL_SETTING!=width) f=XftFontOpen(QX11Info::display(), 0, FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.toUtf8().data()), FC_WEIGHT, FcTypeInteger, weight, FC_SLANT, FcTypeInteger, slant, FC_WIDTH, FcTypeInteger, width, FC_PIXEL_SIZE, FcTypeDouble, (double)size, NULL); else #endif f=XftFontOpen(QX11Info::display(), 0, FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.toUtf8().data()), FC_WEIGHT, FcTypeInteger, weight, FC_SLANT, FcTypeInteger, slant, FC_PIXEL_SIZE, FcTypeDouble, (double)size, NULL); } else { - FcPattern *pattern = FcPatternBuild(NULL, + FcPattern *pattern = FcPatternBuild(nullptr, FC_FILE, FcTypeString, QFile::encodeName(itsName).constData(), FC_INDEX, FcTypeInteger, itsIndex<0 ? 0 : itsIndex, FC_PIXEL_SIZE, FcTypeDouble, (double)size, NULL); f=XftFontOpenPattern(QX11Info::display(), pattern); } #ifdef KFI_FC_DEBUG qDebug() << "ret: " << (int)f; #endif return f; } bool CFcEngine::isCorrect(XftFont *f, bool checkFamily) { int iv, weight, width, slant; FcChar8 *str; if(itsInstalled) FC::decomposeStyleVal(itsStyle, weight, width, slant); #ifdef KFI_FC_DEBUG QString xxx; QTextStream s(&xxx); if(f) { if(itsInstalled) { s << "weight:"; if(FcResultMatch==FcPatternGetInteger(f->pattern, FC_WEIGHT, 0, &iv)) s << iv << '/' << weight; else s << "no"; s << " slant:"; if(FcResultMatch==FcPatternGetInteger(f->pattern, FC_SLANT, 0, &iv)) s << iv << '/' << slant; else s << "no"; s << " width:"; if(FcResultMatch==FcPatternGetInteger(f->pattern, FC_WIDTH, 0, &iv)) s << iv << '/' << width; else s << "no"; s << " fam:"; if(checkFamily) if(FcResultMatch==FcPatternGetString(f->pattern, FC_FAMILY, 0, &str) && str) s << QString::fromUtf8((char *)str) << '/' << itsName; else s << "no"; else s << "ok"; } else s << "NOT Installed... "; } else s << "No font!!! "; qDebug() << "isCorrect? " << xxx; #endif return f ? itsInstalled ? FcResultMatch==FcPatternGetInteger(f->pattern, FC_WEIGHT, 0, &iv) && equalWeight(iv, weight) && FcResultMatch==FcPatternGetInteger(f->pattern, FC_SLANT, 0, &iv) && equalSlant(iv, slant) && #ifndef KFI_FC_NO_WIDTHS (KFI_NULL_SETTING==width || (FcResultMatch==FcPatternGetInteger(f->pattern, FC_WIDTH, 0, &iv) && equalWidth(iv, width))) && #endif (!checkFamily || (FcResultMatch==FcPatternGetString(f->pattern, FC_FAMILY, 0, &str) && str && QString::fromUtf8((char *)str)==itsName)) : (itsIndex<0 || (FcResultMatch==FcPatternGetInteger(f->pattern, FC_INDEX, 0, &iv) && itsIndex==iv)) && FcResultMatch==FcPatternGetString(f->pattern, FC_FILE, 0, &str) && str && QString::fromUtf8((char *)str)==itsName : false; } void CFcEngine::getSizes() { if(!itsSizes.isEmpty()) return; #ifdef KFI_FC_DEBUG qDebug(); #endif XftFont *f=queryFont(); int alphaSize(itsSizes.size()>itsAlphaSizeIndex && itsAlphaSizeIndex>=0 ? itsSizes[itsAlphaSizeIndex] : constDefaultAlphaSize); itsScalable=FcTrue; itsAlphaSizeIndex=0; if(f) { bool gotSizes=false; double px(0.0); if(itsInstalled) { if(FcResultMatch!=FcPatternGetBool(f->pattern, FC_SCALABLE, 0, &itsScalable)) itsScalable=FcFalse; if(!itsScalable) { - FcPattern *pat=NULL; - FcObjectSet *os = FcObjectSetBuild(FC_PIXEL_SIZE, (void*)0); + FcPattern *pat=nullptr; + FcObjectSet *os = FcObjectSetBuild(FC_PIXEL_SIZE, (void*)nullptr); int weight, width, slant; FC::decomposeStyleVal(itsStyle, weight, width, slant); #ifndef KFI_FC_NO_WIDTHS if(KFI_NULL_SETTING!=width) - pat=FcPatternBuild(NULL, + pat=FcPatternBuild(nullptr, FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.toUtf8().data()), FC_WEIGHT, FcTypeInteger, weight, FC_SLANT, FcTypeInteger, slant, FC_WIDTH, FcTypeInteger, width, NULL); else #endif - pat=FcPatternBuild(NULL, + pat=FcPatternBuild(nullptr, FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.toUtf8().data()), FC_WEIGHT, FcTypeInteger, weight, FC_SLANT, FcTypeInteger, slant, NULL); - FcFontSet *set=FcFontList(0, pat, os); + FcFontSet *set=FcFontList(nullptr, pat, os); FcPatternDestroy(pat); FcObjectSetDestroy(os); if (set) { int size(0); #ifdef KFI_FC_DEBUG qDebug() << "got fixed sizes: " << set->nfont; #endif itsSizes.reserve(set->nfont); for (int i = 0; i < set->nfont; i++) if(FcResultMatch==FcPatternGetDouble(set->fonts[i], FC_PIXEL_SIZE, 0, &px)) { gotSizes=true; itsSizes.push_back((int)px); #ifdef KFI_FC_DEBUG qDebug() << "got fixed: " << px; #endif if (px<=alphaSize) itsAlphaSizeIndex=size; size++; } FcFontSetDestroy(set); } } } else { FT_Face face=XftLockFace(f); if(face) { itsIndexCount=face->num_faces; if(!(itsScalable=FT_IS_SCALABLE(face))) { int numSizes=face->num_fixed_sizes, size; gotSizes=true; itsSizes.reserve(numSizes); #ifdef KFI_FC_DEBUG qDebug() << "numSizes fixed: " << numSizes; #endif for (size=0; size= 20105 double px=face->available_sizes[size].y_ppem>>6; #else double px=face->available_sizes[size].width; #endif #ifdef KFI_FC_DEBUG qDebug() << "px: " << px; #endif itsSizes.push_back((int)px); if (px<=alphaSize) itsAlphaSizeIndex=size; } } XftUnlockFace(f); } } closeFont(f); } if(itsScalable) { itsSizes.reserve(sizeof(constScalableSizes)/sizeof(int)); for (int i=0; constScalableSizes[i]; ++i) { int px=point2Pixel(constScalableSizes[i]); if (px<=alphaSize) itsAlphaSizeIndex=i; itsSizes.push_back(px); } } #ifdef KFI_FC_DEBUG qDebug() << "end"; #endif } void CFcEngine::drawName(int x, int &y, int h) { QString title(itsDescriptiveName.isEmpty() ? i18n("ERROR: Could not determine font's name.") : itsDescriptiveName); if(1==itsSizes.size()) title=i18np("%2 [1 pixel]", "%2 [%1 pixels]", itsSizes[0], title); xft()->drawString(title, x, y, h); } void CFcEngine::addFontFile(const QString &file) { if(!itsAddedFiles.contains(file)) { FcInitReinitialize(); FcConfigAppFontAddFile(FcConfigGetCurrent(), (const FcChar8 *)(QFile::encodeName(file).data())); itsAddedFiles.append(file); } } void CFcEngine::reinit() { if(theirFcDirty) { FcInitReinitialize(); theirFcDirty=false; } } CFcEngine::Xft * CFcEngine::xft() { if(!itsXft) itsXft=new Xft; return itsXft; } } diff --git a/kcms/kfontinst/lib/FcEngine.h b/kcms/kfontinst/lib/FcEngine.h index be680b1b6..bfc2b8ab3 100644 --- a/kcms/kfontinst/lib/FcEngine.h +++ b/kcms/kfontinst/lib/FcEngine.h @@ -1,137 +1,137 @@ #ifndef __FC_ENGINE_H__ #define __FC_ENGINE_H__ /* * 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 #include #include #include #include #include "KfiConstants.h" //#include "Misc.h" #include "Fc.h" //Enable the following to use locale aware family name - if font supports this. //#define KFI_USE_TRANSLATED_FAMILY_NAME class KConfig; typedef struct _XftFont XftFont; typedef struct _XftDraw XftDraw; typedef struct _XftColor XftColor; namespace KFI { class Q_DECL_EXPORT CFcEngine { public: class Xft; struct TRange { TRange(quint32 f=0, quint32 t=0) : from(f), to(t) { } bool null() const { return 0==from && 0==to; } quint32 from, to; }; struct TChar : public QRect { TChar(const QRect &r=QRect(), quint32 u=0) : QRect(r), ucs4(u) { } quint32 ucs4; }; static CFcEngine * instance(); CFcEngine(bool init=true); virtual ~CFcEngine(); void readConfig(KConfig &cfg); void writeConfig(KConfig &cfg); static void setDirty() { theirFcDirty=true; } QImage drawPreview(const QString &name, quint32 style, int faceNo, const QColor &txt, const QColor &bgnd, int h); QImage draw(const QString &name, quint32 style, int faceNo, const QColor &txt, const QColor &bgnd, int fSize, const QString &text); QImage draw(const QString &name, quint32 style, int faceNo, const QColor &txt, const QColor &bgnd, - int w, int h, bool thumb, const QList &range=QList(), QList *chars=NULL); + int w, int h, bool thumb, const QList &range=QList(), QList *chars=nullptr); int getNumIndexes() { return itsIndexCount; } // Only valid after draw has been called! static QFont getQFont(const QString &family, quint32 style, int size); const QVector & sizes() const { return itsSizes; } bool atMin() const { return 0==itsSizes.size() || 0==itsAlphaSizeIndex; } bool atMax() const { return 0==itsSizes.size() || itsSizes.size()-1==itsAlphaSizeIndex; } void zoomIn() { if(!atMax()) itsAlphaSizeIndex++; } void zoomOut() { if(!atMin()) itsAlphaSizeIndex--; } int alphaSize() const { return itsSizes[itsAlphaSizeIndex]; } quint32 styleVal() { return itsStyle; } const QString & descriptiveName() const { return itsDescriptiveName; } const QString & getPreviewString(){ return itsPreviewString; } static QString getDefaultPreviewString(); void setPreviewString(const QString &str) { itsPreviewString=str.isEmpty() ? getDefaultPreviewString() : str; } static QString getUppercaseLetters(); static QString getLowercaseLetters(); static QString getPunctuation(); static const int constScalableSizes[]; static const int constDefaultAlphaSize; private: bool parse(const QString &name, quint32 style, int faceNo); XftFont * queryFont(); XftFont * getFont(int size); bool isCorrect(XftFont *f, bool checkFamily); void getSizes(); void drawName(int x, int &y, int h); void addFontFile(const QString &file); void reinit(); Xft * xft(); private: bool itsInstalled; QString itsName, itsDescriptiveName; quint32 itsStyle; int itsIndex, itsIndexCount, itsAlphaSizeIndex; QVector itsSizes; FcBool itsScalable; QStringList itsAddedFiles; QString itsPreviewString; static bool theirFcDirty; Xft *itsXft; }; } #endif diff --git a/kcms/kfontinst/lib/Misc.cpp b/kcms/kfontinst/lib/Misc.cpp index 843df65e0..56113e1c2 100644 --- a/kcms/kfontinst/lib/Misc.cpp +++ b/kcms/kfontinst/lib/Misc.cpp @@ -1,493 +1,493 @@ /* * 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 "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", NULL}, - *pfm[]={"pfm", "PFM", "Pfm", NULL}; + 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/kfontinst/lib/WritingSystems.cpp b/kcms/kfontinst/lib/WritingSystems.cpp index 1ef237000..e5f838f9b 100644 --- a/kcms/kfontinst/lib/WritingSystems.cpp +++ b/kcms/kfontinst/lib/WritingSystems.cpp @@ -1,176 +1,176 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2009 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 #include #include #include "WritingSystems.h" namespace KFI { Q_GLOBAL_STATIC(WritingSystems, theInstance) WritingSystems * WritingSystems::instance() { return theInstance; } static const struct { QFontDatabase::WritingSystem ws; const FcChar8 *lang; } constLanguageForWritingSystem[]= { { QFontDatabase::Latin, (const FcChar8 *)"en" }, { QFontDatabase::Greek, (const FcChar8 *)"el" }, { QFontDatabase::Cyrillic, (const FcChar8 *)"ru" }, { QFontDatabase::Armenian, (const FcChar8 *)"hy" }, { QFontDatabase::Hebrew, (const FcChar8 *)"he" }, { QFontDatabase::Arabic, (const FcChar8 *)"ar" }, { QFontDatabase::Syriac, (const FcChar8 *)"syr" }, { QFontDatabase::Thaana, (const FcChar8 *)"div" }, { QFontDatabase::Devanagari, (const FcChar8 *)"hi" }, { QFontDatabase::Bengali, (const FcChar8 *)"bn" }, { QFontDatabase::Gurmukhi, (const FcChar8 *)"pa" }, { QFontDatabase::Gujarati, (const FcChar8 *)"gu" }, { QFontDatabase::Oriya, (const FcChar8 *)"or" }, { QFontDatabase::Tamil, (const FcChar8 *)"ta" }, { QFontDatabase::Telugu, (const FcChar8 *)"te" }, { QFontDatabase::Kannada, (const FcChar8 *)"kn" }, { QFontDatabase::Malayalam, (const FcChar8 *)"ml" }, { QFontDatabase::Sinhala, (const FcChar8 *)"si" }, { QFontDatabase::Thai, (const FcChar8 *)"th" }, { QFontDatabase::Lao, (const FcChar8 *)"lo" }, { QFontDatabase::Tibetan, (const FcChar8 *)"bo" }, { QFontDatabase::Myanmar, (const FcChar8 *)"my" }, { QFontDatabase::Georgian, (const FcChar8 *)"ka" }, { QFontDatabase::Khmer, (const FcChar8 *)"km" }, { QFontDatabase::SimplifiedChinese, (const FcChar8 *)"zh-cn" }, { QFontDatabase::TraditionalChinese, (const FcChar8 *)"zh-tw" }, { QFontDatabase::Japanese, (const FcChar8 *)"ja" }, { QFontDatabase::Korean, (const FcChar8 *)"ko" }, { QFontDatabase::Vietnamese, (const FcChar8 *)"vi" }, - { QFontDatabase::Other, NULL }, + { QFontDatabase::Other, nullptr }, // The following is only used to save writing system data for disabled fonts... { QFontDatabase::Telugu, (const FcChar8 *)"Qt-Telugu" }, { QFontDatabase::Kannada, (const FcChar8 *)"Qt-Kannada" }, { QFontDatabase::Malayalam, (const FcChar8 *)"Qt-Malayalam" }, { QFontDatabase::Sinhala, (const FcChar8 *)"Qt-Sinhala" }, { QFontDatabase::Myanmar, (const FcChar8 *)"Qt-Myanmar" }, { QFontDatabase::Ogham, (const FcChar8 *)"Qt-Ogham" }, { QFontDatabase::Runic, (const FcChar8 *)"Qt-Runic" }, - { QFontDatabase::Any, NULL } + { QFontDatabase::Any, nullptr } }; inline qulonglong toBit(QFontDatabase::WritingSystem ws) { return ((qulonglong)1) << (int)ws; } //.........the following section is inspired by qfontdatabase_x11.cpp / loadFontConfig // Unfortunately FontConfig doesn't know about some languages. We have to test these through the // charset. The lists below contain the systems where we need to do this. static const struct { QFontDatabase::WritingSystem ws; ushort ch; } sampleCharForWritingSystem[] = { { QFontDatabase::Telugu, 0xc15 }, { QFontDatabase::Kannada, 0xc95 }, { QFontDatabase::Malayalam, 0xd15 }, { QFontDatabase::Sinhala, 0xd9a }, { QFontDatabase::Myanmar, 0x1000 }, { QFontDatabase::Ogham, 0x1681 }, { QFontDatabase::Runic, 0x16a0 }, { QFontDatabase::Any, 0x0 } }; qulonglong WritingSystems::get(FcPattern *pat) const { qulonglong ws(0); - FcLangSet *langset(0); + FcLangSet *langset(nullptr); if (FcResultMatch==FcPatternGetLangSet(pat, FC_LANG, 0, &langset)) { for (int i = 0; constLanguageForWritingSystem[i].lang; ++i) if (FcLangDifferentLang!=FcLangSetHasLang(langset, constLanguageForWritingSystem[i].lang)) ws|=toBit(constLanguageForWritingSystem[i].ws); } else ws|=toBit(QFontDatabase::Other); - FcCharSet *cs(0); + FcCharSet *cs(nullptr); if (FcResultMatch == FcPatternGetCharSet(pat, FC_CHARSET, 0, &cs)) { // some languages are not supported by FontConfig, we rather check the // charset to detect these for (int i = 0; QFontDatabase::Any!=sampleCharForWritingSystem[i].ws; ++i) if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i].ch)) ws|=toBit(sampleCharForWritingSystem[i].ws); } return ws; } //......... qulonglong WritingSystems::get(const QStringList &langs) const { qulonglong ws(0); QStringList::ConstIterator it(langs.begin()), end(langs.end()); for(; it!=end; ++it) ws|=itsMap[*it]; return ws; } QStringList WritingSystems::getLangs(qulonglong ws) const { QMap::ConstIterator wit(itsMap.begin()), wend(itsMap.end()); QStringList systems; for(; wit!=wend; ++wit) if(ws&wit.value()) systems+=wit.key(); return systems; } WritingSystems::WritingSystems() { for(int i=0; QFontDatabase::Any!=constLanguageForWritingSystem[i].ws; ++i) if(constLanguageForWritingSystem[i].lang) itsMap[(const char *)constLanguageForWritingSystem[i].lang]= ((qulonglong)1)< * * ---- * * 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 "FontThumbnail.h" #include "KfiConstants.h" #include "FcEngine.h" #include #include #include #include #include #include #include #include #include #include "debug.h" #define KFI_DBUG qCDebug(KCM_KFONTINST_THUMBNAIL) extern "C" { Q_DECL_EXPORT ThumbCreator *new_creator() { return new KFI::CFontThumbnail; } } namespace KFI { CFontThumbnail::CFontThumbnail() { } bool CFontThumbnail::create(const QString &path, int width, int height, QImage &img) { QString realPath(path); - QTemporaryDir *tempDir = 0; + QTemporaryDir *tempDir = nullptr; KFI_DBUG << "Create font thumbnail for:" << path << endl; // Is this a appliaction/vnd.kde.fontspackage file? If so, extract 1 scalable font... QMimeDatabase db; if (Misc::isPackage(path) || "application/zip" == db.mimeTypeForFile(path, QMimeDatabase::MatchContent).name()) { KZip zip(path); if(zip.open(QIODevice::ReadOnly)) { const KArchiveDirectory *zipDir=zip.directory(); if(zipDir) { QStringList fonts(zipDir->entries()); if(fonts.count()) { QStringList::ConstIterator it(fonts.begin()), end(fonts.end()); for(; it!=end; ++it) { const KArchiveEntry *entry=zipDir->entry(*it); if(entry && entry->isFile()) { delete tempDir; tempDir=new QTemporaryDir(QDir::tempPath() + "/" KFI_TMP_DIR_PREFIX); tempDir->setAutoRemove(true); ((KArchiveFile *)entry)->copyTo(tempDir->path()); QString mime(db.mimeTypeForFile(tempDir->filePath(entry->name())).name()); if(mime=="font/ttf" || mime=="font/otf" || mime=="application/x-font-ttf" || mime=="application/x-font-otf" || mime=="application/x-font-type1") { realPath=tempDir->filePath(entry->name()); break; } else ::unlink(QFile::encodeName(tempDir->filePath(entry->name())).data()); } } } } } } QColor bgnd(Qt::black); bgnd.setAlpha(0); img=itsEngine.draw(realPath, KFI_NO_STYLE_INFO, 0, QApplication::palette().text().color(), bgnd, width, height, true); delete tempDir; return !img.isNull(); } ThumbCreator::Flags CFontThumbnail::flags() const { return None; } } diff --git a/kcms/kfontinst/viewpart/CharTip.cpp b/kcms/kfontinst/viewpart/CharTip.cpp index 90de98d37..92edb761e 100644 --- a/kcms/kfontinst/viewpart/CharTip.cpp +++ b/kcms/kfontinst/viewpart/CharTip.cpp @@ -1,296 +1,296 @@ /* * 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. */ /* * Inspired by konq_filetip.cc * * Copyright (C) 1998, 1999 Torben Weis * Copyright (C) 2000, 2001, 2002 David Faure * Copyright (C) 2004 Martin Koller */ #include "CharTip.h" #include "FontPreview.h" #include "UnicodeCategories.h" #include #include #include #include #include #include #include #include #include namespace KFI { EUnicodeCategory getCategory(quint32 ucs2) { for(int i=0; UNICODE_INVALID!=constUnicodeCategoryList[i].category; ++i) if(constUnicodeCategoryList[i].start<=ucs2 && constUnicodeCategoryList[i].end>=ucs2) return constUnicodeCategoryList[i].category; return UNICODE_UNASSIGNED; } static QString toStr(EUnicodeCategory cat) { switch (cat) { case UNICODE_CONTROL: return i18n("Other, Control"); case UNICODE_FORMAT: return i18n("Other, Format"); case UNICODE_UNASSIGNED: return i18n("Other, Not Assigned"); case UNICODE_PRIVATE_USE: return i18n("Other, Private Use"); case UNICODE_SURROGATE: return i18n("Other, Surrogate"); case UNICODE_LOWERCASE_LETTER: return i18n("Letter, Lowercase"); case UNICODE_MODIFIER_LETTER: return i18n("Letter, Modifier"); case UNICODE_OTHER_LETTER: return i18n("Letter, Other"); case UNICODE_TITLECASE_LETTER: return i18n("Letter, Titlecase"); case UNICODE_UPPERCASE_LETTER: return i18n("Letter, Uppercase"); case UNICODE_COMBINING_MARK: return i18n("Mark, Spacing Combining"); case UNICODE_ENCLOSING_MARK: return i18n("Mark, Enclosing"); case UNICODE_NON_SPACING_MARK: return i18n("Mark, Non-Spacing"); case UNICODE_DECIMAL_NUMBER: return i18n("Number, Decimal Digit"); case UNICODE_LETTER_NUMBER: return i18n("Number, Letter"); case UNICODE_OTHER_NUMBER: return i18n("Number, Other"); case UNICODE_CONNECT_PUNCTUATION: return i18n("Punctuation, Connector"); case UNICODE_DASH_PUNCTUATION: return i18n("Punctuation, Dash"); case UNICODE_CLOSE_PUNCTUATION: return i18n("Punctuation, Close"); case UNICODE_FINAL_PUNCTUATION: return i18n("Punctuation, Final Quote"); case UNICODE_INITIAL_PUNCTUATION: return i18n("Punctuation, Initial Quote"); case UNICODE_OTHER_PUNCTUATION: return i18n("Punctuation, Other"); case UNICODE_OPEN_PUNCTUATION: return i18n("Punctuation, Open"); case UNICODE_CURRENCY_SYMBOL: return i18n("Symbol, Currency"); case UNICODE_MODIFIER_SYMBOL: return i18n("Symbol, Modifier"); case UNICODE_MATH_SYMBOL: return i18n("Symbol, Math"); case UNICODE_OTHER_SYMBOL: return i18n("Symbol, Other"); case UNICODE_LINE_SEPARATOR: return i18n("Separator, Line"); case UNICODE_PARAGRAPH_SEPARATOR: return i18n("Separator, Paragraph"); case UNICODE_SPACE_SEPARATOR: return i18n("Separator, Space"); default: return ""; } } CCharTip::CCharTip(CFontPreview *parent) - : QFrame(0, Qt::ToolTip | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint), + : QFrame(nullptr, Qt::ToolTip | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint), itsParent(parent) { itsPixmapLabel = new QLabel(this); itsLabel = new QLabel(this); itsTimer = new QTimer(this); QBoxLayout* layout = new QBoxLayout(QBoxLayout::LeftToRight, this); layout->setMargin(8); layout->setSpacing(0); layout->addWidget(itsPixmapLabel); layout->addWidget(itsLabel); setPalette(QToolTip::palette()); setFrameShape(QFrame::Box); setFrameShadow(QFrame::Plain); hide(); } CCharTip::~CCharTip() { } void CCharTip::setItem(const CFcEngine::TChar &ch) { hideTip(); itsItem=ch; itsTimer->disconnect(this); connect(itsTimer, SIGNAL(timeout()), this, SLOT(showTip())); itsTimer->setSingleShot(true); itsTimer->start(300); } void CCharTip::showTip() { if(!itsParent->underMouse()) return; static const int constPixSize=96; EUnicodeCategory cat(getCategory(itsItem.ucs4)); QString details(""); details+=""; details+=""; QString str(QString::fromUcs4(&(itsItem.ucs4), 1)); details+=""; details+=""; details+="
    "+i18n("Category")+" "+ toStr(cat)+"
    "+i18n("UCS-4")+" "+ QString().sprintf("U+%4.4X", itsItem.ucs4)+" 
    "+i18n("UTF-16")+" "; const ushort *utf16(str.utf16()); for(int i=0; utf16[i]; ++i) { if(i) details+=' '; details+=QString().sprintf("0x%4.4X", utf16[i]); } details+="
    "+i18n("UTF-8")+" "; QByteArray utf8(str.toUtf8()); for(int i=0; i below is just to stop Qt converting the xml entry into // a character! if ((0x0001 <= itsItem.ucs4 && itsItem.ucs4 <= 0xD7FF) || (0xE000 <= itsItem.ucs4 && itsItem.ucs4 <= 0xFFFD) || (0x10000 <= itsItem.ucs4 && itsItem.ucs4 <= 0x10FFFF)) details+="
    "+i18n("XML Decimal Entity")+" "+ QString().sprintf("&#%d;", itsItem.ucs4)+"
    "; itsLabel->setText(details); QList range; range.append(CFcEngine::TRange(itsItem.ucs4, 0)); QColor bgnd(Qt::white); bgnd.setAlpha(0); QImage img=itsParent->engine()->draw(itsParent->itsFontName, itsParent->itsStyleInfo, itsParent->itsCurrentFace-1, palette().text().color(), bgnd, - constPixSize, constPixSize, false, range, NULL); + constPixSize, constPixSize, false, range, nullptr); if(!img.isNull()) itsPixmapLabel->setPixmap(QPixmap::fromImage(img)); else itsPixmapLabel->setPixmap(QPixmap()); itsTimer->disconnect(this); connect(itsTimer, SIGNAL(timeout()), this, SLOT(hideTip())); itsTimer->setSingleShot(true); itsTimer->start(15000); qApp->installEventFilter(this); reposition(); show(); } void CCharTip::hideTip() { itsTimer->stop(); qApp->removeEventFilter(this); hide(); } void CCharTip::reposition() { QRect rect(itsItem); rect.moveTopRight(itsParent->mapToGlobal(rect.topRight())); QPoint pos(rect.center()); QRect desk(QApplication::desktop()->screenGeometry(rect.center())); if ((rect.center().x() + width()) > desk.right()) { if (pos.x() - width() < 0) pos.setX(0); else pos.setX( pos.x() - width() ); } // should the tooltip be shown above or below the ivi ? if (rect.bottom() + height() > desk.bottom()) pos.setY( rect.top() - height() ); else pos.setY(rect.bottom() + 1); move(pos); update(); } void CCharTip::resizeEvent(QResizeEvent *event) { QFrame::resizeEvent(event); reposition(); } bool CCharTip::eventFilter(QObject *, QEvent *e) { switch (e->type()) { case QEvent::Leave: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::KeyPress: case QEvent::KeyRelease: case QEvent::FocusIn: case QEvent::FocusOut: case QEvent::Wheel: hideTip(); default: break; } return false; } } diff --git a/kcms/kfontinst/viewpart/FontPreview.cpp b/kcms/kfontinst/viewpart/FontPreview.cpp index c1749584f..c192f9fe6 100644 --- a/kcms/kfontinst/viewpart/FontPreview.cpp +++ b/kcms/kfontinst/viewpart/FontPreview.cpp @@ -1,178 +1,178 @@ /* * 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 "FontPreview.h" #include "FcEngine.h" #include "CharTip.h" #include #include #include #include #include namespace KFI { static const int constBorder=4; static const int constStepSize=16; CFontPreview::CFontPreview(QWidget *parent) : QWidget(parent), itsCurrentFace(1), itsLastWidth(0), itsLastHeight(0), itsStyleInfo(KFI_NO_STYLE_INFO), - itsTip(NULL) + itsTip(nullptr) { itsEngine=new CFcEngine; } CFontPreview::~CFontPreview() { delete itsTip; delete itsEngine; } void CFontPreview::showFont(const QString &name, unsigned long styleInfo, int face) { itsFontName=name; itsStyleInfo=styleInfo; showFace(face); } void CFontPreview::showFace(int face) { itsCurrentFace=face; showFont(); } void CFontPreview::showFont() { itsLastWidth=width()+constStepSize; itsLastHeight=height()+constStepSize; itsImage=itsEngine->draw(itsFontName, itsStyleInfo, itsCurrentFace, palette().text().color(), palette().base().color(), itsLastWidth, itsLastHeight, false, itsRange, &itsChars); if(!itsImage.isNull()) { itsLastChar=CFcEngine::TChar(); setMouseTracking(itsChars.count()>0); update(); emit status(true); emit atMax(itsEngine->atMax()); emit atMin(itsEngine->atMin()); } else { itsLastChar=CFcEngine::TChar(); setMouseTracking(false); update(); emit status(false); emit atMax(true); emit atMin(true); } } void CFontPreview::zoomIn() { itsEngine->zoomIn(); showFont(); emit atMax(itsEngine->atMax()); } void CFontPreview::zoomOut() { itsEngine->zoomOut(); showFont(); emit atMin(itsEngine->atMin()); } void CFontPreview::setUnicodeRange(const QList &r) { itsRange=r; showFont(); } void CFontPreview::paintEvent(QPaintEvent *) { QPainter paint(this); paint.fillRect(rect(), palette().base()); if(!itsImage.isNull()) { if(abs(width()-itsLastWidth)>constStepSize || abs(height()-itsLastHeight)>constStepSize) showFont(); else paint.drawImage(QPoint(constBorder, constBorder), itsImage, QRect(0, 0, width()-(constBorder*2) * itsImage.devicePixelRatioF(), height()-(constBorder*2) * itsImage.devicePixelRatioF())); } } void CFontPreview::mouseMoveEvent(QMouseEvent *event) { if(itsChars.size()) { QList::ConstIterator end(itsChars.end()); if(itsLastChar.isNull() || !itsLastChar.contains(event->pos())) for(QList::ConstIterator it(itsChars.begin()); it!=end; ++it) if((*it).contains(event->pos())) { if(!itsTip) itsTip=new CCharTip(this); itsTip->setItem(*it); itsLastChar=*it; break; } } } void CFontPreview::wheelEvent(QWheelEvent *e) { if(e->delta()>0) zoomIn(); else if(e->delta()<0) zoomOut(); e->accept(); } QSize CFontPreview::sizeHint() const { return QSize(132, 132); } QSize CFontPreview::minimumSizeHint() const { return QSize(32, 32); } } diff --git a/kcms/kfontinst/viewpart/FontViewPart.cpp b/kcms/kfontinst/viewpart/FontViewPart.cpp index a155c32b7..4637df015 100644 --- a/kcms/kfontinst/viewpart/FontViewPart.cpp +++ b/kcms/kfontinst/viewpart/FontViewPart.cpp @@ -1,578 +1,578 @@ /* * 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 "FontViewPart.h" #include "Misc.h" #include "KfiConstants.h" #include "FcEngine.h" #include "PreviewSelectAction.h" #include "FontInstInterface.h" #include "FontInst.h" #include "config-workspace.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 "config-fontinst.h" // Enable the following to allow printing of non-installed fonts. Does not seem to work :-( //#define KFI_PRINT_APP_FONTS namespace KFI { static QString getFamily(const QString &font) { int commaPos=font.lastIndexOf(','); return -1==commaPos ? font : font.left(commaPos); } K_PLUGIN_FACTORY(CFontViewPartFactory, registerPlugin();) K_EXPORT_PLUGIN(CFontViewPartFactory("kfontview")) CFontViewPart::CFontViewPart(QWidget *parentWidget, QObject *parent, const QList &) : KParts::ReadOnlyPart(parent), itsConfig(KSharedConfig::openConfig()), - itsProc(NULL), - itsTempDir(NULL), + itsProc(nullptr), + itsTempDir(nullptr), itsInterface(new FontInstInterface()), itsOpening(false) { // create browser extension (for printing when embedded into browser) itsExtension = new BrowserExtension(this); itsFrame=new QFrame(parentWidget); QFrame *previewFrame=new QFrame(itsFrame); QWidget *controls=new QWidget(itsFrame); // QGroupBox *metaBox=new QGroupBox(i18n("Information:"), controls); itsFaceWidget=new QWidget(controls); QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::TopToBottom, itsFrame); QBoxLayout *previewLayout=new QBoxLayout(QBoxLayout::LeftToRight, previewFrame), *controlsLayout=new QBoxLayout(QBoxLayout::LeftToRight, controls), *faceLayout=new QBoxLayout(QBoxLayout::LeftToRight, itsFaceWidget); // QBoxLayout *metaLayout=new QBoxLayout(QBoxLayout::LeftToRight, metaBox); // itsMetaLabel=new QLabel(metaBox); // itsMetaLabel->setAlignment(Qt::AlignTop); // metaLayout->addWidget(itsMetaLabel); previewLayout->setMargin(0); previewLayout->setSpacing(0); faceLayout->setMargin(0); controlsLayout->setMargin(0); previewLayout->setSpacing(0); itsFrame->setFrameShape(QFrame::NoFrame); itsFrame->setFocusPolicy(Qt::ClickFocus); previewFrame->setFrameShape(QFrame::StyledPanel); previewFrame->setFrameShadow(QFrame::Sunken); KAboutData aboutData(KFI_NAME, i18n("FontViewPart"), WORKSPACE_VERSION_STRING); setComponentData(aboutData); itsPreview=new CFontPreview(previewFrame); itsPreview->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); itsFaceLabel=new QLabel(i18n("Show Face:"), itsFaceWidget); itsFaceSelector=new QSpinBox(itsFaceWidget); itsFaceSelector->setValue(1); itsInstallButton=new QPushButton(i18n("Install..."), controls); itsInstallButton->setEnabled(false); previewLayout->addWidget(itsPreview); faceLayout->addWidget(itsFaceLabel); faceLayout->addWidget(itsFaceSelector); faceLayout->addItem(new QSpacerItem(faceLayout->spacing(), 0, QSizePolicy::Fixed, QSizePolicy::Fixed)); itsFaceWidget->hide(); itsPreview->engine()->readConfig(*itsConfig); //controlsLayout->addWidget(metaBox); //controlsLayout->addStretch(2); controlsLayout->addWidget(itsFaceWidget); controlsLayout->addStretch(1); controlsLayout->addWidget(itsInstallButton); mainLayout->addWidget(previewFrame); mainLayout->addWidget(controls); connect(itsPreview, SIGNAL(status(bool)), SLOT(previewStatus(bool))); connect(itsInstallButton, SIGNAL(clicked()), SLOT(install())); connect(itsFaceSelector, SIGNAL(valueChanged(int)), SLOT(showFace(int))); itsChangeTextAction=actionCollection()->addAction("changeText"); itsChangeTextAction->setIcon(QIcon::fromTheme("edit-rename")); itsChangeTextAction->setText(i18n("Change Text...")); connect(itsChangeTextAction, SIGNAL(triggered(bool)), SLOT(changeText())); CPreviewSelectAction *displayTypeAction=new CPreviewSelectAction(this, CPreviewSelectAction::BlocksAndScripts); actionCollection()->addAction("displayType", displayTypeAction); connect(displayTypeAction, SIGNAL(range(QList)), SLOT(displayType(QList))); QAction *zoomIn=actionCollection()->addAction(KStandardAction::ZoomIn, itsPreview, SLOT(zoomIn())), *zoomOut=actionCollection()->addAction(KStandardAction::ZoomOut, itsPreview, SLOT(zoomOut())); connect(itsPreview, SIGNAL(atMax(bool)), zoomIn, SLOT(setDisabled(bool))); connect(itsPreview, SIGNAL(atMin(bool)), zoomOut, SLOT(setDisabled(bool))); setXMLFile("kfontviewpart.rc"); setWidget(itsFrame); itsExtension->enablePrint(false); FontInst::registerTypes(); connect(itsInterface, SIGNAL(status(int,int)), SLOT(dbusStatus(int,int))); connect(itsInterface, SIGNAL(fontStat(int,KFI::Family)), SLOT(fontStat(int,KFI::Family))); } CFontViewPart::~CFontViewPart() { delete itsTempDir; - itsTempDir=NULL; + itsTempDir=nullptr; delete itsInterface; - itsInterface=NULL; + itsInterface=nullptr; } static inline QUrl mostLocalUrl(const QUrl &url, QWidget *widget) { auto job = KIO::mostLocalUrl(url); KJobWidgets::setWindow(job, widget); job->exec(); return job->mostLocalUrl(); } bool CFontViewPart::openUrl(const QUrl &url) { if (!url.isValid() || !closeUrl()) return false; // itsMetaLabel->setText(QString()); // itsMetaInfo.clear(); itsFontDetails=FC::decode(url); if(!itsFontDetails.family.isEmpty() || KFI_KIO_FONTS_PROTOCOL==url.scheme() || mostLocalUrl(url, itsFrame).isLocalFile()) { setUrl(url); - emit started(0); + emit started(nullptr); setLocalFilePath(this->url().path()); bool ret=openFile(); if (ret) emit completed(); return ret; } else return ReadOnlyPart::openUrl(url); } bool CFontViewPart::openFile() { // NOTE: Can't do the real open here, as we don't seem to be able to use KIO::NetAccess functions // during initial start-up. Bug report 111535 indicates that calling "konqueror " crashes. itsInstallButton->setEnabled(false); QTimer::singleShot(0, this, SLOT(timeout())); return true; } static inline bool statUrl(const QUrl &url, KIO::UDSEntry *udsEntry) { auto job = KIO::stat(url); job->exec(); if (job->error()) return false; *udsEntry = job->statResult(); return true; } void CFontViewPart::timeout() { if(!itsInstallButton) return; bool isFonts(KFI_KIO_FONTS_PROTOCOL==url().scheme()), showFs(false), package(false); int fileIndex(-1); QString fontFile; // itsMetaUrl=url(); delete itsTempDir; - itsTempDir=NULL; + itsTempDir=nullptr; itsOpening=true; if(!itsFontDetails.family.isEmpty()) { emit setWindowCaption(FC::createName(itsFontDetails.family, itsFontDetails.styleInfo)); fontFile=FC::getFile(url()); fileIndex=FC::getIndex(url()); } else if(isFonts) { KIO::UDSEntry udsEntry; bool found = statUrl(url(), &udsEntry); if(!found) { // Check if url is "fonts:/ if so try fonts:/System/, then fonts:/Personal QStringList pathList(url().adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), QString::SkipEmptyParts)); if(pathList.count()==1) { found = statUrl(QUrl(QString("fonts:/"+i18n(KFI_KIO_FONTS_SYS)+QLatin1Char('/')+pathList[0])), &udsEntry); if (!found) found = statUrl(QUrl(QString("fonts:/"+i18n(KFI_KIO_FONTS_USER)+QLatin1Char('/')+pathList[0])), &udsEntry); } } if(found) { if(udsEntry.numberValue(KIO::UDSEntry::UDS_HIDDEN, 0)) { fontFile=udsEntry.stringValue(UDS_EXTRA_FILE_NAME); fileIndex=udsEntry.numberValue(UDS_EXTRA_FILE_FACE, 0); } itsFontDetails.family=getFamily(udsEntry.stringValue(KIO::UDSEntry::UDS_NAME)); itsFontDetails.styleInfo=udsEntry.numberValue(UDS_EXTRA_FC_STYLE); emit setWindowCaption(udsEntry.stringValue(KIO::UDSEntry::UDS_NAME)); } else { previewStatus(false); return; } } else { QString path(localFilePath()); // Is this a application/vnd.kde.fontspackage file? If so, extract 1 scalable font... if((package=Misc::isPackage(path))) { KZip zip(path); if(zip.open(QIODevice::ReadOnly)) { const KArchiveDirectory *zipDir=zip.directory(); if(zipDir) { QStringList fonts(zipDir->entries()); if(fonts.count()) { QStringList::ConstIterator it(fonts.begin()), end(fonts.end()); for(; it!=end; ++it) { const KArchiveEntry *entry=zipDir->entry(*it); if(entry && entry->isFile()) { delete itsTempDir; itsTempDir=new QTemporaryDir(QDir::tempPath() + "/" KFI_TMP_DIR_PREFIX); itsTempDir->setAutoRemove(true); ((KArchiveFile *)entry)->copyTo(itsTempDir->path()); QMimeDatabase db; QString mime(db.mimeTypeForFile(itsTempDir->filePath(entry->name())).name()); if(mime=="font/ttf" || mime=="font/otf" || mime=="application/x-font-ttf" || mime=="application/x-font-otf" || mime=="application/x-font-type1") { fontFile=itsTempDir->filePath(entry->name()); //setLocalFilePath(itsTempDir->path()+QLatin1Char('/')+entry->name()); // itsMetaUrl=QUrl::fromLocalFile(localFilePath()); break; } else ::unlink(QFile::encodeName(itsTempDir->filePath(entry->name())).data()); } } } } } } } itsInstallButton->setEnabled(false); if(itsFontDetails.family.isEmpty()) emit setWindowCaption(url().toDisplayString()); else FcInitReinitialize(); itsPreview->showFont(!package && itsFontDetails.family.isEmpty() ? localFilePath() : fontFile.isEmpty() ? itsFontDetails.family : fontFile, itsFontDetails.styleInfo, fileIndex); if(!isFonts && itsPreview->engine()->getNumIndexes()>1) { showFs=true; itsFaceSelector->setRange(1, itsPreview->engine()->getNumIndexes()); itsFaceSelector->setSingleStep(1); itsFaceSelector->blockSignals(true); itsFaceSelector->setValue(1); itsFaceSelector->blockSignals(false); } itsFaceWidget->setVisible(showFs); } void CFontViewPart::previewStatus(bool st) { if(itsOpening) { bool printable(false); if(st) { checkInstallable(); if(Misc::app(KFI_PRINTER).isEmpty()) printable=false; if(KFI_KIO_FONTS_PROTOCOL==url().scheme()) printable=!Misc::isHidden(url()); else if(!FC::decode(url()).family.isEmpty()) printable=!Misc::isHidden(FC::getFile(url())); #ifdef KFI_PRINT_APP_FONTS else { // TODO: Make this work! Plus, printing of disabled TTF/OTF's should also be possible! KMimeType::Ptr mime=KMimeType::findByUrl(QUrl::fromLocalFile(localFilePath()), 0, false, true); printable=mime->is("application/x-font-ttf") || mime->is("application/x-font-otf"); } #endif } itsExtension->enablePrint(st && printable); itsOpening=false; } itsChangeTextAction->setEnabled(st); // if(st) // getMetaInfo(itsFaceSelector->isVisible() && itsFaceSelector->value()>0 // ? itsFaceSelector->value()-1 : 0); // else if(!st) KMessageBox::error(itsFrame, i18n("Could not read font.")); } void CFontViewPart::install() { if(!itsProc || QProcess::NotRunning==itsProc->state()) { QStringList args; if(!itsProc) itsProc=new QProcess(this); else itsProc->kill(); QString title = QGuiApplication::applicationDisplayName(); if (title.isEmpty()) title = QCoreApplication::applicationName(); args << "--embed" << QString().sprintf("0x%x", (unsigned int)(itsFrame->window()->winId())) << "--qwindowtitle" << title << "--qwindowicon" << "kfontview" << url().toDisplayString(); connect(itsProc, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(installlStatus())); itsProc->start(Misc::app(KFI_INSTALLER), args); itsInstallButton->setEnabled(false); } } void CFontViewPart::installlStatus() { checkInstallable(); } void CFontViewPart::dbusStatus(int pid, int status) { if(pid==getpid() && FontInst::STATUS_OK!=status) itsInstallButton->setEnabled(false); } void CFontViewPart::fontStat(int pid, const KFI::Family &font) { if(pid==getpid()) itsInstallButton->setEnabled(!Misc::app(KFI_INSTALLER).isEmpty() && font.styles().count()==0); } void CFontViewPart::changeText() { bool status; QString oldStr(itsPreview->engine()->getPreviewString()), newStr(QInputDialog::getText(itsFrame, i18n("Preview String"), i18n("Please enter new string:"), QLineEdit::Normal, oldStr, &status)); if(status && newStr!=oldStr) { itsPreview->engine()->setPreviewString(newStr); itsPreview->engine()->writeConfig(*itsConfig); itsPreview->showFont(); } } void CFontViewPart::print() { QStringList args; QString title = QGuiApplication::applicationDisplayName(); if (title.isEmpty()) title = QCoreApplication::applicationName(); if(!itsFontDetails.family.isEmpty()) { args << "--embed" << QString().sprintf("0x%x", (unsigned int)(itsFrame->window()->winId())) << "--qwindowtitle" << title << "--qwindowicon" << "kfontview" << "--size" << "0" << "--pfont" << QString(itsFontDetails.family+','+QString().setNum(itsFontDetails.styleInfo)); } #ifdef KFI_PRINT_APP_FONTS else args << "--embed" << QString().sprintf("0x%x", (unsigned int)(itsFrame->window()->winId())) << "--qwindowtitle" << title << "--qwindowicon" << "kfontview" << "--size " << "0" << localFilePath() << QString().setNum(KFI_NO_STYLE_INFO); #endif if(args.count()) QProcess::startDetached(Misc::app(KFI_PRINTER), args); } void CFontViewPart::displayType(const QList &range) { itsPreview->setUnicodeRange(range); itsChangeTextAction->setEnabled(0==range.count()); } void CFontViewPart::showFace(int face) { itsPreview->showFace(face-1); } void CFontViewPart::checkInstallable() { if(itsFontDetails.family.isEmpty()) { if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(OrgKdeFontinstInterface::staticInterfaceName())) QProcess::startDetached(QLatin1String(KFONTINST_LIB_EXEC_DIR"/fontinst"), QStringList()); itsInstallButton->setEnabled(false); itsInterface->statFont(itsPreview->engine()->descriptiveName(), FontInst::SYS_MASK|FontInst::USR_MASK, getpid()); } } #if 0 void CFontViewPart::getMetaInfo(int face) { if(itsMetaInfo[face].isEmpty()) { // Pass as much inofmration as possible to analyzer... if(KFI_KIO_FONTS_PROTOCOL!=itsMetaUrl.protocol()) { itsMetaUrl.removeQueryItem(KFI_KIO_FACE); if(face>0) itsMetaUrl.addQueryItem(KFI_KIO_FACE, QString().setNum(face)); } KFileMetaInfo meta(itsMetaUrl); if(meta.isValid() && meta.keys().count()) { QStringList keys(meta.keys()); QStringList::const_iterator it(keys.begin()), end(keys.end()); itsMetaInfo[face]=""; for(; it!=end; ++it) { KFileMetaInfoItem mi(meta.item(*it)); itsMetaInfo[face]+=""; } itsMetaInfo[face]+="
    "+mi.name()+"
    "+ mi.value().toString()+"
    "; itsMetaLabel->setText(itsMetaInfo[face]); } else itsMetaLabel->setText(i18n("

    No information

    ")); } else itsMetaLabel->setText(itsMetaInfo[face]); } #endif BrowserExtension::BrowserExtension(CFontViewPart *parent) : KParts::BrowserExtension(parent) { setURLDropHandlingEnabled(true); } void BrowserExtension::enablePrint(bool enable) { if(enable!=isActionEnabled("print") && (!enable || !Misc::app(KFI_PRINTER).isEmpty())) emit enableAction("print", enable); } void BrowserExtension::print() { if(!Misc::app(KFI_PRINTER).isEmpty()) static_cast(parent())->print(); } } #include "FontViewPart.moc" diff --git a/kcms/kfontinst/viewpart/UnicodeBlocks.h b/kcms/kfontinst/viewpart/UnicodeBlocks.h index 1b978b719..57685d43e 100644 --- a/kcms/kfontinst/viewpart/UnicodeBlocks.h +++ b/kcms/kfontinst/viewpart/UnicodeBlocks.h @@ -1,179 +1,179 @@ /* UnicodeBlocks.h */ /* THIS IS A GENERATED FILE. CHANGES WILL BE OVERWRITTEN. */ /* Generated by generate-unicode-tables.pl */ /* Generated from UCD version 5.0 */ #ifndef __UNICODE_BLOCKS_H__ #define __UNICODE_BLOCKS_H__ #include #include struct TUnicodeBlock { quint32 start, end; const char *blockName; }; static const struct TUnicodeBlock constUnicodeBlocks[] = { { 0x0000, 0x007F, I18N_NOOP("Basic Latin") }, { 0x0080, 0x00FF, I18N_NOOP("Latin-1 Supplement") }, { 0x0100, 0x017F, I18N_NOOP("Latin Extended-A") }, { 0x0180, 0x024F, I18N_NOOP("Latin Extended-B") }, { 0x0250, 0x02AF, I18N_NOOP("IPA Extensions") }, { 0x02B0, 0x02FF, I18N_NOOP("Spacing Modifier Letters") }, { 0x0300, 0x036F, I18N_NOOP("Combining Diacritical Marks") }, { 0x0370, 0x03FF, I18N_NOOP("Greek and Coptic") }, { 0x0400, 0x04FF, I18N_NOOP("Cyrillic") }, { 0x0500, 0x052F, I18N_NOOP("Cyrillic Supplement") }, { 0x0530, 0x058F, I18N_NOOP("Armenian") }, { 0x0590, 0x05FF, I18N_NOOP("Hebrew") }, { 0x0600, 0x06FF, I18N_NOOP("Arabic") }, { 0x0700, 0x074F, I18N_NOOP("Syriac") }, { 0x0750, 0x077F, I18N_NOOP("Arabic Supplement") }, { 0x0780, 0x07BF, I18N_NOOP("Thaana") }, { 0x07C0, 0x07FF, I18N_NOOP("NKo") }, { 0x0900, 0x097F, I18N_NOOP("Devanagari") }, { 0x0980, 0x09FF, I18N_NOOP("Bengali") }, { 0x0A00, 0x0A7F, I18N_NOOP("Gurmukhi") }, { 0x0A80, 0x0AFF, I18N_NOOP("Gujarati") }, { 0x0B00, 0x0B7F, I18N_NOOP("Oriya") }, { 0x0B80, 0x0BFF, I18N_NOOP("Tamil") }, { 0x0C00, 0x0C7F, I18N_NOOP("Telugu") }, { 0x0C80, 0x0CFF, I18N_NOOP("Kannada") }, { 0x0D00, 0x0D7F, I18N_NOOP("Malayalam") }, { 0x0D80, 0x0DFF, I18N_NOOP("Sinhala") }, { 0x0E00, 0x0E7F, I18N_NOOP("Thai") }, { 0x0E80, 0x0EFF, I18N_NOOP("Lao") }, { 0x0F00, 0x0FFF, I18N_NOOP("Tibetan") }, { 0x1000, 0x109F, I18N_NOOP("Myanmar") }, { 0x10A0, 0x10FF, I18N_NOOP("Georgian") }, { 0x1100, 0x11FF, I18N_NOOP("Hangul Jamo") }, { 0x1200, 0x137F, I18N_NOOP("Ethiopic") }, { 0x1380, 0x139F, I18N_NOOP("Ethiopic Supplement") }, { 0x13A0, 0x13FF, I18N_NOOP("Cherokee") }, { 0x1400, 0x167F, I18N_NOOP("Unified Canadian Aboriginal Syllabics") }, { 0x1680, 0x169F, I18N_NOOP("Ogham") }, { 0x16A0, 0x16FF, I18N_NOOP("Runic") }, { 0x1700, 0x171F, I18N_NOOP("Tagalog") }, { 0x1720, 0x173F, I18N_NOOP("Hanunoo") }, { 0x1740, 0x175F, I18N_NOOP("Buhid") }, { 0x1760, 0x177F, I18N_NOOP("Tagbanwa") }, { 0x1780, 0x17FF, I18N_NOOP("Khmer") }, { 0x1800, 0x18AF, I18N_NOOP("Mongolian") }, { 0x1900, 0x194F, I18N_NOOP("Limbu") }, { 0x1950, 0x197F, I18N_NOOP("Tai Le") }, { 0x1980, 0x19DF, I18N_NOOP("New Tai Lue") }, { 0x19E0, 0x19FF, I18N_NOOP("Khmer Symbols") }, { 0x1A00, 0x1A1F, I18N_NOOP("Buginese") }, { 0x1B00, 0x1B7F, I18N_NOOP("Balinese") }, { 0x1D00, 0x1D7F, I18N_NOOP("Phonetic Extensions") }, { 0x1D80, 0x1DBF, I18N_NOOP("Phonetic Extensions Supplement") }, { 0x1DC0, 0x1DFF, I18N_NOOP("Combining Diacritical Marks Supplement") }, { 0x1E00, 0x1EFF, I18N_NOOP("Latin Extended Additional") }, { 0x1F00, 0x1FFF, I18N_NOOP("Greek Extended") }, { 0x2000, 0x206F, I18N_NOOP("General Punctuation") }, { 0x2070, 0x209F, I18N_NOOP("Superscripts and Subscripts") }, { 0x20A0, 0x20CF, I18N_NOOP("Currency Symbols") }, { 0x20D0, 0x20FF, I18N_NOOP("Combining Diacritical Marks for Symbols") }, { 0x2100, 0x214F, I18N_NOOP("Letter-Like Symbols") }, { 0x2150, 0x218F, I18N_NOOP("Number Forms") }, { 0x2190, 0x21FF, I18N_NOOP("Arrows") }, { 0x2200, 0x22FF, I18N_NOOP("Mathematical Operators") }, { 0x2300, 0x23FF, I18N_NOOP("Miscellaneous Technical") }, { 0x2400, 0x243F, I18N_NOOP("Control Pictures") }, { 0x2440, 0x245F, I18N_NOOP("Optical Character Recognition") }, { 0x2460, 0x24FF, I18N_NOOP("Enclosed Alphanumerics") }, { 0x2500, 0x257F, I18N_NOOP("Box Drawing") }, { 0x2580, 0x259F, I18N_NOOP("Block Elements") }, { 0x25A0, 0x25FF, I18N_NOOP("Geometric Shapes") }, { 0x2600, 0x26FF, I18N_NOOP("Miscellaneous Symbols") }, { 0x2700, 0x27BF, I18N_NOOP("Dingbats") }, { 0x27C0, 0x27EF, I18N_NOOP("Miscellaneous Mathematical Symbols-A") }, { 0x27F0, 0x27FF, I18N_NOOP("Supplemental Arrows-A") }, { 0x2800, 0x28FF, I18N_NOOP("Braille Patterns") }, { 0x2900, 0x297F, I18N_NOOP("Supplemental Arrows-B") }, { 0x2980, 0x29FF, I18N_NOOP("Miscellaneous Mathematical Symbols-B") }, { 0x2A00, 0x2AFF, I18N_NOOP("Supplemental Mathematical Operators") }, { 0x2B00, 0x2BFF, I18N_NOOP("Miscellaneous Symbols and Arrows") }, { 0x2C00, 0x2C5F, I18N_NOOP("Glagolitic") }, { 0x2C60, 0x2C7F, I18N_NOOP("Latin Extended-C") }, { 0x2C80, 0x2CFF, I18N_NOOP("Coptic") }, { 0x2D00, 0x2D2F, I18N_NOOP("Georgian Supplement") }, { 0x2D30, 0x2D7F, I18N_NOOP("Tifinagh") }, { 0x2D80, 0x2DDF, I18N_NOOP("Ethiopic Extended") }, { 0x2E00, 0x2E7F, I18N_NOOP("Supplemental Punctuation") }, { 0x2E80, 0x2EFF, I18N_NOOP("CJK Radicals Supplement") }, { 0x2F00, 0x2FDF, I18N_NOOP("Kangxi Radicals") }, { 0x2FF0, 0x2FFF, I18N_NOOP("Ideographic Description Characters") }, { 0x3000, 0x303F, I18N_NOOP("CJK Symbols and Punctuation") }, { 0x3040, 0x309F, I18N_NOOP("Hiragana") }, { 0x30A0, 0x30FF, I18N_NOOP("Katakana") }, { 0x3100, 0x312F, I18N_NOOP("Bopomofo") }, { 0x3130, 0x318F, I18N_NOOP("Hangul Compatibility Jamo") }, { 0x3190, 0x319F, I18N_NOOP("Kanbun") }, { 0x31A0, 0x31BF, I18N_NOOP("Bopomofo Extended") }, { 0x31C0, 0x31EF, I18N_NOOP("CJK Strokes") }, { 0x31F0, 0x31FF, I18N_NOOP("Katakana Phonetic Extensions") }, { 0x3200, 0x32FF, I18N_NOOP("Enclosed CJK Letters and Months") }, { 0x3300, 0x33FF, I18N_NOOP("CJK Compatibility") }, { 0x3400, 0x4DBF, I18N_NOOP("CJK Unified Ideographs Extension A") }, { 0x4DC0, 0x4DFF, I18N_NOOP("Yijing Hexagram Symbols") }, { 0x4E00, 0x9FFF, I18N_NOOP("CJK Unified Ideographs") }, { 0xA000, 0xA48F, I18N_NOOP("Yi Syllables") }, { 0xA490, 0xA4CF, I18N_NOOP("Yi Radicals") }, { 0xA700, 0xA71F, I18N_NOOP("Modifier Tone Letters") }, { 0xA720, 0xA7FF, I18N_NOOP("Latin Extended-D") }, { 0xA800, 0xA82F, I18N_NOOP("Syloti Nagri") }, { 0xA840, 0xA87F, I18N_NOOP("Phags-pa") }, { 0xAC00, 0xD7AF, I18N_NOOP("Hangul Syllables") }, { 0xD800, 0xDB7F, I18N_NOOP("High Surrogates") }, { 0xDB80, 0xDBFF, I18N_NOOP("High Private Use Surrogates") }, { 0xDC00, 0xDFFF, I18N_NOOP("Low Surrogates") }, { 0xE000, 0xF8FF, I18N_NOOP("Private Use Area") }, { 0xF900, 0xFAFF, I18N_NOOP("CJK Compatibility Ideographs") }, { 0xFB00, 0xFB4F, I18N_NOOP("Alphabetic Presentation Forms") }, { 0xFB50, 0xFDFF, I18N_NOOP("Arabic Presentation Forms-A") }, { 0xFE00, 0xFE0F, I18N_NOOP("Variation Selectors") }, { 0xFE10, 0xFE1F, I18N_NOOP("Vertical Forms") }, { 0xFE20, 0xFE2F, I18N_NOOP("Combining Half Marks") }, { 0xFE30, 0xFE4F, I18N_NOOP("CJK Compatibility Forms") }, { 0xFE50, 0xFE6F, I18N_NOOP("Small Form Variants") }, { 0xFE70, 0xFEFF, I18N_NOOP("Arabic Presentation Forms-B") }, { 0xFF00, 0xFFEF, I18N_NOOP("Half-Width and Full-Width Forms") }, { 0xFFF0, 0xFFFF, I18N_NOOP("Specials") }, { 0x10000, 0x1007F, I18N_NOOP("Linear B Syllabary") }, { 0x10080, 0x100FF, I18N_NOOP("Linear B Ideograms") }, { 0x10100, 0x1013F, I18N_NOOP("Aegean Numbers") }, { 0x10140, 0x1018F, I18N_NOOP("Ancient Greek Numbers") }, { 0x10300, 0x1032F, I18N_NOOP("Old Italic") }, { 0x10330, 0x1034F, I18N_NOOP("Gothic") }, { 0x10380, 0x1039F, I18N_NOOP("Ugaritic") }, { 0x103A0, 0x103DF, I18N_NOOP("Old Persian") }, { 0x10400, 0x1044F, I18N_NOOP("Deseret") }, { 0x10450, 0x1047F, I18N_NOOP("Shavian") }, { 0x10480, 0x104AF, I18N_NOOP("Osmanya") }, { 0x10800, 0x1083F, I18N_NOOP("Cypriot Syllabary") }, { 0x10900, 0x1091F, I18N_NOOP("Phoenician") }, { 0x10A00, 0x10A5F, I18N_NOOP("Kharoshthi") }, { 0x12000, 0x123FF, I18N_NOOP("Cuneiform") }, { 0x12400, 0x1247F, I18N_NOOP("Cuneiform Numbers and Punctuation") }, { 0x1D000, 0x1D0FF, I18N_NOOP("Byzantine Musical Symbols") }, { 0x1D100, 0x1D1FF, I18N_NOOP("Musical Symbols") }, { 0x1D200, 0x1D24F, I18N_NOOP("Ancient Greek Musical Notation") }, { 0x1D300, 0x1D35F, I18N_NOOP("Tai Xuan Jing Symbols") }, { 0x1D360, 0x1D37F, I18N_NOOP("Counting Rod Numerals") }, { 0x1D400, 0x1D7FF, I18N_NOOP("Mathematical Alphanumeric Symbols") }, { 0x20000, 0x2A6DF, I18N_NOOP("CJK Unified Ideographs Extension B") }, { 0x2F800, 0x2FA1F, I18N_NOOP("CJK Compatibility Ideographs Supplement") }, { 0xE0000, 0xE007F, I18N_NOOP("Tags") }, { 0xE0100, 0xE01EF, I18N_NOOP("Variation Selectors Supplement") }, { 0xF0000, 0xFFFFF, I18N_NOOP("Supplementary Private Use Area-A") }, { 0x100000, 0x10FFFF, I18N_NOOP("Supplementary Private Use Area-B") }, - { 0x0, 0x0, NULL } + { 0x0, 0x0, nullptr } }; #endif diff --git a/kcms/kfontinst/viewpart/UnicodeScripts.h b/kcms/kfontinst/viewpart/UnicodeScripts.h index 33eabc843..3e35c8dd7 100644 --- a/kcms/kfontinst/viewpart/UnicodeScripts.h +++ b/kcms/kfontinst/viewpart/UnicodeScripts.h @@ -1,1286 +1,1286 @@ /* UnicodeScripts.h */ /* THIS IS A GENERATED FILE. CHANGES WILL BE OVERWRITTEN. */ /* Generated by generate-unicode-tables.pl */ /* Generated from UCD version 5.0 */ #ifndef __UNICODE_SCRIPTS_H__ #define __UNICODE_SCRIPTS_H__ #include #include static const char * const constUnicodeScriptList[] = { I18N_NOOP("Arabic"), I18N_NOOP("Armenian"), I18N_NOOP("Balinese"), I18N_NOOP("Bengali"), I18N_NOOP("Bopomofo"), I18N_NOOP("Braille"), I18N_NOOP("Buginese"), I18N_NOOP("Buhid"), I18N_NOOP("Canadian Aboriginal"), I18N_NOOP("Cherokee"), I18N_NOOP("Common"), I18N_NOOP("Coptic"), I18N_NOOP("Cuneiform"), I18N_NOOP("Cypriot"), I18N_NOOP("Cyrillic"), I18N_NOOP("Deseret"), I18N_NOOP("Devanagari"), I18N_NOOP("Ethiopic"), I18N_NOOP("Georgian"), I18N_NOOP("Glagolitic"), I18N_NOOP("Gothic"), I18N_NOOP("Greek"), I18N_NOOP("Gujarati"), I18N_NOOP("Gurmukhi"), I18N_NOOP("Han"), I18N_NOOP("Hangul"), I18N_NOOP("Hanunoo"), I18N_NOOP("Hebrew"), I18N_NOOP("Hiragana"), I18N_NOOP("Inherited"), I18N_NOOP("Kannada"), I18N_NOOP("Katakana"), I18N_NOOP("Kharoshthi"), I18N_NOOP("Khmer"), I18N_NOOP("Lao"), I18N_NOOP("Latin"), I18N_NOOP("Limbu"), I18N_NOOP("Linear B"), I18N_NOOP("Malayalam"), I18N_NOOP("Mongolian"), I18N_NOOP("Myanmar"), I18N_NOOP("New Tai Lue"), I18N_NOOP("Nko"), I18N_NOOP("Ogham"), I18N_NOOP("Old Italic"), I18N_NOOP("Old Persian"), I18N_NOOP("Oriya"), I18N_NOOP("Osmanya"), I18N_NOOP("Phags Pa"), I18N_NOOP("Phoenician"), I18N_NOOP("Runic"), I18N_NOOP("Shavian"), I18N_NOOP("Sinhala"), I18N_NOOP("Syloti Nagri"), I18N_NOOP("Syriac"), I18N_NOOP("Tagalog"), I18N_NOOP("Tagbanwa"), I18N_NOOP("Tai Le"), I18N_NOOP("Tamil"), I18N_NOOP("Telugu"), I18N_NOOP("Thaana"), I18N_NOOP("Thai"), I18N_NOOP("Tibetan"), I18N_NOOP("Tifinagh"), I18N_NOOP("Ugaritic"), I18N_NOOP("Yi"), - NULL + nullptr }; struct TUnicodeScript { quint32 start, end; int scriptIndex; /* index into constUnicodeScriptList */ }; static const TUnicodeScript constUnicodeScripts[] = { { 0x0000, 0x001F, 10 }, { 0x0020, 0x0020, 10 }, { 0x0021, 0x0023, 10 }, { 0x0024, 0x0024, 10 }, { 0x0025, 0x0027, 10 }, { 0x0028, 0x0028, 10 }, { 0x0029, 0x0029, 10 }, { 0x002A, 0x002A, 10 }, { 0x002B, 0x002B, 10 }, { 0x002C, 0x002C, 10 }, { 0x002D, 0x002D, 10 }, { 0x002E, 0x002F, 10 }, { 0x0030, 0x0039, 10 }, { 0x003A, 0x003B, 10 }, { 0x003C, 0x003E, 10 }, { 0x003F, 0x0040, 10 }, { 0x0041, 0x005A, 35 }, { 0x005B, 0x005B, 10 }, { 0x005C, 0x005C, 10 }, { 0x005D, 0x005D, 10 }, { 0x005E, 0x005E, 10 }, { 0x005F, 0x005F, 10 }, { 0x0060, 0x0060, 10 }, { 0x0061, 0x007A, 35 }, { 0x007B, 0x007B, 10 }, { 0x007C, 0x007C, 10 }, { 0x007D, 0x007D, 10 }, { 0x007E, 0x007E, 10 }, { 0x007F, 0x009F, 10 }, { 0x00A0, 0x00A0, 10 }, { 0x00A1, 0x00A1, 10 }, { 0x00A2, 0x00A5, 10 }, { 0x00A6, 0x00A7, 10 }, { 0x00A8, 0x00A8, 10 }, { 0x00A9, 0x00A9, 10 }, { 0x00AA, 0x00AA, 35 }, { 0x00AB, 0x00AB, 10 }, { 0x00AC, 0x00AC, 10 }, { 0x00AD, 0x00AD, 10 }, { 0x00AE, 0x00AE, 10 }, { 0x00AF, 0x00AF, 10 }, { 0x00B0, 0x00B0, 10 }, { 0x00B1, 0x00B1, 10 }, { 0x00B2, 0x00B3, 10 }, { 0x00B4, 0x00B4, 10 }, { 0x00B5, 0x00B5, 10 }, { 0x00B6, 0x00B6, 10 }, { 0x00B7, 0x00B7, 10 }, { 0x00B8, 0x00B8, 10 }, { 0x00B9, 0x00B9, 10 }, { 0x00BA, 0x00BA, 35 }, { 0x00BB, 0x00BB, 10 }, { 0x00BC, 0x00BE, 10 }, { 0x00BF, 0x00BF, 10 }, { 0x00C0, 0x00D6, 35 }, { 0x00D7, 0x00D7, 10 }, { 0x00D8, 0x00F6, 35 }, { 0x00F7, 0x00F7, 10 }, { 0x00F8, 0x01BA, 35 }, { 0x01BB, 0x01BB, 35 }, { 0x01BC, 0x01BF, 35 }, { 0x01C0, 0x01C3, 35 }, { 0x01C4, 0x0293, 35 }, { 0x0294, 0x0294, 35 }, { 0x0295, 0x02AF, 35 }, { 0x02B0, 0x02B8, 35 }, { 0x02B9, 0x02C1, 10 }, { 0x02C2, 0x02C5, 10 }, { 0x02C6, 0x02D1, 10 }, { 0x02D2, 0x02DF, 10 }, { 0x02E0, 0x02E4, 35 }, { 0x02E5, 0x02ED, 10 }, { 0x02EE, 0x02EE, 10 }, { 0x02EF, 0x02FF, 10 }, { 0x0300, 0x036F, 29 }, { 0x0374, 0x0375, 21 }, { 0x037A, 0x037A, 21 }, { 0x037B, 0x037D, 21 }, { 0x037E, 0x037E, 10 }, { 0x0384, 0x0385, 21 }, { 0x0386, 0x0386, 21 }, { 0x0387, 0x0387, 10 }, { 0x0388, 0x038A, 21 }, { 0x038C, 0x038C, 21 }, { 0x038E, 0x03A1, 21 }, { 0x03A3, 0x03CE, 21 }, { 0x03D0, 0x03E1, 21 }, { 0x03E2, 0x03EF, 11 }, { 0x03F0, 0x03F5, 21 }, { 0x03F6, 0x03F6, 21 }, { 0x03F7, 0x03FF, 21 }, { 0x0400, 0x0481, 14 }, { 0x0482, 0x0482, 14 }, { 0x0483, 0x0486, 14 }, { 0x0488, 0x0489, 14 }, { 0x048A, 0x0513, 14 }, { 0x0531, 0x0556, 1 }, { 0x0559, 0x0559, 1 }, { 0x055A, 0x055F, 1 }, { 0x0561, 0x0587, 1 }, { 0x0589, 0x0589, 10 }, { 0x058A, 0x058A, 1 }, { 0x0591, 0x05BD, 27 }, { 0x05BE, 0x05BE, 27 }, { 0x05BF, 0x05BF, 27 }, { 0x05C0, 0x05C0, 27 }, { 0x05C1, 0x05C2, 27 }, { 0x05C3, 0x05C3, 27 }, { 0x05C4, 0x05C5, 27 }, { 0x05C6, 0x05C6, 27 }, { 0x05C7, 0x05C7, 27 }, { 0x05D0, 0x05EA, 27 }, { 0x05F0, 0x05F2, 27 }, { 0x05F3, 0x05F4, 27 }, { 0x0600, 0x0603, 10 }, { 0x060B, 0x060B, 0 }, { 0x060C, 0x060C, 10 }, { 0x060D, 0x060D, 0 }, { 0x060E, 0x060F, 0 }, { 0x0610, 0x0615, 0 }, { 0x061B, 0x061B, 10 }, { 0x061E, 0x061E, 0 }, { 0x061F, 0x061F, 10 }, { 0x0621, 0x063A, 0 }, { 0x0640, 0x0640, 10 }, { 0x0641, 0x064A, 0 }, { 0x064B, 0x0655, 29 }, { 0x0656, 0x065E, 0 }, { 0x0660, 0x0669, 10 }, { 0x066A, 0x066D, 0 }, { 0x066E, 0x066F, 0 }, { 0x0670, 0x0670, 29 }, { 0x0671, 0x06D3, 0 }, { 0x06D4, 0x06D4, 0 }, { 0x06D5, 0x06D5, 0 }, { 0x06D6, 0x06DC, 0 }, { 0x06DD, 0x06DD, 10 }, { 0x06DE, 0x06DE, 0 }, { 0x06DF, 0x06E4, 0 }, { 0x06E5, 0x06E6, 0 }, { 0x06E7, 0x06E8, 0 }, { 0x06E9, 0x06E9, 0 }, { 0x06EA, 0x06ED, 0 }, { 0x06EE, 0x06EF, 0 }, { 0x06F0, 0x06F9, 0 }, { 0x06FA, 0x06FC, 0 }, { 0x06FD, 0x06FE, 0 }, { 0x06FF, 0x06FF, 0 }, { 0x0700, 0x070D, 54 }, { 0x070F, 0x070F, 54 }, { 0x0710, 0x0710, 54 }, { 0x0711, 0x0711, 54 }, { 0x0712, 0x072F, 54 }, { 0x0730, 0x074A, 54 }, { 0x074D, 0x074F, 54 }, { 0x0750, 0x076D, 0 }, { 0x0780, 0x07A5, 60 }, { 0x07A6, 0x07B0, 60 }, { 0x07B1, 0x07B1, 60 }, { 0x07C0, 0x07C9, 42 }, { 0x07CA, 0x07EA, 42 }, { 0x07EB, 0x07F3, 42 }, { 0x07F4, 0x07F5, 42 }, { 0x07F6, 0x07F6, 42 }, { 0x07F7, 0x07F9, 42 }, { 0x07FA, 0x07FA, 42 }, { 0x0901, 0x0902, 16 }, { 0x0903, 0x0903, 16 }, { 0x0904, 0x0939, 16 }, { 0x093C, 0x093C, 16 }, { 0x093D, 0x093D, 16 }, { 0x093E, 0x0940, 16 }, { 0x0941, 0x0948, 16 }, { 0x0949, 0x094C, 16 }, { 0x094D, 0x094D, 16 }, { 0x0950, 0x0950, 16 }, { 0x0951, 0x0954, 16 }, { 0x0958, 0x0961, 16 }, { 0x0962, 0x0963, 16 }, { 0x0964, 0x0965, 10 }, { 0x0966, 0x096F, 16 }, { 0x0970, 0x0970, 10 }, { 0x097B, 0x097F, 16 }, { 0x0981, 0x0981, 3 }, { 0x0982, 0x0983, 3 }, { 0x0985, 0x098C, 3 }, { 0x098F, 0x0990, 3 }, { 0x0993, 0x09A8, 3 }, { 0x09AA, 0x09B0, 3 }, { 0x09B2, 0x09B2, 3 }, { 0x09B6, 0x09B9, 3 }, { 0x09BC, 0x09BC, 3 }, { 0x09BD, 0x09BD, 3 }, { 0x09BE, 0x09C0, 3 }, { 0x09C1, 0x09C4, 3 }, { 0x09C7, 0x09C8, 3 }, { 0x09CB, 0x09CC, 3 }, { 0x09CD, 0x09CD, 3 }, { 0x09CE, 0x09CE, 3 }, { 0x09D7, 0x09D7, 3 }, { 0x09DC, 0x09DD, 3 }, { 0x09DF, 0x09E1, 3 }, { 0x09E2, 0x09E3, 3 }, { 0x09E6, 0x09EF, 3 }, { 0x09F0, 0x09F1, 3 }, { 0x09F2, 0x09F3, 3 }, { 0x09F4, 0x09F9, 3 }, { 0x09FA, 0x09FA, 3 }, { 0x0A01, 0x0A02, 23 }, { 0x0A03, 0x0A03, 23 }, { 0x0A05, 0x0A0A, 23 }, { 0x0A0F, 0x0A10, 23 }, { 0x0A13, 0x0A28, 23 }, { 0x0A2A, 0x0A30, 23 }, { 0x0A32, 0x0A33, 23 }, { 0x0A35, 0x0A36, 23 }, { 0x0A38, 0x0A39, 23 }, { 0x0A3C, 0x0A3C, 23 }, { 0x0A3E, 0x0A40, 23 }, { 0x0A41, 0x0A42, 23 }, { 0x0A47, 0x0A48, 23 }, { 0x0A4B, 0x0A4D, 23 }, { 0x0A59, 0x0A5C, 23 }, { 0x0A5E, 0x0A5E, 23 }, { 0x0A66, 0x0A6F, 23 }, { 0x0A70, 0x0A71, 23 }, { 0x0A72, 0x0A74, 23 }, { 0x0A81, 0x0A82, 22 }, { 0x0A83, 0x0A83, 22 }, { 0x0A85, 0x0A8D, 22 }, { 0x0A8F, 0x0A91, 22 }, { 0x0A93, 0x0AA8, 22 }, { 0x0AAA, 0x0AB0, 22 }, { 0x0AB2, 0x0AB3, 22 }, { 0x0AB5, 0x0AB9, 22 }, { 0x0ABC, 0x0ABC, 22 }, { 0x0ABD, 0x0ABD, 22 }, { 0x0ABE, 0x0AC0, 22 }, { 0x0AC1, 0x0AC5, 22 }, { 0x0AC7, 0x0AC8, 22 }, { 0x0AC9, 0x0AC9, 22 }, { 0x0ACB, 0x0ACC, 22 }, { 0x0ACD, 0x0ACD, 22 }, { 0x0AD0, 0x0AD0, 22 }, { 0x0AE0, 0x0AE1, 22 }, { 0x0AE2, 0x0AE3, 22 }, { 0x0AE6, 0x0AEF, 22 }, { 0x0AF1, 0x0AF1, 22 }, { 0x0B01, 0x0B01, 46 }, { 0x0B02, 0x0B03, 46 }, { 0x0B05, 0x0B0C, 46 }, { 0x0B0F, 0x0B10, 46 }, { 0x0B13, 0x0B28, 46 }, { 0x0B2A, 0x0B30, 46 }, { 0x0B32, 0x0B33, 46 }, { 0x0B35, 0x0B39, 46 }, { 0x0B3C, 0x0B3C, 46 }, { 0x0B3D, 0x0B3D, 46 }, { 0x0B3E, 0x0B3E, 46 }, { 0x0B3F, 0x0B3F, 46 }, { 0x0B40, 0x0B40, 46 }, { 0x0B41, 0x0B43, 46 }, { 0x0B47, 0x0B48, 46 }, { 0x0B4B, 0x0B4C, 46 }, { 0x0B4D, 0x0B4D, 46 }, { 0x0B56, 0x0B56, 46 }, { 0x0B57, 0x0B57, 46 }, { 0x0B5C, 0x0B5D, 46 }, { 0x0B5F, 0x0B61, 46 }, { 0x0B66, 0x0B6F, 46 }, { 0x0B70, 0x0B70, 46 }, { 0x0B71, 0x0B71, 46 }, { 0x0B82, 0x0B82, 58 }, { 0x0B83, 0x0B83, 58 }, { 0x0B85, 0x0B8A, 58 }, { 0x0B8E, 0x0B90, 58 }, { 0x0B92, 0x0B95, 58 }, { 0x0B99, 0x0B9A, 58 }, { 0x0B9C, 0x0B9C, 58 }, { 0x0B9E, 0x0B9F, 58 }, { 0x0BA3, 0x0BA4, 58 }, { 0x0BA8, 0x0BAA, 58 }, { 0x0BAE, 0x0BB9, 58 }, { 0x0BBE, 0x0BBF, 58 }, { 0x0BC0, 0x0BC0, 58 }, { 0x0BC1, 0x0BC2, 58 }, { 0x0BC6, 0x0BC8, 58 }, { 0x0BCA, 0x0BCC, 58 }, { 0x0BCD, 0x0BCD, 58 }, { 0x0BD7, 0x0BD7, 58 }, { 0x0BE6, 0x0BEF, 58 }, { 0x0BF0, 0x0BF2, 58 }, { 0x0BF3, 0x0BF8, 58 }, { 0x0BF9, 0x0BF9, 58 }, { 0x0BFA, 0x0BFA, 58 }, { 0x0C01, 0x0C03, 59 }, { 0x0C05, 0x0C0C, 59 }, { 0x0C0E, 0x0C10, 59 }, { 0x0C12, 0x0C28, 59 }, { 0x0C2A, 0x0C33, 59 }, { 0x0C35, 0x0C39, 59 }, { 0x0C3E, 0x0C40, 59 }, { 0x0C41, 0x0C44, 59 }, { 0x0C46, 0x0C48, 59 }, { 0x0C4A, 0x0C4D, 59 }, { 0x0C55, 0x0C56, 59 }, { 0x0C60, 0x0C61, 59 }, { 0x0C66, 0x0C6F, 59 }, { 0x0C82, 0x0C83, 30 }, { 0x0C85, 0x0C8C, 30 }, { 0x0C8E, 0x0C90, 30 }, { 0x0C92, 0x0CA8, 30 }, { 0x0CAA, 0x0CB3, 30 }, { 0x0CB5, 0x0CB9, 30 }, { 0x0CBC, 0x0CBC, 30 }, { 0x0CBD, 0x0CBD, 30 }, { 0x0CBE, 0x0CBE, 30 }, { 0x0CBF, 0x0CBF, 30 }, { 0x0CC0, 0x0CC4, 30 }, { 0x0CC6, 0x0CC6, 30 }, { 0x0CC7, 0x0CC8, 30 }, { 0x0CCA, 0x0CCB, 30 }, { 0x0CCC, 0x0CCD, 30 }, { 0x0CD5, 0x0CD6, 30 }, { 0x0CDE, 0x0CDE, 30 }, { 0x0CE0, 0x0CE1, 30 }, { 0x0CE2, 0x0CE3, 30 }, { 0x0CE6, 0x0CEF, 30 }, { 0x0CF1, 0x0CF2, 30 }, { 0x0D02, 0x0D03, 38 }, { 0x0D05, 0x0D0C, 38 }, { 0x0D0E, 0x0D10, 38 }, { 0x0D12, 0x0D28, 38 }, { 0x0D2A, 0x0D39, 38 }, { 0x0D3E, 0x0D40, 38 }, { 0x0D41, 0x0D43, 38 }, { 0x0D46, 0x0D48, 38 }, { 0x0D4A, 0x0D4C, 38 }, { 0x0D4D, 0x0D4D, 38 }, { 0x0D57, 0x0D57, 38 }, { 0x0D60, 0x0D61, 38 }, { 0x0D66, 0x0D6F, 38 }, { 0x0D82, 0x0D83, 52 }, { 0x0D85, 0x0D96, 52 }, { 0x0D9A, 0x0DB1, 52 }, { 0x0DB3, 0x0DBB, 52 }, { 0x0DBD, 0x0DBD, 52 }, { 0x0DC0, 0x0DC6, 52 }, { 0x0DCA, 0x0DCA, 52 }, { 0x0DCF, 0x0DD1, 52 }, { 0x0DD2, 0x0DD4, 52 }, { 0x0DD6, 0x0DD6, 52 }, { 0x0DD8, 0x0DDF, 52 }, { 0x0DF2, 0x0DF3, 52 }, { 0x0DF4, 0x0DF4, 52 }, { 0x0E01, 0x0E30, 61 }, { 0x0E31, 0x0E31, 61 }, { 0x0E32, 0x0E33, 61 }, { 0x0E34, 0x0E3A, 61 }, { 0x0E3F, 0x0E3F, 10 }, { 0x0E40, 0x0E45, 61 }, { 0x0E46, 0x0E46, 61 }, { 0x0E47, 0x0E4E, 61 }, { 0x0E4F, 0x0E4F, 61 }, { 0x0E50, 0x0E59, 61 }, { 0x0E5A, 0x0E5B, 61 }, { 0x0E81, 0x0E82, 34 }, { 0x0E84, 0x0E84, 34 }, { 0x0E87, 0x0E88, 34 }, { 0x0E8A, 0x0E8A, 34 }, { 0x0E8D, 0x0E8D, 34 }, { 0x0E94, 0x0E97, 34 }, { 0x0E99, 0x0E9F, 34 }, { 0x0EA1, 0x0EA3, 34 }, { 0x0EA5, 0x0EA5, 34 }, { 0x0EA7, 0x0EA7, 34 }, { 0x0EAA, 0x0EAB, 34 }, { 0x0EAD, 0x0EB0, 34 }, { 0x0EB1, 0x0EB1, 34 }, { 0x0EB2, 0x0EB3, 34 }, { 0x0EB4, 0x0EB9, 34 }, { 0x0EBB, 0x0EBC, 34 }, { 0x0EBD, 0x0EBD, 34 }, { 0x0EC0, 0x0EC4, 34 }, { 0x0EC6, 0x0EC6, 34 }, { 0x0EC8, 0x0ECD, 34 }, { 0x0ED0, 0x0ED9, 34 }, { 0x0EDC, 0x0EDD, 34 }, { 0x0F00, 0x0F00, 62 }, { 0x0F01, 0x0F03, 62 }, { 0x0F04, 0x0F12, 62 }, { 0x0F13, 0x0F17, 62 }, { 0x0F18, 0x0F19, 62 }, { 0x0F1A, 0x0F1F, 62 }, { 0x0F20, 0x0F29, 62 }, { 0x0F2A, 0x0F33, 62 }, { 0x0F34, 0x0F34, 62 }, { 0x0F35, 0x0F35, 62 }, { 0x0F36, 0x0F36, 62 }, { 0x0F37, 0x0F37, 62 }, { 0x0F38, 0x0F38, 62 }, { 0x0F39, 0x0F39, 62 }, { 0x0F3A, 0x0F3A, 62 }, { 0x0F3B, 0x0F3B, 62 }, { 0x0F3C, 0x0F3C, 62 }, { 0x0F3D, 0x0F3D, 62 }, { 0x0F3E, 0x0F3F, 62 }, { 0x0F40, 0x0F47, 62 }, { 0x0F49, 0x0F6A, 62 }, { 0x0F71, 0x0F7E, 62 }, { 0x0F7F, 0x0F7F, 62 }, { 0x0F80, 0x0F84, 62 }, { 0x0F85, 0x0F85, 62 }, { 0x0F86, 0x0F87, 62 }, { 0x0F88, 0x0F8B, 62 }, { 0x0F90, 0x0F97, 62 }, { 0x0F99, 0x0FBC, 62 }, { 0x0FBE, 0x0FC5, 62 }, { 0x0FC6, 0x0FC6, 62 }, { 0x0FC7, 0x0FCC, 62 }, { 0x0FCF, 0x0FCF, 62 }, { 0x0FD0, 0x0FD1, 62 }, { 0x1000, 0x1021, 40 }, { 0x1023, 0x1027, 40 }, { 0x1029, 0x102A, 40 }, { 0x102C, 0x102C, 40 }, { 0x102D, 0x1030, 40 }, { 0x1031, 0x1031, 40 }, { 0x1032, 0x1032, 40 }, { 0x1036, 0x1037, 40 }, { 0x1038, 0x1038, 40 }, { 0x1039, 0x1039, 40 }, { 0x1040, 0x1049, 40 }, { 0x104A, 0x104F, 40 }, { 0x1050, 0x1055, 40 }, { 0x1056, 0x1057, 40 }, { 0x1058, 0x1059, 40 }, { 0x10A0, 0x10C5, 18 }, { 0x10D0, 0x10FA, 18 }, { 0x10FB, 0x10FB, 10 }, { 0x10FC, 0x10FC, 18 }, { 0x1100, 0x1159, 25 }, { 0x115F, 0x11A2, 25 }, { 0x11A8, 0x11F9, 25 }, { 0x1200, 0x1248, 17 }, { 0x124A, 0x124D, 17 }, { 0x1250, 0x1256, 17 }, { 0x1258, 0x1258, 17 }, { 0x125A, 0x125D, 17 }, { 0x1260, 0x1288, 17 }, { 0x128A, 0x128D, 17 }, { 0x1290, 0x12B0, 17 }, { 0x12B2, 0x12B5, 17 }, { 0x12B8, 0x12BE, 17 }, { 0x12C0, 0x12C0, 17 }, { 0x12C2, 0x12C5, 17 }, { 0x12C8, 0x12D6, 17 }, { 0x12D8, 0x1310, 17 }, { 0x1312, 0x1315, 17 }, { 0x1318, 0x135A, 17 }, { 0x135F, 0x135F, 17 }, { 0x1360, 0x1360, 17 }, { 0x1361, 0x1368, 17 }, { 0x1369, 0x137C, 17 }, { 0x1380, 0x138F, 17 }, { 0x1390, 0x1399, 17 }, { 0x13A0, 0x13F4, 9 }, { 0x1401, 0x166C, 8 }, { 0x166D, 0x166E, 8 }, { 0x166F, 0x1676, 8 }, { 0x1680, 0x1680, 43 }, { 0x1681, 0x169A, 43 }, { 0x169B, 0x169B, 43 }, { 0x169C, 0x169C, 43 }, { 0x16A0, 0x16EA, 50 }, { 0x16EB, 0x16ED, 10 }, { 0x16EE, 0x16F0, 50 }, { 0x1700, 0x170C, 55 }, { 0x170E, 0x1711, 55 }, { 0x1712, 0x1714, 55 }, { 0x1720, 0x1731, 26 }, { 0x1732, 0x1734, 26 }, { 0x1735, 0x1736, 10 }, { 0x1740, 0x1751, 7 }, { 0x1752, 0x1753, 7 }, { 0x1760, 0x176C, 56 }, { 0x176E, 0x1770, 56 }, { 0x1772, 0x1773, 56 }, { 0x1780, 0x17B3, 33 }, { 0x17B4, 0x17B5, 33 }, { 0x17B6, 0x17B6, 33 }, { 0x17B7, 0x17BD, 33 }, { 0x17BE, 0x17C5, 33 }, { 0x17C6, 0x17C6, 33 }, { 0x17C7, 0x17C8, 33 }, { 0x17C9, 0x17D3, 33 }, { 0x17D4, 0x17D6, 33 }, { 0x17D7, 0x17D7, 33 }, { 0x17D8, 0x17DA, 33 }, { 0x17DB, 0x17DB, 33 }, { 0x17DC, 0x17DC, 33 }, { 0x17DD, 0x17DD, 33 }, { 0x17E0, 0x17E9, 33 }, { 0x17F0, 0x17F9, 33 }, { 0x1800, 0x1801, 39 }, { 0x1802, 0x1803, 10 }, { 0x1804, 0x1804, 39 }, { 0x1805, 0x1805, 10 }, { 0x1806, 0x1806, 39 }, { 0x1807, 0x180A, 39 }, { 0x180B, 0x180D, 39 }, { 0x180E, 0x180E, 39 }, { 0x1810, 0x1819, 39 }, { 0x1820, 0x1842, 39 }, { 0x1843, 0x1843, 39 }, { 0x1844, 0x1877, 39 }, { 0x1880, 0x18A8, 39 }, { 0x18A9, 0x18A9, 39 }, { 0x1900, 0x191C, 36 }, { 0x1920, 0x1922, 36 }, { 0x1923, 0x1926, 36 }, { 0x1927, 0x1928, 36 }, { 0x1929, 0x192B, 36 }, { 0x1930, 0x1931, 36 }, { 0x1932, 0x1932, 36 }, { 0x1933, 0x1938, 36 }, { 0x1939, 0x193B, 36 }, { 0x1940, 0x1940, 36 }, { 0x1944, 0x1945, 36 }, { 0x1946, 0x194F, 36 }, { 0x1950, 0x196D, 57 }, { 0x1970, 0x1974, 57 }, { 0x1980, 0x19A9, 41 }, { 0x19B0, 0x19C0, 41 }, { 0x19C1, 0x19C7, 41 }, { 0x19C8, 0x19C9, 41 }, { 0x19D0, 0x19D9, 41 }, { 0x19DE, 0x19DF, 41 }, { 0x19E0, 0x19FF, 33 }, { 0x1A00, 0x1A16, 6 }, { 0x1A17, 0x1A18, 6 }, { 0x1A19, 0x1A1B, 6 }, { 0x1A1E, 0x1A1F, 6 }, { 0x1B00, 0x1B03, 2 }, { 0x1B04, 0x1B04, 2 }, { 0x1B05, 0x1B33, 2 }, { 0x1B34, 0x1B34, 2 }, { 0x1B35, 0x1B35, 2 }, { 0x1B36, 0x1B3A, 2 }, { 0x1B3B, 0x1B3B, 2 }, { 0x1B3C, 0x1B3C, 2 }, { 0x1B3D, 0x1B41, 2 }, { 0x1B42, 0x1B42, 2 }, { 0x1B43, 0x1B44, 2 }, { 0x1B45, 0x1B4B, 2 }, { 0x1B50, 0x1B59, 2 }, { 0x1B5A, 0x1B60, 2 }, { 0x1B61, 0x1B6A, 2 }, { 0x1B6B, 0x1B73, 2 }, { 0x1B74, 0x1B7C, 2 }, { 0x1D00, 0x1D25, 35 }, { 0x1D26, 0x1D2A, 21 }, { 0x1D2B, 0x1D2B, 14 }, { 0x1D2C, 0x1D5C, 35 }, { 0x1D5D, 0x1D61, 21 }, { 0x1D62, 0x1D65, 35 }, { 0x1D66, 0x1D6A, 21 }, { 0x1D6B, 0x1D77, 35 }, { 0x1D78, 0x1D78, 14 }, { 0x1D79, 0x1D9A, 35 }, { 0x1D9B, 0x1DBE, 35 }, { 0x1DBF, 0x1DBF, 21 }, { 0x1DC0, 0x1DCA, 29 }, { 0x1DFE, 0x1DFF, 29 }, { 0x1E00, 0x1E9B, 35 }, { 0x1EA0, 0x1EF9, 35 }, { 0x1F00, 0x1F15, 21 }, { 0x1F18, 0x1F1D, 21 }, { 0x1F20, 0x1F45, 21 }, { 0x1F48, 0x1F4D, 21 }, { 0x1F50, 0x1F57, 21 }, { 0x1F59, 0x1F59, 21 }, { 0x1F5B, 0x1F5B, 21 }, { 0x1F5D, 0x1F5D, 21 }, { 0x1F5F, 0x1F7D, 21 }, { 0x1F80, 0x1FB4, 21 }, { 0x1FB6, 0x1FBC, 21 }, { 0x1FBD, 0x1FBD, 21 }, { 0x1FBE, 0x1FBE, 21 }, { 0x1FBF, 0x1FC1, 21 }, { 0x1FC2, 0x1FC4, 21 }, { 0x1FC6, 0x1FCC, 21 }, { 0x1FCD, 0x1FCF, 21 }, { 0x1FD0, 0x1FD3, 21 }, { 0x1FD6, 0x1FDB, 21 }, { 0x1FDD, 0x1FDF, 21 }, { 0x1FE0, 0x1FEC, 21 }, { 0x1FED, 0x1FEF, 21 }, { 0x1FF2, 0x1FF4, 21 }, { 0x1FF6, 0x1FFC, 21 }, { 0x1FFD, 0x1FFE, 21 }, { 0x2000, 0x200A, 10 }, { 0x200B, 0x200B, 10 }, { 0x200C, 0x200D, 29 }, { 0x200E, 0x200F, 10 }, { 0x2010, 0x2015, 10 }, { 0x2016, 0x2017, 10 }, { 0x2018, 0x2018, 10 }, { 0x2019, 0x2019, 10 }, { 0x201A, 0x201A, 10 }, { 0x201B, 0x201C, 10 }, { 0x201D, 0x201D, 10 }, { 0x201E, 0x201E, 10 }, { 0x201F, 0x201F, 10 }, { 0x2020, 0x2027, 10 }, { 0x2028, 0x2028, 10 }, { 0x2029, 0x2029, 10 }, { 0x202A, 0x202E, 10 }, { 0x202F, 0x202F, 10 }, { 0x2030, 0x2038, 10 }, { 0x2039, 0x2039, 10 }, { 0x203A, 0x203A, 10 }, { 0x203B, 0x203E, 10 }, { 0x203F, 0x2040, 10 }, { 0x2041, 0x2043, 10 }, { 0x2044, 0x2044, 10 }, { 0x2045, 0x2045, 10 }, { 0x2046, 0x2046, 10 }, { 0x2047, 0x2051, 10 }, { 0x2052, 0x2052, 10 }, { 0x2053, 0x2053, 10 }, { 0x2054, 0x2054, 10 }, { 0x2055, 0x205E, 10 }, { 0x205F, 0x205F, 10 }, { 0x2060, 0x2063, 10 }, { 0x206A, 0x206F, 10 }, { 0x2070, 0x2070, 10 }, { 0x2071, 0x2071, 35 }, { 0x2074, 0x2079, 10 }, { 0x207A, 0x207C, 10 }, { 0x207D, 0x207D, 10 }, { 0x207E, 0x207E, 10 }, { 0x207F, 0x207F, 35 }, { 0x2080, 0x2089, 10 }, { 0x208A, 0x208C, 10 }, { 0x208D, 0x208D, 10 }, { 0x208E, 0x208E, 10 }, { 0x2090, 0x2094, 35 }, { 0x20A0, 0x20B5, 10 }, { 0x20D0, 0x20DC, 29 }, { 0x20DD, 0x20E0, 29 }, { 0x20E1, 0x20E1, 29 }, { 0x20E2, 0x20E4, 29 }, { 0x20E5, 0x20EF, 29 }, { 0x2100, 0x2101, 10 }, { 0x2102, 0x2102, 10 }, { 0x2103, 0x2106, 10 }, { 0x2107, 0x2107, 10 }, { 0x2108, 0x2109, 10 }, { 0x210A, 0x2113, 10 }, { 0x2114, 0x2114, 10 }, { 0x2115, 0x2115, 10 }, { 0x2116, 0x2118, 10 }, { 0x2119, 0x211D, 10 }, { 0x211E, 0x2123, 10 }, { 0x2124, 0x2124, 10 }, { 0x2125, 0x2125, 10 }, { 0x2126, 0x2126, 21 }, { 0x2127, 0x2127, 10 }, { 0x2128, 0x2128, 10 }, { 0x2129, 0x2129, 10 }, { 0x212A, 0x212B, 35 }, { 0x212C, 0x212D, 10 }, { 0x212E, 0x212E, 10 }, { 0x212F, 0x2131, 10 }, { 0x2132, 0x2132, 35 }, { 0x2133, 0x2134, 10 }, { 0x2135, 0x2138, 10 }, { 0x2139, 0x2139, 10 }, { 0x213A, 0x213B, 10 }, { 0x213C, 0x213F, 10 }, { 0x2140, 0x2144, 10 }, { 0x2145, 0x2149, 10 }, { 0x214A, 0x214A, 10 }, { 0x214B, 0x214B, 10 }, { 0x214C, 0x214D, 10 }, { 0x214E, 0x214E, 35 }, { 0x2153, 0x215F, 10 }, { 0x2160, 0x2182, 10 }, { 0x2183, 0x2183, 10 }, { 0x2184, 0x2184, 35 }, { 0x2190, 0x2194, 10 }, { 0x2195, 0x2199, 10 }, { 0x219A, 0x219B, 10 }, { 0x219C, 0x219F, 10 }, { 0x21A0, 0x21A0, 10 }, { 0x21A1, 0x21A2, 10 }, { 0x21A3, 0x21A3, 10 }, { 0x21A4, 0x21A5, 10 }, { 0x21A6, 0x21A6, 10 }, { 0x21A7, 0x21AD, 10 }, { 0x21AE, 0x21AE, 10 }, { 0x21AF, 0x21CD, 10 }, { 0x21CE, 0x21CF, 10 }, { 0x21D0, 0x21D1, 10 }, { 0x21D2, 0x21D2, 10 }, { 0x21D3, 0x21D3, 10 }, { 0x21D4, 0x21D4, 10 }, { 0x21D5, 0x21F3, 10 }, { 0x21F4, 0x22FF, 10 }, { 0x2300, 0x2307, 10 }, { 0x2308, 0x230B, 10 }, { 0x230C, 0x231F, 10 }, { 0x2320, 0x2321, 10 }, { 0x2322, 0x2328, 10 }, { 0x2329, 0x2329, 10 }, { 0x232A, 0x232A, 10 }, { 0x232B, 0x237B, 10 }, { 0x237C, 0x237C, 10 }, { 0x237D, 0x239A, 10 }, { 0x239B, 0x23B3, 10 }, { 0x23B4, 0x23DB, 10 }, { 0x23DC, 0x23E1, 10 }, { 0x23E2, 0x23E7, 10 }, { 0x2400, 0x2426, 10 }, { 0x2440, 0x244A, 10 }, { 0x2460, 0x249B, 10 }, { 0x249C, 0x24E9, 10 }, { 0x24EA, 0x24FF, 10 }, { 0x2500, 0x25B6, 10 }, { 0x25B7, 0x25B7, 10 }, { 0x25B8, 0x25C0, 10 }, { 0x25C1, 0x25C1, 10 }, { 0x25C2, 0x25F7, 10 }, { 0x25F8, 0x25FF, 10 }, { 0x2600, 0x266E, 10 }, { 0x266F, 0x266F, 10 }, { 0x2670, 0x269C, 10 }, { 0x26A0, 0x26B2, 10 }, { 0x2701, 0x2704, 10 }, { 0x2706, 0x2709, 10 }, { 0x270C, 0x2727, 10 }, { 0x2729, 0x274B, 10 }, { 0x274D, 0x274D, 10 }, { 0x274F, 0x2752, 10 }, { 0x2756, 0x2756, 10 }, { 0x2758, 0x275E, 10 }, { 0x2761, 0x2767, 10 }, { 0x2768, 0x2768, 10 }, { 0x2769, 0x2769, 10 }, { 0x276A, 0x276A, 10 }, { 0x276B, 0x276B, 10 }, { 0x276C, 0x276C, 10 }, { 0x276D, 0x276D, 10 }, { 0x276E, 0x276E, 10 }, { 0x276F, 0x276F, 10 }, { 0x2770, 0x2770, 10 }, { 0x2771, 0x2771, 10 }, { 0x2772, 0x2772, 10 }, { 0x2773, 0x2773, 10 }, { 0x2774, 0x2774, 10 }, { 0x2775, 0x2775, 10 }, { 0x2776, 0x2793, 10 }, { 0x2794, 0x2794, 10 }, { 0x2798, 0x27AF, 10 }, { 0x27B1, 0x27BE, 10 }, { 0x27C0, 0x27C4, 10 }, { 0x27C5, 0x27C5, 10 }, { 0x27C6, 0x27C6, 10 }, { 0x27C7, 0x27CA, 10 }, { 0x27D0, 0x27E5, 10 }, { 0x27E6, 0x27E6, 10 }, { 0x27E7, 0x27E7, 10 }, { 0x27E8, 0x27E8, 10 }, { 0x27E9, 0x27E9, 10 }, { 0x27EA, 0x27EA, 10 }, { 0x27EB, 0x27EB, 10 }, { 0x27F0, 0x27FF, 10 }, { 0x2800, 0x28FF, 5 }, { 0x2900, 0x2982, 10 }, { 0x2983, 0x2983, 10 }, { 0x2984, 0x2984, 10 }, { 0x2985, 0x2985, 10 }, { 0x2986, 0x2986, 10 }, { 0x2987, 0x2987, 10 }, { 0x2988, 0x2988, 10 }, { 0x2989, 0x2989, 10 }, { 0x298A, 0x298A, 10 }, { 0x298B, 0x298B, 10 }, { 0x298C, 0x298C, 10 }, { 0x298D, 0x298D, 10 }, { 0x298E, 0x298E, 10 }, { 0x298F, 0x298F, 10 }, { 0x2990, 0x2990, 10 }, { 0x2991, 0x2991, 10 }, { 0x2992, 0x2992, 10 }, { 0x2993, 0x2993, 10 }, { 0x2994, 0x2994, 10 }, { 0x2995, 0x2995, 10 }, { 0x2996, 0x2996, 10 }, { 0x2997, 0x2997, 10 }, { 0x2998, 0x2998, 10 }, { 0x2999, 0x29D7, 10 }, { 0x29D8, 0x29D8, 10 }, { 0x29D9, 0x29D9, 10 }, { 0x29DA, 0x29DA, 10 }, { 0x29DB, 0x29DB, 10 }, { 0x29DC, 0x29FB, 10 }, { 0x29FC, 0x29FC, 10 }, { 0x29FD, 0x29FD, 10 }, { 0x29FE, 0x2AFF, 10 }, { 0x2B00, 0x2B1A, 10 }, { 0x2B20, 0x2B23, 10 }, { 0x2C00, 0x2C2E, 19 }, { 0x2C30, 0x2C5E, 19 }, { 0x2C60, 0x2C6C, 35 }, { 0x2C74, 0x2C77, 35 }, { 0x2C80, 0x2CE4, 11 }, { 0x2CE5, 0x2CEA, 11 }, { 0x2CF9, 0x2CFC, 11 }, { 0x2CFD, 0x2CFD, 11 }, { 0x2CFE, 0x2CFF, 11 }, { 0x2D00, 0x2D25, 18 }, { 0x2D30, 0x2D65, 63 }, { 0x2D6F, 0x2D6F, 63 }, { 0x2D80, 0x2D96, 17 }, { 0x2DA0, 0x2DA6, 17 }, { 0x2DA8, 0x2DAE, 17 }, { 0x2DB0, 0x2DB6, 17 }, { 0x2DB8, 0x2DBE, 17 }, { 0x2DC0, 0x2DC6, 17 }, { 0x2DC8, 0x2DCE, 17 }, { 0x2DD0, 0x2DD6, 17 }, { 0x2DD8, 0x2DDE, 17 }, { 0x2E00, 0x2E01, 10 }, { 0x2E02, 0x2E02, 10 }, { 0x2E03, 0x2E03, 10 }, { 0x2E04, 0x2E04, 10 }, { 0x2E05, 0x2E05, 10 }, { 0x2E06, 0x2E08, 10 }, { 0x2E09, 0x2E09, 10 }, { 0x2E0A, 0x2E0A, 10 }, { 0x2E0B, 0x2E0B, 10 }, { 0x2E0C, 0x2E0C, 10 }, { 0x2E0D, 0x2E0D, 10 }, { 0x2E0E, 0x2E16, 10 }, { 0x2E17, 0x2E17, 10 }, { 0x2E1C, 0x2E1C, 10 }, { 0x2E1D, 0x2E1D, 10 }, { 0x2E80, 0x2E99, 24 }, { 0x2E9B, 0x2EF3, 24 }, { 0x2F00, 0x2FD5, 24 }, { 0x2FF0, 0x2FFB, 10 }, { 0x3000, 0x3000, 10 }, { 0x3001, 0x3003, 10 }, { 0x3004, 0x3004, 10 }, { 0x3005, 0x3005, 24 }, { 0x3006, 0x3006, 10 }, { 0x3007, 0x3007, 24 }, { 0x3008, 0x3008, 10 }, { 0x3009, 0x3009, 10 }, { 0x300A, 0x300A, 10 }, { 0x300B, 0x300B, 10 }, { 0x300C, 0x300C, 10 }, { 0x300D, 0x300D, 10 }, { 0x300E, 0x300E, 10 }, { 0x300F, 0x300F, 10 }, { 0x3010, 0x3010, 10 }, { 0x3011, 0x3011, 10 }, { 0x3012, 0x3013, 10 }, { 0x3014, 0x3014, 10 }, { 0x3015, 0x3015, 10 }, { 0x3016, 0x3016, 10 }, { 0x3017, 0x3017, 10 }, { 0x3018, 0x3018, 10 }, { 0x3019, 0x3019, 10 }, { 0x301A, 0x301A, 10 }, { 0x301B, 0x301B, 10 }, { 0x301C, 0x301C, 10 }, { 0x301D, 0x301D, 10 }, { 0x301E, 0x301F, 10 }, { 0x3020, 0x3020, 10 }, { 0x3021, 0x3029, 24 }, { 0x302A, 0x302F, 29 }, { 0x3030, 0x3030, 10 }, { 0x3031, 0x3035, 10 }, { 0x3036, 0x3037, 10 }, { 0x3038, 0x303A, 24 }, { 0x303B, 0x303B, 24 }, { 0x303C, 0x303C, 10 }, { 0x303D, 0x303D, 10 }, { 0x303E, 0x303F, 10 }, { 0x3041, 0x3096, 28 }, { 0x3099, 0x309A, 29 }, { 0x309B, 0x309C, 10 }, { 0x309D, 0x309E, 28 }, { 0x309F, 0x309F, 28 }, { 0x30A0, 0x30A0, 10 }, { 0x30A1, 0x30FA, 31 }, { 0x30FB, 0x30FB, 10 }, { 0x30FC, 0x30FC, 10 }, { 0x30FD, 0x30FE, 31 }, { 0x30FF, 0x30FF, 31 }, { 0x3105, 0x312C, 4 }, { 0x3131, 0x318E, 25 }, { 0x3190, 0x3191, 10 }, { 0x3192, 0x3195, 10 }, { 0x3196, 0x319F, 10 }, { 0x31A0, 0x31B7, 4 }, { 0x31C0, 0x31CF, 10 }, { 0x31F0, 0x31FF, 31 }, { 0x3200, 0x321E, 25 }, { 0x3220, 0x3229, 10 }, { 0x322A, 0x3243, 10 }, { 0x3250, 0x3250, 10 }, { 0x3251, 0x325F, 10 }, { 0x3260, 0x327D, 25 }, { 0x327E, 0x327F, 10 }, { 0x3280, 0x3289, 10 }, { 0x328A, 0x32B0, 10 }, { 0x32B1, 0x32BF, 10 }, { 0x32C0, 0x32FE, 10 }, { 0x3300, 0x33FF, 10 }, { 0x3400, 0x4DB5, 24 }, { 0x4DC0, 0x4DFF, 10 }, { 0x4E00, 0x9FBB, 24 }, { 0xA000, 0xA014, 65 }, { 0xA015, 0xA015, 65 }, { 0xA016, 0xA48C, 65 }, { 0xA490, 0xA4C6, 65 }, { 0xA700, 0xA716, 10 }, { 0xA717, 0xA71A, 10 }, { 0xA720, 0xA721, 10 }, { 0xA800, 0xA801, 53 }, { 0xA802, 0xA802, 53 }, { 0xA803, 0xA805, 53 }, { 0xA806, 0xA806, 53 }, { 0xA807, 0xA80A, 53 }, { 0xA80B, 0xA80B, 53 }, { 0xA80C, 0xA822, 53 }, { 0xA823, 0xA824, 53 }, { 0xA825, 0xA826, 53 }, { 0xA827, 0xA827, 53 }, { 0xA828, 0xA82B, 53 }, { 0xA840, 0xA873, 48 }, { 0xA874, 0xA877, 48 }, { 0xAC00, 0xD7A3, 25 }, { 0xF900, 0xFA2D, 24 }, { 0xFA30, 0xFA6A, 24 }, { 0xFA70, 0xFAD9, 24 }, { 0xFB00, 0xFB06, 35 }, { 0xFB13, 0xFB17, 1 }, { 0xFB1D, 0xFB1D, 27 }, { 0xFB1E, 0xFB1E, 27 }, { 0xFB1F, 0xFB28, 27 }, { 0xFB29, 0xFB29, 27 }, { 0xFB2A, 0xFB36, 27 }, { 0xFB38, 0xFB3C, 27 }, { 0xFB3E, 0xFB3E, 27 }, { 0xFB40, 0xFB41, 27 }, { 0xFB43, 0xFB44, 27 }, { 0xFB46, 0xFB4F, 27 }, { 0xFB50, 0xFBB1, 0 }, { 0xFBD3, 0xFD3D, 0 }, { 0xFD3E, 0xFD3E, 10 }, { 0xFD3F, 0xFD3F, 10 }, { 0xFD50, 0xFD8F, 0 }, { 0xFD92, 0xFDC7, 0 }, { 0xFDF0, 0xFDFB, 0 }, { 0xFDFC, 0xFDFC, 0 }, { 0xFDFD, 0xFDFD, 10 }, { 0xFE00, 0xFE0F, 29 }, { 0xFE10, 0xFE16, 10 }, { 0xFE17, 0xFE17, 10 }, { 0xFE18, 0xFE18, 10 }, { 0xFE19, 0xFE19, 10 }, { 0xFE20, 0xFE23, 29 }, { 0xFE30, 0xFE30, 10 }, { 0xFE31, 0xFE32, 10 }, { 0xFE33, 0xFE34, 10 }, { 0xFE35, 0xFE35, 10 }, { 0xFE36, 0xFE36, 10 }, { 0xFE37, 0xFE37, 10 }, { 0xFE38, 0xFE38, 10 }, { 0xFE39, 0xFE39, 10 }, { 0xFE3A, 0xFE3A, 10 }, { 0xFE3B, 0xFE3B, 10 }, { 0xFE3C, 0xFE3C, 10 }, { 0xFE3D, 0xFE3D, 10 }, { 0xFE3E, 0xFE3E, 10 }, { 0xFE3F, 0xFE3F, 10 }, { 0xFE40, 0xFE40, 10 }, { 0xFE41, 0xFE41, 10 }, { 0xFE42, 0xFE42, 10 }, { 0xFE43, 0xFE43, 10 }, { 0xFE44, 0xFE44, 10 }, { 0xFE45, 0xFE46, 10 }, { 0xFE47, 0xFE47, 10 }, { 0xFE48, 0xFE48, 10 }, { 0xFE49, 0xFE4C, 10 }, { 0xFE4D, 0xFE4F, 10 }, { 0xFE50, 0xFE52, 10 }, { 0xFE54, 0xFE57, 10 }, { 0xFE58, 0xFE58, 10 }, { 0xFE59, 0xFE59, 10 }, { 0xFE5A, 0xFE5A, 10 }, { 0xFE5B, 0xFE5B, 10 }, { 0xFE5C, 0xFE5C, 10 }, { 0xFE5D, 0xFE5D, 10 }, { 0xFE5E, 0xFE5E, 10 }, { 0xFE5F, 0xFE61, 10 }, { 0xFE62, 0xFE62, 10 }, { 0xFE63, 0xFE63, 10 }, { 0xFE64, 0xFE66, 10 }, { 0xFE68, 0xFE68, 10 }, { 0xFE69, 0xFE69, 10 }, { 0xFE6A, 0xFE6B, 10 }, { 0xFE70, 0xFE74, 0 }, { 0xFE76, 0xFEFC, 0 }, { 0xFEFF, 0xFEFF, 10 }, { 0xFF01, 0xFF03, 10 }, { 0xFF04, 0xFF04, 10 }, { 0xFF05, 0xFF07, 10 }, { 0xFF08, 0xFF08, 10 }, { 0xFF09, 0xFF09, 10 }, { 0xFF0A, 0xFF0A, 10 }, { 0xFF0B, 0xFF0B, 10 }, { 0xFF0C, 0xFF0C, 10 }, { 0xFF0D, 0xFF0D, 10 }, { 0xFF0E, 0xFF0F, 10 }, { 0xFF10, 0xFF19, 10 }, { 0xFF1A, 0xFF1B, 10 }, { 0xFF1C, 0xFF1E, 10 }, { 0xFF1F, 0xFF20, 10 }, { 0xFF21, 0xFF3A, 35 }, { 0xFF3B, 0xFF3B, 10 }, { 0xFF3C, 0xFF3C, 10 }, { 0xFF3D, 0xFF3D, 10 }, { 0xFF3E, 0xFF3E, 10 }, { 0xFF3F, 0xFF3F, 10 }, { 0xFF40, 0xFF40, 10 }, { 0xFF41, 0xFF5A, 35 }, { 0xFF5B, 0xFF5B, 10 }, { 0xFF5C, 0xFF5C, 10 }, { 0xFF5D, 0xFF5D, 10 }, { 0xFF5E, 0xFF5E, 10 }, { 0xFF5F, 0xFF5F, 10 }, { 0xFF60, 0xFF60, 10 }, { 0xFF61, 0xFF61, 10 }, { 0xFF62, 0xFF62, 10 }, { 0xFF63, 0xFF63, 10 }, { 0xFF64, 0xFF65, 10 }, { 0xFF66, 0xFF6F, 31 }, { 0xFF70, 0xFF70, 10 }, { 0xFF71, 0xFF9D, 31 }, { 0xFF9E, 0xFF9F, 10 }, { 0xFFA0, 0xFFBE, 25 }, { 0xFFC2, 0xFFC7, 25 }, { 0xFFCA, 0xFFCF, 25 }, { 0xFFD2, 0xFFD7, 25 }, { 0xFFDA, 0xFFDC, 25 }, { 0xFFE0, 0xFFE1, 10 }, { 0xFFE2, 0xFFE2, 10 }, { 0xFFE3, 0xFFE3, 10 }, { 0xFFE4, 0xFFE4, 10 }, { 0xFFE5, 0xFFE6, 10 }, { 0xFFE8, 0xFFE8, 10 }, { 0xFFE9, 0xFFEC, 10 }, { 0xFFED, 0xFFEE, 10 }, { 0xFFF9, 0xFFFB, 10 }, { 0xFFFC, 0xFFFD, 10 }, { 0x10000, 0x1000B, 37 }, { 0x1000D, 0x10026, 37 }, { 0x10028, 0x1003A, 37 }, { 0x1003C, 0x1003D, 37 }, { 0x1003F, 0x1004D, 37 }, { 0x10050, 0x1005D, 37 }, { 0x10080, 0x100FA, 37 }, { 0x10100, 0x10101, 10 }, { 0x10102, 0x10102, 10 }, { 0x10107, 0x10133, 10 }, { 0x10137, 0x1013F, 10 }, { 0x10140, 0x10174, 21 }, { 0x10175, 0x10178, 21 }, { 0x10179, 0x10189, 21 }, { 0x1018A, 0x1018A, 21 }, { 0x10300, 0x1031E, 44 }, { 0x10320, 0x10323, 44 }, { 0x10330, 0x10340, 20 }, { 0x10341, 0x10341, 20 }, { 0x10342, 0x10349, 20 }, { 0x1034A, 0x1034A, 20 }, { 0x10380, 0x1039D, 64 }, { 0x1039F, 0x1039F, 64 }, { 0x103A0, 0x103C3, 45 }, { 0x103C8, 0x103CF, 45 }, { 0x103D0, 0x103D0, 45 }, { 0x103D1, 0x103D5, 45 }, { 0x10400, 0x1044F, 15 }, { 0x10450, 0x1047F, 51 }, { 0x10480, 0x1049D, 47 }, { 0x104A0, 0x104A9, 47 }, { 0x10800, 0x10805, 13 }, { 0x10808, 0x10808, 13 }, { 0x1080A, 0x10835, 13 }, { 0x10837, 0x10838, 13 }, { 0x1083C, 0x1083C, 13 }, { 0x1083F, 0x1083F, 13 }, { 0x10900, 0x10915, 49 }, { 0x10916, 0x10919, 49 }, { 0x1091F, 0x1091F, 49 }, { 0x10A00, 0x10A00, 32 }, { 0x10A01, 0x10A03, 32 }, { 0x10A05, 0x10A06, 32 }, { 0x10A0C, 0x10A0F, 32 }, { 0x10A10, 0x10A13, 32 }, { 0x10A15, 0x10A17, 32 }, { 0x10A19, 0x10A33, 32 }, { 0x10A38, 0x10A3A, 32 }, { 0x10A3F, 0x10A3F, 32 }, { 0x10A40, 0x10A47, 32 }, { 0x10A50, 0x10A58, 32 }, { 0x12000, 0x1236E, 12 }, { 0x12400, 0x12462, 12 }, { 0x12470, 0x12473, 12 }, { 0x1D000, 0x1D0F5, 10 }, { 0x1D100, 0x1D126, 10 }, { 0x1D12A, 0x1D164, 10 }, { 0x1D165, 0x1D166, 10 }, { 0x1D167, 0x1D169, 29 }, { 0x1D16A, 0x1D16C, 10 }, { 0x1D16D, 0x1D172, 10 }, { 0x1D173, 0x1D17A, 10 }, { 0x1D17B, 0x1D182, 29 }, { 0x1D183, 0x1D184, 10 }, { 0x1D185, 0x1D18B, 29 }, { 0x1D18C, 0x1D1A9, 10 }, { 0x1D1AA, 0x1D1AD, 29 }, { 0x1D1AE, 0x1D1DD, 10 }, { 0x1D200, 0x1D241, 21 }, { 0x1D242, 0x1D244, 21 }, { 0x1D245, 0x1D245, 21 }, { 0x1D300, 0x1D356, 10 }, { 0x1D360, 0x1D371, 10 }, { 0x1D400, 0x1D454, 10 }, { 0x1D456, 0x1D49C, 10 }, { 0x1D49E, 0x1D49F, 10 }, { 0x1D4A2, 0x1D4A2, 10 }, { 0x1D4A5, 0x1D4A6, 10 }, { 0x1D4A9, 0x1D4AC, 10 }, { 0x1D4AE, 0x1D4B9, 10 }, { 0x1D4BB, 0x1D4BB, 10 }, { 0x1D4BD, 0x1D4C3, 10 }, { 0x1D4C5, 0x1D505, 10 }, { 0x1D507, 0x1D50A, 10 }, { 0x1D50D, 0x1D514, 10 }, { 0x1D516, 0x1D51C, 10 }, { 0x1D51E, 0x1D539, 10 }, { 0x1D53B, 0x1D53E, 10 }, { 0x1D540, 0x1D544, 10 }, { 0x1D546, 0x1D546, 10 }, { 0x1D54A, 0x1D550, 10 }, { 0x1D552, 0x1D6A5, 10 }, { 0x1D6A8, 0x1D6C0, 10 }, { 0x1D6C1, 0x1D6C1, 10 }, { 0x1D6C2, 0x1D6DA, 10 }, { 0x1D6DB, 0x1D6DB, 10 }, { 0x1D6DC, 0x1D6FA, 10 }, { 0x1D6FB, 0x1D6FB, 10 }, { 0x1D6FC, 0x1D714, 10 }, { 0x1D715, 0x1D715, 10 }, { 0x1D716, 0x1D734, 10 }, { 0x1D735, 0x1D735, 10 }, { 0x1D736, 0x1D74E, 10 }, { 0x1D74F, 0x1D74F, 10 }, { 0x1D750, 0x1D76E, 10 }, { 0x1D76F, 0x1D76F, 10 }, { 0x1D770, 0x1D788, 10 }, { 0x1D789, 0x1D789, 10 }, { 0x1D78A, 0x1D7A8, 10 }, { 0x1D7A9, 0x1D7A9, 10 }, { 0x1D7AA, 0x1D7C2, 10 }, { 0x1D7C3, 0x1D7C3, 10 }, { 0x1D7C4, 0x1D7CB, 10 }, { 0x1D7CE, 0x1D7FF, 10 }, { 0x20000, 0x2A6D6, 24 }, { 0x2F800, 0x2FA1D, 24 }, { 0xE0001, 0xE0001, 10 }, { 0xE0020, 0xE007F, 10 }, { 0xE0100, 0xE01EF, 29 }, { 0x0, 0x0, -1 } }; #endif diff --git a/kcms/krdb/krdb.cpp b/kcms/krdb/krdb.cpp index 128c45bcf..c0827a281 100644 --- a/kcms/krdb/krdb.cpp +++ b/kcms/krdb/krdb.cpp @@ -1,730 +1,730 @@ /**************************************************************************** ** ** ** 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(":")); 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::Background ); clr = wmCfgGroup.readEntry("activeBackground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/activeBackground"), clr.name()); if (QPixmap::defaultDepth() > 8) clr = clr.dark(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::Background ); 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::Background); clr = wmCfgGroup.readEntry("inactiveBackground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveBackground"), clr.name()); if (QPixmap::defaultDepth() > 8) clr = clr.dark(110); clr = wmCfgGroup.readEntry("inactiveBlend", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveBlend"), clr.name()); clr = newPal.color(QPalette::Inactive, QPalette::Background).dark(); clr = wmCfgGroup.readEntry("inactiveForeground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveForeground"), clr.name()); clr = newPal.color(QPalette::Inactive, QPalette::Background); 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::Background ) ) << endl; t << " bg[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl; t << " bg[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Background ) ) << endl; t << " bg[ACTIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl; t << " bg[PRELIGHT] = " << color( cg.color( QPalette::Active, QPalette::Background ) ) << 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::Background ) ) << 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::Foreground ) ) << 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::Foreground ) ) << endl; t << " fg[PRELIGHT] = " << color( cg.color( QPalette::Active, QPalette::Foreground ) ) << 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; QPalette group = QToolTip::palette(); t << " bg[NORMAL] = " << color( group.color( QPalette::Active, QPalette::Background ) ) << endl; t << " base[NORMAL] = " << color( group.color( QPalette::Active, QPalette::Base ) ) << endl; t << " text[NORMAL] = " << color( group.color( QPalette::Active, QPalette::Text ) ) << endl; t << " fg[NORMAL] = " << color( group.color( QPalette::Active, QPalette::Foreground ) ) << endl; t << "}" << endl; t << endl; t << "widget \"gtk-tooltip\" style \"ToolTip\"" << endl; t << "widget \"gtk-tooltips\" 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(); } // ----------------------------------------------------------------------------- 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; 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::Background ); addColorDef(preproc, "FOREGROUND" , newPal.color( QPalette::Active, QPalette::Foreground ) ); addColorDef(preproc, "BACKGROUND" , backCol); addColorDef(preproc, "HIGHLIGHT" , backCol.light(100+(2*KColorScheme::contrast()+4)*16/1)); addColorDef(preproc, "LOWLIGHT" , backCol.dark(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) { if (generalCfgGroup.hasKey("XftAntialias")) { contents += QLatin1String("Xft.antialias: "); if(generalCfgGroup.readEntry("XftAntialias", true)) contents += QLatin1String("1\n"); else contents += QLatin1String("0\n"); } if (generalCfgGroup.hasKey("XftHintStyle")) { QString hintStyle = generalCfgGroup.readEntry("XftHintStyle", "hintmedium"); 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'; } } if (generalCfgGroup.hasKey("XftSubPixel")) { QString subPixel = generalCfgGroup.readEntry("XftSubPixel"); 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")) { // 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( 0 ); // Use the $DISPLAY envvar. + 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")); } diff --git a/kcms/ksmserver/kcmsmserver.h b/kcms/ksmserver/kcmsmserver.h index 811f224ad..07d830a55 100644 --- a/kcms/ksmserver/kcmsmserver.h +++ b/kcms/ksmserver/kcmsmserver.h @@ -1,44 +1,44 @@ /* * kcmsmserver.h * Copyright (c) 2000 Oswald Buddenhagen * * based on kcmtaskbar.h * 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 */ #ifndef __kcmsmserver_h__ #define __kcmsmserver_h__ #include class SMServerConfigImpl; class SMServerConfig : public KCModule { Q_OBJECT public: - explicit SMServerConfig( QWidget *parent=0, const QVariantList &list=QVariantList() ); + explicit SMServerConfig( QWidget *parent=nullptr, const QVariantList &list=QVariantList() ); void load() override; void save() override; void defaults() override; private: SMServerConfigImpl* dialog; }; #endif diff --git a/kcms/ksmserver/smserverconfigimpl.h b/kcms/ksmserver/smserverconfigimpl.h index 004359afc..00a53cd9a 100644 --- a/kcms/ksmserver/smserverconfigimpl.h +++ b/kcms/ksmserver/smserverconfigimpl.h @@ -1,50 +1,50 @@ /*************************************************************************** smserverconfigimpl.h - description ------------------- begin : Thu May 17 2001 copyright : (C) 2001 by stulle email : stulle@tux ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef SMSERVERCONFIGIMPL_H #define SMSERVERCONFIGIMPL_H #include #include "ui_smserverconfigdlg.h" /** *@author stulle */ class SMServerConfigDlg : public QWidget, public Ui::SMServerConfigDlg { public: SMServerConfigDlg( QWidget *parent ) : QWidget( parent ) { setupUi( this ); } }; class SMServerConfigImpl : public SMServerConfigDlg { Q_OBJECT public: - SMServerConfigImpl(QWidget *parent=0); + SMServerConfigImpl(QWidget *parent=nullptr); ~SMServerConfigImpl() override; public Q_SLOTS: // Public slots /** No descriptions */ void configChanged(); Q_SIGNALS: // Signals /** No descriptions */ void changed(); }; #endif diff --git a/kcms/ksplash/kcm.cpp b/kcms/ksplash/kcm.cpp index 0edf7ef2a..e7809e5f3 100644 --- a/kcms/ksplash/kcm.cpp +++ b/kcms/ksplash/kcm.cpp @@ -1,210 +1,210 @@ /* This file is part of the KDE Project Copyright (c) 2014 Marco Martin Copyright (c) 2014 Vishesh Handa 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 K_PLUGIN_FACTORY_WITH_JSON(KCMSplashScreenFactory, "kcm_splashscreen.json", registerPlugin();) KCMSplashScreen::KCMSplashScreen(QObject* parent, const QVariantList& args) : KQuickAddons::ConfigModule(parent, args) , m_config(QStringLiteral("ksplashrc")) , m_configGroup(m_config.group("KSplash")) { qmlRegisterType(); KAboutData* about = new KAboutData(QStringLiteral("kcm_splashscreen"), i18n("Configure Splash screen details"), QStringLiteral("0.1"), QString(), KAboutLicense::LGPL); about->addAuthor(i18n("Marco Martin"), QString(), QStringLiteral("mart@kde.org")); setAboutData(about); setButtons(Help | Apply | Default); m_model = new QStandardItemModel(this); QHash roles = m_model->roleNames(); roles[PluginNameRole] = "pluginName"; roles[ScreenhotRole] = "screenshot"; roles[DescriptionRole] = "description"; m_model->setItemRoleNames(roles); loadModel(); } QList KCMSplashScreen::availablePackages(const QString &component) { QList packages; QStringList paths; const QStringList dataPaths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); for (const QString &path : dataPaths) { QDir dir(path + QStringLiteral("/plasma/look-and-feel")); paths << dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); } for (const QString &path : paths) { Plasma::Package pkg = Plasma::PluginLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel")); pkg.setPath(path); pkg.setFallbackPackage(Plasma::Package()); if (component.isEmpty() || !pkg.filePath(component.toUtf8()).isEmpty()) { packages << pkg; } } return packages; } QStandardItemModel *KCMSplashScreen::splashModel() { return m_model; } QString KCMSplashScreen::selectedPlugin() const { return m_selectedPlugin; } void KCMSplashScreen::setSelectedPlugin(const QString &plugin) { if (m_selectedPlugin == plugin) { return; } if (!m_selectedPlugin.isEmpty()) { setNeedsSave(true); } m_selectedPlugin = plugin; emit selectedPluginChanged(); emit selectedPluginIndexChanged(); } void KCMSplashScreen::getNewClicked() { - KNS3::DownloadDialog dialog("ksplash.knsrc", 0); + KNS3::DownloadDialog dialog("ksplash.knsrc", nullptr); if (dialog.exec()) { KNS3::Entry::List list = dialog.changedEntries(); if (list.count() > 0) { loadModel(); } } } void KCMSplashScreen::loadModel() { m_model->clear(); QStandardItem* row = new QStandardItem(i18n("None")); row->setData("None", PluginNameRole); row->setData(i18n("No splash screen will be shown"), DescriptionRole); m_model->appendRow(row); const QList pkgs = availablePackages(QStringLiteral("splashmainscript")); for (const Plasma::Package &pkg : pkgs) { QStandardItem* row = new QStandardItem(pkg.metadata().name()); row->setData(pkg.metadata().pluginName(), PluginNameRole); row->setData(pkg.filePath("previews", QStringLiteral("splash.png")), ScreenhotRole); row->setData(pkg.metadata().comment(), DescriptionRole); m_model->appendRow(row); } emit selectedPluginIndexChanged(); } void KCMSplashScreen::load() { m_package = Plasma::PluginLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel")); KConfigGroup cg(KSharedConfig::openConfig(QStringLiteral("kdeglobals")), "KDE"); const QString packageName = cg.readEntry("LookAndFeelPackage", QString()); if (!packageName.isEmpty()) { m_package.setPath(packageName); } QString currentPlugin = m_configGroup.readEntry("Theme", QString()); if (currentPlugin.isEmpty()) { currentPlugin = m_package.metadata().pluginName(); } setSelectedPlugin(currentPlugin); setNeedsSave(false); } void KCMSplashScreen::save() { if (m_selectedPlugin.isEmpty()) { return; } else if (m_selectedPlugin == QLatin1String("None")) { m_configGroup.writeEntry("Theme", m_selectedPlugin); m_configGroup.writeEntry("Engine", "none"); } else { m_configGroup.writeEntry("Theme", m_selectedPlugin); m_configGroup.writeEntry("Engine", "KSplashQML"); } m_configGroup.sync(); setNeedsSave(false); } void KCMSplashScreen::defaults() { if (!m_package.metadata().isValid()) { return; } setSelectedPlugin(m_package.metadata().pluginName()); } int KCMSplashScreen::selectedPluginIndex() const { for (int i = 0; i < m_model->rowCount(); ++i) { if (m_model->data(m_model->index(i, 0), PluginNameRole).toString() == m_selectedPlugin) { return i; } } return -1; } void KCMSplashScreen::test(const QString &plugin) { if (plugin.isEmpty() || plugin == QLatin1String("None")) { return; } QProcess proc; QStringList arguments; arguments << plugin << QStringLiteral("--test"); if (proc.execute(QStringLiteral("ksplashqml"), arguments)) { - QMessageBox::critical(0, i18n("Error"), i18n("Failed to successfully test the splash screen.")); + QMessageBox::critical(nullptr, i18n("Error"), i18n("Failed to successfully test the splash screen.")); } } #include "kcm.moc" diff --git a/kcms/lookandfeel/autotests/kcmtest.cpp b/kcms/lookandfeel/autotests/kcmtest.cpp index 6cf30758c..41ffe6bf0 100644 --- a/kcms/lookandfeel/autotests/kcmtest.cpp +++ b/kcms/lookandfeel/autotests/kcmtest.cpp @@ -1,219 +1,219 @@ /******************************************************************** KSld - the KDE Screenlocker Daemon This file is part of the KDE project. Copyright (C) 2014 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "../kcm.h" // Qt #include #include #include #include #include class KcmTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void testWidgetStyle(); void testColors(); void testIcons(); void testPlasmaTheme(); void testCursorTheme(); void testSplashScreen(); void testLockScreen(); void testWindowSwitcher(); void testDesktopSwitcher(); void testKCMSave(); private: QDir m_configDir; QDir m_dataDir; KCMLookandFeel *m_KCMLookandFeel; }; void KcmTest::initTestCase() { QStandardPaths::setTestModeEnabled(true); m_configDir = QDir(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)); m_configDir.removeRecursively(); m_dataDir = QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)); m_dataDir.removeRecursively(); QVERIFY(m_configDir.mkpath(".")); //we need an existing colorscheme file, even if empty QVERIFY(m_dataDir.mkpath(QStringLiteral("color-schemes"))); QFile f(m_dataDir.path() + QStringLiteral("/color-schemes/TestValue.colors")); f.open(QIODevice::WriteOnly); f.close(); const QString packagePath = QFINDTESTDATA("lookandfeel"); Plasma::Package p = Plasma::PluginLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel")); p.setPath(packagePath); QVERIFY(p.isValid()); const QString packageRoot = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)+"/plasma/look-and-feel/"; auto installJob = p.install(packagePath, packageRoot); installJob->exec(); KConfig config(QStringLiteral("kdeglobals")); KConfigGroup cg(&config, "KDE"); cg.writeEntry("LookAndFeelPackage", "org.kde.test"); cg.sync(); - m_KCMLookandFeel = new KCMLookandFeel(0, QVariantList()); + m_KCMLookandFeel = new KCMLookandFeel(nullptr, QVariantList()); m_KCMLookandFeel->load(); } void KcmTest::cleanupTestCase() { m_configDir.removeRecursively(); m_dataDir.removeRecursively(); } void KcmTest::testWidgetStyle() { m_KCMLookandFeel->setWidgetStyle(QStringLiteral("customTestValue")); KConfig config(QStringLiteral("kdeglobals")); KConfigGroup cg(&config, "KDE"); QCOMPARE(cg.readEntry("widgetStyle", QString()), QString("customTestValue")); } void KcmTest::testColors() { //TODO: test colorFile as well m_KCMLookandFeel->setColors(QStringLiteral("customTestValue"), QString()); KConfig config(QStringLiteral("kdeglobals")); KConfigGroup cg(&config, "General"); QCOMPARE(cg.readEntry("ColorScheme", QString()), QString("customTestValue")); } void KcmTest::testIcons() { m_KCMLookandFeel->setIcons(QStringLiteral("customTestValue")); KConfig config(QStringLiteral("kdeglobals")); KConfigGroup cg(&config, "Icons"); QCOMPARE(cg.readEntry("Theme", QString()), QString("customTestValue")); } void KcmTest::testPlasmaTheme() { m_KCMLookandFeel->setPlasmaTheme(QStringLiteral("customTestValue")); KConfig config(QStringLiteral("plasmarc")); KConfigGroup cg(&config, "Theme"); QCOMPARE(cg.readEntry("name", QString()), QString("customTestValue")); } void KcmTest::testCursorTheme() { m_KCMLookandFeel->setCursorTheme(QStringLiteral("customTestValue")); KConfig config(QStringLiteral("kcminputrc")); KConfigGroup cg(&config, "Mouse"); QCOMPARE(cg.readEntry("cursorTheme", QString()), QString("customTestValue")); } void KcmTest::testSplashScreen() { m_KCMLookandFeel->setSplashScreen(QStringLiteral("customTestValue")); KConfig config(QStringLiteral("ksplashrc")); KConfigGroup cg(&config, "KSplash"); QCOMPARE(cg.readEntry("Theme", QString()), QString("customTestValue")); QCOMPARE(cg.readEntry("Engine", QString()), QString("KSplashQML")); } void KcmTest::testLockScreen() { m_KCMLookandFeel->setLockScreen(QStringLiteral("customTestValue")); KConfig config(QStringLiteral("kscreenlockerrc")); KConfigGroup cg(&config, "Greeter"); QCOMPARE(cg.readEntry("Theme", QString()), QString("customTestValue")); } void KcmTest::testWindowSwitcher() { m_KCMLookandFeel->setWindowSwitcher(QStringLiteral("customTestValue")); KConfig config(QStringLiteral("kwinrc")); KConfigGroup cg(&config, "TabBox"); QCOMPARE(cg.readEntry("LayoutName", QString()), QStringLiteral("customTestValue")); } void KcmTest::testDesktopSwitcher() { m_KCMLookandFeel->setDesktopSwitcher(QStringLiteral("customTestValue")); KConfig config(QStringLiteral("kwinrc")); KConfigGroup cg(&config, "TabBox"); QCOMPARE(cg.readEntry("DesktopLayout", QString()), QStringLiteral("customTestValue")); QCOMPARE(cg.readEntry("DesktopListLayout", QString()), QStringLiteral("customTestValue")); } void KcmTest::testKCMSave() { m_KCMLookandFeel->save(); KConfig config(QStringLiteral("kdeglobals")); KConfigGroup cg(&config, "KDE"); QCOMPARE(cg.readEntry("widgetStyle", QString()), QString("testValue")); cg = KConfigGroup(&config, "General"); //save() capitalizes the ColorScheme QCOMPARE(cg.readEntry("ColorScheme", QString()), QString("TestValue")); cg = KConfigGroup(&config, "Icons"); QCOMPARE(cg.readEntry("Theme", QString()), QString("testValue")); KConfig plasmaConfig(QStringLiteral("plasmarc")); cg = KConfigGroup(&plasmaConfig, "Theme"); QCOMPARE(cg.readEntry("name", QString()), QString("testValue")); KConfig inputConfig(QStringLiteral("kcminputrc")); cg = KConfigGroup(&inputConfig, "Mouse"); QCOMPARE(cg.readEntry("cursorTheme", QString()), QString("testValue")); KConfig splashConfig(QStringLiteral("ksplashrc")); cg = KConfigGroup(&splashConfig, "KSplash"); QCOMPARE(cg.readEntry("Theme", QString()), QString("org.kde.test")); QCOMPARE(cg.readEntry("Engine", QString()), QString("KSplashQML")); KConfig lockerConfig(QStringLiteral("kscreenlockerrc")); cg = KConfigGroup(&lockerConfig, "Greeter"); QCOMPARE(cg.readEntry("Theme", QString()), QString("org.kde.test")); KConfig kwinConfig(QStringLiteral("kwinrc")); cg = KConfigGroup(&kwinConfig, "TabBox"); QCOMPARE(cg.readEntry("LayoutName", QString()), QStringLiteral("testValue")); QCOMPARE(cg.readEntry("DesktopLayout", QString()), QStringLiteral("testDesktopValue")); QCOMPARE(cg.readEntry("DesktopListLayout", QString()), QStringLiteral("testDesktopValue")); } QTEST_MAIN(KcmTest) #include "kcmtest.moc" diff --git a/kcms/phonon/devicepreference.cpp b/kcms/phonon/devicepreference.cpp index a4a8440e3..c2f8ccb2a 100644 --- a/kcms/phonon/devicepreference.cpp +++ b/kcms/phonon/devicepreference.cpp @@ -1,993 +1,993 @@ /* This file is part of the KDE project Copyright (C) 2006-2008 Matthias Kretz Copyright (C) 2011 Casian Andrei Copyright (C) 2014 Harald Sitter This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) version 3. 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 "devicepreference.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef METATYPE_QLIST_INT_DEFINED #define METATYPE_QLIST_INT_DEFINED // Want this exactly once, see phonondefs_p.h kcm/devicepreference.cpp Q_DECLARE_METATYPE(QList) #endif namespace Phonon { /* * Lists of categories for every device type */ static const Category audioOutCategories[] = { NoCategory, NotificationCategory, MusicCategory, VideoCategory, CommunicationCategory, GameCategory, AccessibilityCategory, }; static const CaptureCategory audioCapCategories[] = { NoCaptureCategory, CommunicationCaptureCategory, RecordingCaptureCategory, ControlCaptureCategory }; static const CaptureCategory videoCapCategories[] = { NoCaptureCategory, CommunicationCaptureCategory, RecordingCaptureCategory, }; static const int audioOutCategoriesCount = sizeof(audioOutCategories) / sizeof(Category); static const int audioCapCategoriesCount = sizeof(audioCapCategories) / sizeof(CaptureCategory); static const int videoCapCategoriesCount = sizeof(videoCapCategories) / sizeof(CaptureCategory); void operator++(Category &c) { c = static_cast(1 + static_cast(c)); //Q_ASSERT(c <= LastCategory); } class CategoryItem : public QStandardItem { public: CategoryItem(Category cat) : QStandardItem(), m_cat(cat), m_odtype(AudioOutputDeviceType) { if (cat == NoCategory) { setText(i18n("Audio Playback")); } else { setText(categoryToString(cat)); } } CategoryItem(CaptureCategory cat, ObjectDescriptionType t = AudioCaptureDeviceType) : QStandardItem(), m_capcat(cat), m_odtype(t) { if (cat == NoCaptureCategory) { switch(t) { case AudioCaptureDeviceType: setText(i18n("Audio Recording")); break; case VideoCaptureDeviceType: setText(i18n("Video Recording")); break; default: setText(i18n("Invalid")); } } else { setText(categoryToString(cat)); } } int type() const override { return 1001; } Category category() const { return m_cat; } CaptureCategory captureCategory() const { return m_capcat; } ObjectDescriptionType odtype() const { return m_odtype; } private: Category m_cat; CaptureCategory m_capcat; ObjectDescriptionType m_odtype; }; /** * Need this to change the colors of the ListView if the Palette changed. With CSS set this won't * change automatically */ void DevicePreference::changeEvent(QEvent *e) { QWidget::changeEvent(e); if (e->type() == QEvent::PaletteChange) { deviceList->setStyleSheet(deviceList->styleSheet()); } } DevicePreference::DevicePreference(QWidget *parent) : QWidget(parent), - m_headerModel(0, 1, 0), + m_headerModel(0, 1, nullptr), m_media(nullptr), m_audioOutput(nullptr), m_videoWidget(nullptr) { setupUi(this); // Setup the buttons testPlaybackButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); testPlaybackButton->setEnabled(false); testPlaybackButton->setToolTip(i18n("Test the selected device")); deferButton->setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); preferButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); // Configure the device list deviceList->setDragDropMode(QAbstractItemView::InternalMove); deviceList->setStyleSheet(QStringLiteral("QTreeView {" "background-color: palette(base);" "background-image: url(%1);" "background-position: bottom left;" "background-attachment: fixed;" "background-repeat: no-repeat;" "background-clip: padding;" "}") .arg(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kcm_phonon/listview-background.png"))); deviceList->setAlternatingRowColors(false); // The root item for the categories QStandardItem *parentItem = m_categoryModel.invisibleRootItem(); // Audio Output Parent QStandardItem *aOutputItem = new CategoryItem(NoCategory); m_audioOutputModel[NoCategory] = new AudioOutputDeviceModel(this); aOutputItem->setEditable(false); aOutputItem->setToolTip(i18n("Defines the default ordering of devices which can be overridden by individual categories.")); parentItem->appendRow(aOutputItem); // Audio Capture Parent QStandardItem *aCaptureItem = new CategoryItem(NoCaptureCategory, AudioCaptureDeviceType); m_audioCaptureModel[NoCaptureCategory] = new AudioCaptureDeviceModel(this); aCaptureItem->setEditable(false); aCaptureItem->setToolTip(i18n("Defines the default ordering of devices which can be overridden by individual categories.")); parentItem->appendRow(aCaptureItem); // Video Capture Parent QStandardItem *vCaptureItem = new CategoryItem(NoCaptureCategory, VideoCaptureDeviceType); m_videoCaptureModel[NoCaptureCategory] = new VideoCaptureDeviceModel(this); vCaptureItem->setEditable(false); vCaptureItem->setToolTip(i18n("Defines the default ordering of devices which can be overridden by individual categories.")); parentItem->appendRow(vCaptureItem); // Audio Output Children parentItem = aOutputItem; for (int i = 1; i < audioOutCategoriesCount; ++i) { // i == 1 to skip NoCategory m_audioOutputModel[audioOutCategories[i]] = new AudioOutputDeviceModel(this); QStandardItem *item = new CategoryItem(audioOutCategories[i]); item->setEditable(false); parentItem->appendRow(item); } // Audio Capture Children parentItem = aCaptureItem; for (int i = 1; i < audioCapCategoriesCount; ++i) { // i == 1 to skip NoCategory m_audioCaptureModel[audioCapCategories[i]] = new AudioCaptureDeviceModel(this); QStandardItem *item = new CategoryItem(audioCapCategories[i], AudioCaptureDeviceType); item->setEditable(false); parentItem->appendRow(item); } // Video Capture Children parentItem = vCaptureItem; for (int i = 1; i < videoCapCategoriesCount; ++i) { // i == 1 to skip NoCategory m_videoCaptureModel[videoCapCategories[i]] = new VideoCaptureDeviceModel(this); QStandardItem *item = new CategoryItem(videoCapCategories[i], VideoCaptureDeviceType); item->setEditable(false); parentItem->appendRow(item); } // Configure the category tree categoryTree->setModel(&m_categoryModel); if (categoryTree->header()) { categoryTree->header()->hide(); } categoryTree->expandAll(); connect(categoryTree->selectionModel(), SIGNAL(currentChanged(const QModelIndex &,const QModelIndex &)), SLOT(updateDeviceList())); // Connect all model data change signals to the changed slot for (int i = -1; i <= LastCategory; ++i) { connect(m_audioOutputModel[i], SIGNAL(rowsInserted(QModelIndex, int, int)), this, SIGNAL(changed())); connect(m_audioOutputModel[i], SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SIGNAL(changed())); connect(m_audioOutputModel[i], SIGNAL(layoutChanged()), this, SIGNAL(changed())); connect(m_audioOutputModel[i], SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(changed())); if (m_audioCaptureModel.contains(i)) { connect(m_audioCaptureModel[i], SIGNAL(rowsInserted(QModelIndex, int, int)), this, SIGNAL(changed())); connect(m_audioCaptureModel[i], SIGNAL(rowsRemoved(QModelIndex , int, int)), this, SIGNAL(changed())); connect(m_audioCaptureModel[i], SIGNAL(layoutChanged()), this, SIGNAL(changed())); connect(m_audioCaptureModel[i], SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(changed())); } if (m_videoCaptureModel.contains(i)) { connect(m_videoCaptureModel[i], SIGNAL(rowsInserted(QModelIndex, int, int)), this, SIGNAL(changed())); connect(m_videoCaptureModel[i], SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SIGNAL(changed())); connect(m_videoCaptureModel[i], SIGNAL(layoutChanged()), this, SIGNAL(changed())); connect(m_videoCaptureModel[i], SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(changed())); } } connect(showAdvancedDevicesCheckBox, &QCheckBox::stateChanged, this, &DevicePreference::changed); // Connect the signals from Phonon that notify changes in the device lists connect(BackendCapabilities::notifier(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(updateAudioOutputDevices())); connect(BackendCapabilities::notifier(), SIGNAL(availableAudioCaptureDevicesChanged()), SLOT(updateAudioCaptureDevices())); connect(BackendCapabilities::notifier(), SIGNAL(availableVideoCaptureDevicesChanged()), SLOT(updateVideoCaptureDevices())); connect(BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), SLOT(updateAudioOutputDevices())); connect(BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), SLOT(updateAudioCaptureDevices())); connect(BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), SLOT(updateVideoCaptureDevices())); if (!categoryTree->currentIndex().isValid()) { categoryTree->setCurrentIndex(m_categoryModel.index(0, 0).child(1, 0)); } } DevicePreference::~DevicePreference() { // Ensure that the video widget is destroyed, if it remains active delete m_videoWidget; } void DevicePreference::updateDeviceList() { // Temporarily disconnect the device list selection model if (deviceList->selectionModel()) { disconnect(deviceList->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &,const QModelIndex &)), this, SLOT(updateButtonsEnabled())); } // Get the current selected category item QStandardItem *currentItem = m_categoryModel.itemFromIndex(categoryTree->currentIndex()); if (currentItem && currentItem->type() == 1001) { CategoryItem *catItem = static_cast(currentItem); bool cap = catItem->odtype() != AudioOutputDeviceType; const Category cat = catItem->category(); const CaptureCategory capcat = catItem->captureCategory(); // Update the device list, by setting it's model to the one for the corresponding category switch (catItem->odtype()) { case AudioOutputDeviceType: deviceList->setModel(m_audioOutputModel[cat]); break; case AudioCaptureDeviceType: deviceList->setModel(m_audioCaptureModel[capcat]); break; case VideoCaptureDeviceType: deviceList->setModel(m_videoCaptureModel[capcat]); break; default: ; } // Update the header if (cap ? capcat == NoCaptureCategory : cat == NoCategory) { switch (catItem->odtype()) { case AudioOutputDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Default Audio Playback Device Preference"), Qt::DisplayRole); break; case AudioCaptureDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Default Audio Recording Device Preference"), Qt::DisplayRole); break; case VideoCaptureDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Default Video Recording Device Preference"), Qt::DisplayRole); break; default: ; } } else { switch (catItem->odtype()) { case AudioOutputDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Audio Playback Device Preference for the '%1' Category", categoryToString(cat)), Qt::DisplayRole); break; case AudioCaptureDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Audio Recording Device Preference for the '%1' Category", categoryToString(capcat)), Qt::DisplayRole); break; case VideoCaptureDeviceType: m_headerModel.setHeaderData(0, Qt::Horizontal, i18n("Video Recording Device Preference for the '%1' Category ", categoryToString(capcat)), Qt::DisplayRole); break; default: ; } } } else { // No valid category selected m_headerModel.setHeaderData(0, Qt::Horizontal, QString(), Qt::DisplayRole); deviceList->setModel(nullptr); } // Update the header, the buttons enabled state deviceList->header()->setModel(&m_headerModel); updateButtonsEnabled(); // Reconnect the device list selection model if (deviceList->selectionModel()) { connect(deviceList->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &,const QModelIndex &)), this, SLOT(updateButtonsEnabled())); } deviceList->resizeColumnToContents(0); } void DevicePreference::updateAudioCaptureDevices() { const QList list = availableAudioCaptureDevices(); QHash hash; foreach (const AudioCaptureDevice &dev, list) { hash.insert(dev.index(), dev); } for (int catIndex = 0; catIndex < audioCapCategoriesCount; ++ catIndex) { const int i = audioCapCategories[catIndex]; AudioCaptureDeviceModel *model = m_audioCaptureModel.value(i); Q_ASSERT(model); QHash hashCopy(hash); QList orderedList; if (model->rowCount() > 0) { QList order = model->tupleIndexOrder(); foreach (int idx, order) { if (hashCopy.contains(idx)) { orderedList << hashCopy.take(idx); } } if (hashCopy.size() > 1) { // keep the order of the original list foreach (const AudioCaptureDevice &dev, list) { if (hashCopy.contains(dev.index())) { orderedList << hashCopy.take(dev.index()); } } } else if (hashCopy.size() == 1) { orderedList += hashCopy.values(); } model->setModelData(orderedList); } else { model->setModelData(list); } } deviceList->resizeColumnToContents(0); } void DevicePreference::updateVideoCaptureDevices() { const QList list = availableVideoCaptureDevices(); QHash hash; foreach (const VideoCaptureDevice &dev, list) { hash.insert(dev.index(), dev); } for (int catIndex = 0; catIndex < videoCapCategoriesCount; ++ catIndex) { const int i = videoCapCategories[catIndex]; VideoCaptureDeviceModel *model = m_videoCaptureModel.value(i); Q_ASSERT(model); QHash hashCopy(hash); QList orderedList; if (model->rowCount() > 0) { QList order = model->tupleIndexOrder(); foreach (int idx, order) { if (hashCopy.contains(idx)) { orderedList << hashCopy.take(idx); } } if (hashCopy.size() > 1) { // keep the order of the original list foreach (const VideoCaptureDevice &dev, list) { if (hashCopy.contains(dev.index())) { orderedList << hashCopy.take(dev.index()); } } } else if (hashCopy.size() == 1) { orderedList += hashCopy.values(); } model->setModelData(orderedList); } else { model->setModelData(list); } } deviceList->resizeColumnToContents(0); } void DevicePreference::updateAudioOutputDevices() { const QList list = availableAudioOutputDevices(); QHash hash; foreach (const AudioOutputDevice &dev, list) { hash.insert(dev.index(), dev); } for (int catIndex = 0; catIndex < audioOutCategoriesCount; ++ catIndex) { const int i = audioOutCategories[catIndex]; AudioOutputDeviceModel *model = m_audioOutputModel.value(i); Q_ASSERT(model); QHash hashCopy(hash); QList orderedList; if (model->rowCount() > 0) { QList order = model->tupleIndexOrder(); foreach (int idx, order) { if (hashCopy.contains(idx)) { orderedList << hashCopy.take(idx); } } if (hashCopy.size() > 1) { // keep the order of the original list foreach (const AudioOutputDevice &dev, list) { if (hashCopy.contains(dev.index())) { orderedList << hashCopy.take(dev.index()); } } } else if (hashCopy.size() == 1) { orderedList += hashCopy.values(); } model->setModelData(orderedList); } else { model->setModelData(list); } } deviceList->resizeColumnToContents(0); } QList DevicePreference::availableAudioOutputDevices() const { return BackendCapabilities::availableAudioOutputDevices(); } QList DevicePreference::availableAudioCaptureDevices() const { #ifndef PHONON_NO_AUDIOCAPTURE return BackendCapabilities::availableAudioCaptureDevices(); #else return QList(); #endif } QList DevicePreference::availableVideoCaptureDevices() const { #ifndef PHONON_NO_VIDEOCAPTURE return BackendCapabilities::availableVideoCaptureDevices(); #else return QList(); #endif } void DevicePreference::load() { showAdvancedDevicesCheckBox->setChecked(!GlobalConfig().hideAdvancedDevices()); loadCategoryDevices(); } void DevicePreference::loadCategoryDevices() { // "Load" the settings from the backend. for (int i = 0; i < audioOutCategoriesCount; ++ i) { const Category cat = audioOutCategories[i]; QList list; const QList deviceIndexes = GlobalConfig().audioOutputDeviceListFor(cat); foreach (int i, deviceIndexes) { list.append(AudioOutputDevice::fromIndex(i)); } m_audioOutputModel[cat]->setModelData(list); } #ifndef PHONON_NO_AUDIOCAPTURE for (int i = 0; i < audioCapCategoriesCount; ++ i) { const CaptureCategory cat = audioCapCategories[i]; QList list; const QList deviceIndexes = GlobalConfig().audioCaptureDeviceListFor(cat); foreach (int i, deviceIndexes) { list.append(AudioCaptureDevice::fromIndex(i)); } m_audioCaptureModel[cat]->setModelData(list); } #endif #ifndef PHONON_NO_VIDEOCAPTURE for (int i = 0; i < videoCapCategoriesCount; ++ i) { const CaptureCategory cat = videoCapCategories[i]; QList list; const QList deviceIndexes = GlobalConfig().videoCaptureDeviceListFor(cat); foreach (int i, deviceIndexes) { list.append(VideoCaptureDevice::fromIndex(i)); } m_videoCaptureModel[cat]->setModelData(list); } #endif deviceList->resizeColumnToContents(0); } void DevicePreference::save() { for (int i = 0; i < audioOutCategoriesCount; ++i) { const Category cat = audioOutCategories[i]; Q_ASSERT(m_audioOutputModel.value(cat)); const QList order = m_audioOutputModel.value(cat)->tupleIndexOrder(); GlobalConfig().setAudioOutputDeviceListFor(cat, order); } #ifndef PHONON_NO_AUDIOCAPTURE for (int i = 0; i < audioCapCategoriesCount; ++i) { const CaptureCategory cat = audioCapCategories[i]; Q_ASSERT(m_audioCaptureModel.value(cat)); const QList order = m_audioCaptureModel.value(cat)->tupleIndexOrder(); GlobalConfig().setAudioCaptureDeviceListFor(cat, order); } #endif #ifndef PHONON_NO_VIDEOCAPTURE for (int i = 0; i < videoCapCategoriesCount; ++i) { const CaptureCategory cat = videoCapCategories[i]; Q_ASSERT(m_videoCaptureModel.value(cat)); const QList order = m_videoCaptureModel.value(cat)->tupleIndexOrder(); GlobalConfig().setVideoCaptureDeviceListFor(cat, order); } #endif } void DevicePreference::defaults() { { const QList list = availableAudioOutputDevices(); for (int i = 0; i < audioOutCategoriesCount; ++i) { m_audioOutputModel[audioOutCategories[i]]->setModelData(list); } } { const QList list = availableAudioCaptureDevices(); for (int i = 0; i < audioCapCategoriesCount; ++i) { m_audioCaptureModel[audioCapCategories[i]]->setModelData(list); } } { const QList list = availableVideoCaptureDevices(); for (int i = 0; i < videoCapCategoriesCount; ++i) { m_videoCaptureModel[videoCapCategories[i]]->setModelData(list); } } /* * Save this list (that contains even hidden devices) to GlobaConfig, and then * load them back. All devices that should be hidden will be hidden */ save(); loadCategoryDevices(); deviceList->resizeColumnToContents(0); } void DevicePreference::pulseAudioEnabled() { showAdvancedDevicesContainer->removeItem(showAdvancedDevicesSpacer); delete showAdvancedDevicesSpacer; showAdvancedDevicesCheckBox->setVisible(false); } void DevicePreference::on_preferButton_clicked() { QAbstractItemModel *model = deviceList->model(); { AudioOutputDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveUp(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } { AudioCaptureDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveUp(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } { VideoCaptureDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveUp(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } } void DevicePreference::on_deferButton_clicked() { QAbstractItemModel *model = deviceList->model(); { AudioOutputDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveDown(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } { AudioCaptureDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveDown(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } { VideoCaptureDeviceModel *deviceModel = dynamic_cast(model); if (deviceModel) { deviceModel->moveDown(deviceList->currentIndex()); updateButtonsEnabled(); emit changed(); } } } DevicePreference::DeviceType DevicePreference::shownModelType() const { const QStandardItem *item = m_categoryModel.itemFromIndex(categoryTree->currentIndex()); if (!item) return dtInvalidDevice; Q_ASSERT(item->type() == 1001); const CategoryItem *catItem = static_cast(item); if (!catItem) return dtInvalidDevice; switch (catItem->odtype()) { case AudioOutputDeviceType: return dtAudioOutput; case AudioCaptureDeviceType: return dtAudioCapture; case VideoCaptureDeviceType: return dtVideoCapture; default: return dtInvalidDevice; } } void DevicePreference::on_applyPreferencesButton_clicked() { const QModelIndex idx = categoryTree->currentIndex(); const QStandardItem *item = m_categoryModel.itemFromIndex(idx); if (!item) return; Q_ASSERT(item->type() == 1001); const CategoryItem *catItem = static_cast(item); QList aoPreferredList; QList acPreferredList; QList vcPreferredList; - const Category *categoryList = NULL; - const CaptureCategory *capCategoryList = NULL; + const Category *categoryList = nullptr; + const CaptureCategory *capCategoryList = nullptr; int categoryListCount; int catIndex; bool cap = false; switch (catItem->odtype()) { case AudioOutputDeviceType: aoPreferredList = m_audioOutputModel.value(catItem->category())->modelData(); categoryList = audioOutCategories; categoryListCount = audioOutCategoriesCount; cap = false; break; case AudioCaptureDeviceType: acPreferredList = m_audioCaptureModel.value(catItem->captureCategory())->modelData(); capCategoryList = audioCapCategories; categoryListCount = audioCapCategoriesCount; cap = true; break; case VideoCaptureDeviceType: vcPreferredList = m_videoCaptureModel.value(catItem->captureCategory())->modelData(); capCategoryList = videoCapCategories; categoryListCount = videoCapCategoriesCount; cap = true; break; default: return; } QPointer dialog = new QDialog(this); QLabel *label = new QLabel(dialog); label->setText(i18n("Apply the currently shown device preference list to the following other " "audio playback categories:")); label->setWordWrap(true); QListWidget *list = new QListWidget(dialog); for (catIndex = 0; catIndex < categoryListCount; catIndex ++) { Category cat = cap ? NoCategory : categoryList[catIndex]; CaptureCategory capcat = cap ? capCategoryList[catIndex] : NoCaptureCategory; QListWidgetItem *item = nullptr; if (cap) { if (capcat == NoCaptureCategory) { item = new QListWidgetItem(i18n("Default/Unspecified Category"), list, capcat); } else { item = new QListWidgetItem(categoryToString(capcat), list, capcat); } } else { if (cat == NoCategory) { item = new QListWidgetItem(i18n("Default/Unspecified Category"), list, cat); } else { item = new QListWidgetItem(categoryToString(cat), list, cat); } } item->setCheckState(Qt::Checked); if (cat == catItem->category()) { item->setFlags(item->flags() & ~Qt::ItemIsEnabled); } } QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog); connect(buttonBox, &QDialogButtonBox::accepted, dialog.data(), &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, dialog.data(), &QDialog::reject); QVBoxLayout *layout = new QVBoxLayout(dialog); layout->addWidget(label); layout->addWidget(list); layout->addWidget(buttonBox); switch (dialog->exec()) { case QDialog::Accepted: for (catIndex = 0; catIndex < categoryListCount; catIndex ++) { Category cat = cap ? NoCategory : categoryList[catIndex]; CaptureCategory capcat = cap ? capCategoryList[catIndex] : NoCaptureCategory; if (cap ? capcat != catItem->captureCategory() : cat != catItem->category()) { QListWidgetItem *item = list->item(catIndex); Q_ASSERT(item->type() == cap ? (int) capcat : (int) cat); if (item->checkState() == Qt::Checked) { switch (catItem->odtype()) { case AudioOutputDeviceType: m_audioOutputModel.value(cat)->setModelData(aoPreferredList); break; case AudioCaptureDeviceType: m_audioCaptureModel.value(capcat)->setModelData(acPreferredList); break; case VideoCaptureDeviceType: m_videoCaptureModel.value(capcat)->setModelData(vcPreferredList); break; default: ; } } } } emit changed(); break; case QDialog::Rejected: // nothing to do break; } delete dialog; } void DevicePreference::on_showAdvancedDevicesCheckBox_toggled() { // In order to get the right list from the backend, we need to update the settings now // before calling availableAudio{Output,Capture}Devices() GlobalConfig().setHideAdvancedDevices(!showAdvancedDevicesCheckBox->isChecked()); loadCategoryDevices(); } void DevicePreference::on_testPlaybackButton_toggled(bool down) { if (down) { QModelIndex idx = deviceList->currentIndex(); if (!idx.isValid()) { return; } // Shouldn't happen, but better to be on the safe side if (m_testingType != dtInvalidDevice) { delete m_media; m_media = nullptr; delete m_audioOutput; m_audioOutput = nullptr; delete m_videoWidget; m_videoWidget = nullptr; } // Setup the Phonon objects according to the testing type m_testingType = shownModelType(); switch (m_testingType) { case dtAudioOutput: { // Create an audio output with the selected device m_media = new MediaObject(this); const AudioOutputDeviceModel *model = static_cast(idx.model()); const AudioOutputDevice &device = model->modelData(idx); m_audioOutput = new AudioOutput(this); if (!m_audioOutput->setOutputDevice(device)) { KMessageBox::error(this, i18n("Failed to set the selected audio output device")); break; } // Just to be very sure that nothing messes our test sound up m_audioOutput->setVolume(1.0); m_audioOutput->setMuted(false); createPath(m_media, m_audioOutput); static QUrl testUrl = QUrl::fromLocalFile(QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("sounds/Oxygen-Sys-Log-In.ogg"))); m_media->setCurrentSource(testUrl); connect(m_media, &MediaObject::finished, testPlaybackButton, &QToolButton::toggle); break; } #ifndef PHONON_NO_AUDIOCAPTURE case dtAudioCapture: { // Create a media object and an audio output m_media = new MediaObject(this); m_audioOutput = new AudioOutput(NoCategory, this); // Just to be very sure that nothing messes our test sound up m_audioOutput->setVolume(1.0); m_audioOutput->setMuted(false); // Try to create a path if (!createPath(m_media, m_audioOutput).isValid()) { KMessageBox::error(this, i18n("Your backend may not support audio recording")); break; } // Determine the selected device const AudioCaptureDeviceModel *model = static_cast(idx.model()); const AudioCaptureDevice &device = model->modelData(idx); m_media->setCurrentSource(device); break; } #endif #ifndef PHONON_NO_VIDEOCAPTURE case dtVideoCapture: { // Create a media object and a video output m_media = new MediaObject(this); - m_videoWidget = new VideoWidget(NULL); + m_videoWidget = new VideoWidget(nullptr); // Try to create a path if (!createPath(m_media, m_videoWidget).isValid()) { KMessageBox::error(this, i18n("Your backend may not support video recording")); break; } // Determine the selected device const VideoCaptureDeviceModel *model = static_cast(idx.model()); const VideoCaptureDevice &device = model->modelData(idx); m_media->setCurrentSource(device); // Set up the testing video widget m_videoWidget->setWindowTitle(i18n("Testing %1", device.name())); m_videoWidget->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint); if (device.property("icon").canConvert(QVariant::String)) m_videoWidget->setWindowIcon(QIcon::fromTheme(device.property("icon").toString())); m_videoWidget->move(QCursor::pos() - QPoint(250, 295)); m_videoWidget->resize(320, 240); m_videoWidget->show(); break; } #endif default: return; } m_media->play(); } else { // Uninitialize the Phonon objects according to the testing type switch (m_testingType) { case dtAudioOutput: disconnect(m_media, &MediaObject::finished, testPlaybackButton, &QToolButton::toggle); delete m_media; delete m_audioOutput; break; case dtAudioCapture: delete m_media; delete m_audioOutput; break; case dtVideoCapture: delete m_media; delete m_videoWidget; break; default: return; } - m_media = NULL; - m_videoWidget = NULL; - m_audioOutput = NULL; + m_media = nullptr; + m_videoWidget = nullptr; + m_audioOutput = nullptr; m_testingType = dtInvalidDevice; } } void DevicePreference::updateButtonsEnabled() { if (deviceList->model()) { QModelIndex idx = deviceList->currentIndex(); preferButton->setEnabled(idx.isValid() && idx.row() > 0); deferButton->setEnabled(idx.isValid() && idx.row() < deviceList->model()->rowCount() - 1); testPlaybackButton->setEnabled(idx.isValid() && (idx.flags() & Qt::ItemIsEnabled)); } else { preferButton->setEnabled(false); deferButton->setEnabled(false); testPlaybackButton->setEnabled(false); } } } // Phonon namespace #include "moc_devicepreference.cpp" diff --git a/kcms/solid_actions/ActionEditor.cpp b/kcms/solid_actions/ActionEditor.cpp index cd8ef4dbc..10a3b54ce 100644 --- a/kcms/solid_actions/ActionEditor.cpp +++ b/kcms/solid_actions/ActionEditor.cpp @@ -1,192 +1,192 @@ /*************************************************************************** * 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 "ActionEditor.h" #include #include ActionEditor::ActionEditor(QWidget *parent) : QDialog(parent) { - topItem = new PredicateItem( Solid::Predicate(), 0 ); - rootItem = 0; + topItem = new PredicateItem( Solid::Predicate(), nullptr ); + rootItem = nullptr; rootModel = new PredicateModel( topItem, this ); // Prepare the dialog resize( QSize(600, 600) ); // Set a decent initial size // setModal( true ); // Set up the interface ui.setupUi(this); ui.TvPredicateTree->setHeaderHidden( true ); ui.TvPredicateTree->setModel( rootModel ); ui.IbActionIcon->setIconSize( KIconLoader::SizeLarge ); ui.CbDeviceType->addItems( actionData()->interfaceList() ); // Connect up with everything needed -> slot names explain connect(ui.TvPredicateTree, &QTreeView::activated, this, &ActionEditor::updateParameter); connect(ui.PbParameterSave, &QPushButton::clicked, this, &ActionEditor::saveParameter); connect(ui.PbParameterReset, &QPushButton::clicked, this, &ActionEditor::updateParameter); connect(ui.CbDeviceType, static_cast(&QComboBox::currentIndexChanged), this, &ActionEditor::updatePropertyList); connect(ui.CbParameterType, static_cast(&QComboBox::currentIndexChanged), this, &ActionEditor::manageControlStatus); connect(ui.buttonBox, &QDialogButtonBox::accepted, this, &ActionEditor::accept); connect(ui.buttonBox, &QDialogButtonBox::rejected, this, &ActionEditor::reject); if (ui.TvPredicateTree->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) { connect(ui.TvPredicateTree, &QTreeView::clicked, this, &ActionEditor::updateParameter); } } ActionEditor::~ActionEditor() { delete topItem; } void ActionEditor::setActionToEdit( ActionItem * item ) { activeItem = item; // Set all the text appropriately ui.IbActionIcon->setIcon( item->icon() ); ui.LeActionFriendlyName->setText( item->name() ); ui.LeActionCommand->setText(item->exec()); setPredicate( item->predicate() ); setWindowTitle(i18n("Editing Action '%1'", item->name()) ); // Set a friendly i18n caption } void ActionEditor::setPredicate( Solid::Predicate predicate ) { delete topItem; - topItem = new PredicateItem( Solid::Predicate(), 0 ); + topItem = new PredicateItem( Solid::Predicate(), nullptr ); rootItem = new PredicateItem( predicate, topItem ); rootModel->setRootPredicate( rootItem->parent() ); // Select the top item, not the hidden root QModelIndex topItem = rootModel->index( 0, 0, QModelIndex() ); ui.TvPredicateTree->setCurrentIndex( topItem ); ui.TvPredicateTree->expandToDepth( 2 ); updateParameter(); } void ActionEditor::updateParameter() { QModelIndex current = ui.TvPredicateTree->currentIndex(); PredicateItem * currentItem = static_cast( current.internalPointer() ); ui.CbParameterType->setCurrentIndex( currentItem->itemType ); updatePropertyList(); ui.CbDeviceType->setCurrentIndex( actionData()->interfacePosition( currentItem->ifaceType ) ); int valuePos = actionData()->propertyPosition( currentItem->ifaceType, currentItem->property ); ui.CbValueName->setCurrentIndex( valuePos ); ui.LeValueMatch->setText( currentItem->value.toString() ); ui.CbValueMatch->setCurrentIndex( currentItem->compOperator ); } void ActionEditor::saveParameter() { QModelIndex current = ui.TvPredicateTree->currentIndex(); PredicateItem * currentItem = static_cast( current.internalPointer() ); // Hold onto this so we can determine if the number of children has changed... Solid::Predicate::Type oldType = currentItem->itemType; currentItem->setTypeByInt( ui.CbParameterType->currentIndex() ); currentItem->ifaceType = actionData()->interfaceFromName( ui.CbDeviceType->currentText() ); currentItem->property = actionData()->propertyInternal( currentItem->ifaceType, ui.CbValueName->currentText() ); currentItem->value = QVariant( ui.LeValueMatch->text() ); currentItem->setComparisonByInt( ui.CbValueMatch->currentIndex() ); rootModel->itemUpdated( current ); rootModel->childrenChanging( current, oldType ); } QString ActionEditor::predicateString() { return rootItem->predicate().toString(); } void ActionEditor::updatePropertyList() { Solid::DeviceInterface::Type currentType; currentType = actionData()->interfaceFromName( ui.CbDeviceType->currentText() ); ui.CbValueName->clear(); ui.CbValueName->addItems( actionData()->propertyList( currentType ) ); } void ActionEditor::manageControlStatus() { bool atomEnable = false; bool isEnable = false; switch( ui.CbParameterType->currentIndex() ) { case Solid::Predicate::PropertyCheck: atomEnable = true; case Solid::Predicate::InterfaceCheck: isEnable = true; break; default: break; } ui.CbDeviceType->setEnabled( isEnable ); ui.CbValueName->setEnabled( atomEnable ); ui.CbValueMatch->setEnabled( atomEnable ); ui.LeValueMatch->setEnabled( atomEnable ); } SolidActionData * ActionEditor::actionData() { return SolidActionData::instance(); } void ActionEditor::accept() { // Save any open parameter changes first... saveParameter(); // Read the data and prepare to save QString iconName = ui.IbActionIcon->icon(); QString actionName = ui.LeActionFriendlyName->text(); QString command = ui.LeActionCommand->text(); QString predicate = predicateString(); // We need to ensure that they are all valid before applying if (iconName.isEmpty() || actionName.isEmpty() || command.isEmpty() || !Solid::Predicate::fromString(predicate).isValid()) { KMessageBox::error(this, i18n("It appears that the action name, command, icon or condition are not valid.\nTherefore, changes will not be applied."), i18n("Invalid action")); return; } // apply the changes if (iconName != activeItem->icon()) { // Has the icon changed? activeItem->setIcon( ui.IbActionIcon->icon() ); // Write the change } if (actionName != activeItem->name()) { // Has the friendly name changed? activeItem->setName( ui.LeActionFriendlyName->text() ); // Write the change } if (command != activeItem->exec()) { // Has the command changed? activeItem->setExec( ui.LeActionCommand->text() ); // Write the change } if (predicate != activeItem->predicate().toString() ) { // Has it changed? activeItem->setPredicate( predicate ); // Write the change } QDialog::accept(); } diff --git a/kcms/solid_actions/PredicateModel.cpp b/kcms/solid_actions/PredicateModel.cpp index 9c59e763d..151f71c05 100644 --- a/kcms/solid_actions/PredicateModel.cpp +++ b/kcms/solid_actions/PredicateModel.cpp @@ -1,176 +1,176 @@ /************************************************************************** * Copyright (C) 2009 Ben Cooksley * * Copyright (C) 2007 Will Stephenson * * * * 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 "PredicateModel.h" #include "PredicateItem.h" class PredicateModel::Private { public: Private() {} PredicateItem * rootItem; }; PredicateModel::PredicateModel( PredicateItem * menuRoot, QObject *parent ) : QAbstractItemModel( parent ) , d( new Private() ) { d->rootItem = menuRoot; } PredicateModel::~PredicateModel() { delete d; } int PredicateModel::columnCount( const QModelIndex &parent ) const { Q_UNUSED( parent ); return 1; } int PredicateModel::rowCount( const QModelIndex &parent ) const { PredicateItem * mi; if ( parent.isValid() ) { mi = static_cast( parent.internalPointer() ); } else { mi = d->rootItem; } return mi->children().count(); } QVariant PredicateModel::data( const QModelIndex &index, int role ) const { - PredicateItem * mi = 0; + PredicateItem * mi = nullptr; QVariant theData; if ( !index.isValid() ) { return QVariant(); } mi = static_cast( index.internalPointer() ); switch ( role ) { case Qt::DisplayRole: theData.setValue( mi->prettyName() ); break; case Qt::UserRole: theData.setValue( mi ); break; default: break; } return theData; } Qt::ItemFlags PredicateModel::flags( const QModelIndex &index ) const { if ( !index.isValid() ) { - return 0; + return nullptr; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QModelIndex PredicateModel::index( int row, int column, const QModelIndex &parent ) const { if ( !hasIndex(row, column, parent) ) { return QModelIndex(); } PredicateItem *parentItem; if ( !parent.isValid() ) { parentItem = d->rootItem; } else { parentItem = static_cast( parent.internalPointer() ); } PredicateItem *childItem = parentItem->children().value(row); if ( childItem ) { return createIndex( row, column, childItem ); } else { return QModelIndex(); } } QModelIndex PredicateModel::parent( const QModelIndex &index ) const { PredicateItem *childItem = static_cast( index.internalPointer() ); if( !childItem ) { return QModelIndex(); } PredicateItem * parent = childItem->parent(); PredicateItem * grandParent = parent->parent(); int childRow = 0; if( grandParent ) { childRow = grandParent->children().indexOf( parent ); } if ( parent == d->rootItem ) { return QModelIndex(); } return createIndex( childRow, 0, parent ); } PredicateItem * PredicateModel::rootItem() const { return d->rootItem; } void PredicateModel::setRootPredicate( PredicateItem * item ) { beginResetModel(); d->rootItem = item; endResetModel(); } void PredicateModel::itemUpdated( const QModelIndex& item ) { emit dataChanged( item, item ); } void PredicateModel::childrenChanging( const QModelIndex& item, Solid::Predicate::Type oldType ) { PredicateItem * currentItem = static_cast( item.internalPointer() ); Solid::Predicate::Type newType = currentItem->itemType; if( oldType == newType ) { return; } if( rowCount(item) != 0 && newType != Solid::Predicate::Conjunction && newType != Solid::Predicate::Disjunction ) { emit beginRemoveRows( item, 0, 1 ); currentItem->updateChildrenStatus(); emit endRemoveRows(); return; } bool hasChildren = (newType == Solid::Predicate::Conjunction || newType == Solid::Predicate::Disjunction); if( rowCount(item) == 0 && hasChildren ) { emit beginInsertRows( item, 0, 1 ); currentItem->updateChildrenStatus(); emit endInsertRows(); } } diff --git a/kcms/solid_actions/SolidActionData.cpp b/kcms/solid_actions/SolidActionData.cpp index 3aadcf688..d14a8f2c0 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 = 0; +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 = KStringHandler::capwords( finalString ); // Capitalize everything return finalString.trimmed(); } SolidActionData * SolidActionData::instance() { - if( actData == 0 ) { + 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; } diff --git a/kcms/standard_actions/standard_actions_module.cpp b/kcms/standard_actions/standard_actions_module.cpp index 020927298..6ecdce5be 100644 --- a/kcms/standard_actions/standard_actions_module.cpp +++ b/kcms/standard_actions/standard_actions_module.cpp @@ -1,163 +1,163 @@ /* * Copyright 2008 Michael Jansen * * 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 "standard_actions_module.h" #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(StandardActionsModuleFactory, registerPlugin();) K_EXPORT_PLUGIN(StandardActionsModuleFactory("kcm_standard_actions")) static void dressUpAction(QAction *action, KStandardShortcut::StandardShortcut shortcutId) { // Remember the shortcutId so we know where to save changes. action->setData(shortcutId); // We have to manually adjust the action. We want to show the // hardcoded default and the user set shortcut. But action currently // only contain the active shortcuts as default shortcut. So we // have to fill it correctly const auto hardcoded = KStandardShortcut::hardcodedDefaultShortcut(shortcutId); const auto active = KStandardShortcut::shortcut(shortcutId); // Set the hardcoded default shortcut as default shortcut action->setProperty("defaultShortcuts", QVariant::fromValue(hardcoded)); action->setShortcuts(active); } StandardActionsModule::StandardActionsModule( QWidget *parent, const QVariantList &args ) : KCModule(parent, args ) - ,m_editor(NULL) - ,m_actionCollection(NULL) + ,m_editor(nullptr) + ,m_actionCollection(nullptr) { KAboutData *about = new KAboutData(QStringLiteral("kcm_standard_actions"), i18n("Standard Shortcuts"), QStringLiteral("0.1"), QString(), KAboutLicense::GPL); setAboutData(about); // Configure the KCM KCModule::setButtons(KCModule::Buttons(KCModule::Default | KCModule::Apply | KCModule::Help)); // Create and configure the editor m_editor = new KShortcutsEditor(this, KShortcutsEditor::WidgetAction | KShortcutsEditor::WindowAction | KShortcutsEditor::ApplicationAction); // there will be no global actions, so make sure that column is hidden connect(m_editor, &KShortcutsEditor::keyChange, this, &StandardActionsModule::keyChanged); // Make a layout QVBoxLayout *global = new QVBoxLayout; global->addWidget(m_editor); setLayout(global); } StandardActionsModule::~StandardActionsModule() {} void StandardActionsModule::defaults() { m_editor->allDefault(); } void StandardActionsModule::keyChanged() { emit changed(true); } void StandardActionsModule::load() { // Create a collection to handle the shortcuts m_actionCollection = new KActionCollection( this, QStringLiteral("kcm_standard_actions")); // Keeps track of which shortcut IDs have been added QSet shortcutIdsAdded; // Put all shortcuts for standard actions into the collection Q_FOREACH(KStandardAction::StandardAction id, KStandardAction::actionIds()) { KStandardShortcut::StandardShortcut shortcutId = KStandardAction::shortcutForActionId(id); // If the StandardShortcutId is AccelNone skip configuration for this // action. if (shortcutId == KStandardShortcut::AccelNone || shortcutIdsAdded.contains(shortcutId)) { continue; } // Create the action - QAction *action = KStandardAction::create(id, NULL, NULL, m_actionCollection); + QAction *action = KStandardAction::create(id, nullptr, nullptr, m_actionCollection); dressUpAction(action, shortcutId); shortcutIdsAdded << shortcutId; } // Put in the remaining standard shortcuts too... for(int i = int(KStandardShortcut::AccelNone) + 1; i < KStandardShortcut::StandardShortcutCount; ++i) { KStandardShortcut::StandardShortcut shortcutId = static_cast(i); if(!shortcutIdsAdded.contains(shortcutId)) { QAction *action = new QAction(KStandardShortcut::label(shortcutId), this); action->setWhatsThis(KStandardShortcut::whatsThis(shortcutId)); dressUpAction(action, shortcutId); m_actionCollection->addAction(KStandardShortcut::name(shortcutId), action); } } // Hand the collection to the editor m_editor->addCollection(m_actionCollection, i18n("Standard Shortcuts")); } void StandardActionsModule::save() { m_editor->commit(); Q_FOREACH(QAction* action, m_actionCollection->actions()) { KStandardShortcut::saveShortcut( static_cast(action->data().toInt()) , action->shortcuts()); } KSharedConfig::openConfig()->sync(); KConfigGroup cg(KSharedConfig::openConfig(), "Shortcuts"); cg.sync(); QString title = i18n("Standard Actions successfully saved"); QString message = i18n( "The changes have been saved. Please note that:" "
    • Applications need to be restarted to see the changes.
    • " "
    • This change could introduce shortcut conflicts in some applications.
    • " "
    " ); KMessageBox::information(this, message, title, QStringLiteral("shortcuts_saved_info")); } #include "standard_actions_module.moc" diff --git a/kcms/style/kcmstyle.cpp b/kcms/style/kcmstyle.cpp index edc00c427..518af5509 100644 --- a/kcms/style/kcmstyle.cpp +++ b/kcms/style/kcmstyle.cpp @@ -1,753 +1,753 @@ /* * KCMStyle * Copyright (C) 2002 Karol Szwed * Copyright (C) 2002 Daniel Molkentin * Copyright (C) 2007 Urs Wolfer * Copyright (C) 2009 by Davide Bettio * Portions Copyright (C) 2007 Paolo Capriotti * Portions Copyright (C) 2007 Ivan Cukic * Portions Copyright (C) 2008 by Petri Damsten * Portions Copyright (C) 2000 TrollTech AS. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kcmstyle.h" #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) #include #endif #include "styleconfdialog.h" #include "ui_stylepreview.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 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) #include #endif #include "../krdb/krdb.h" #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) #include #endif // X11 namespace cleanup #undef Bool #undef Below #undef KeyPress #undef KeyRelease /**** DLL Interface for kcontrol ****/ #include #include #include K_PLUGIN_FACTORY(KCMStyleFactory, registerPlugin();) K_EXPORT_PLUGIN(KCMStyleFactory("kcmstyle")) extern "C" { Q_DECL_EXPORT void kcminit_style() { uint flags = KRdbExportQtSettings | KRdbExportQtColors | KRdbExportXftSettings | KRdbExportGtkTheme; KConfig _config( QStringLiteral("kcmdisplayrc"), KConfig::NoGlobals ); KConfigGroup config(&_config, "X11"); // This key is written by the "colors" module. bool exportKDEColors = config.readEntry("exportKDEColors", true); if (exportKDEColors) flags |= KRdbExportColors; runRdb( flags ); } } class StylePreview : public QWidget, public Ui::StylePreview { public: StylePreview(QWidget *parent = nullptr) : QWidget(parent) { setupUi(this); // Ensure that the user can't toy with the child widgets. // Method borrowed from Qt's qtconfig. QList widgets = findChildren(); foreach (QWidget* widget, widgets) { widget->installEventFilter(this); widget->setFocusPolicy(Qt::NoFocus); } } bool eventFilter( QObject* /* obj */, QEvent* ev ) override { switch( ev->type() ) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: case QEvent::KeyPress: case QEvent::KeyRelease: case QEvent::Enter: case QEvent::Leave: case QEvent::Wheel: case QEvent::ContextMenu: return true; // ignore default: break; } return false; } }; QString KCMStyle::defaultStyle() { #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) return QStringLiteral("breeze"); #else return QString(); // native style #endif } KCMStyle::KCMStyle( QWidget* parent, const QVariantList& ) - : KCModule( parent ), appliedStyle(NULL) + : KCModule( parent ), appliedStyle(nullptr) { setQuickHelp( i18n("

    Style

    " "This module allows you to modify the visual appearance " "of user interface elements, such as the widget style " "and effects.")); m_bStyleDirty= false; m_bEffectsDirty = false; KGlobal::dirs()->addResourceType("themes", "data", "kstyle/themes"); KAboutData *about = new KAboutData( QStringLiteral("kcmstyle"), i18n("KDE Style Module"), QStringLiteral("1.0"), QString(), KAboutLicense::GPL, i18n("(c) 2002 Karol Szwed, Daniel Molkentin")); about->addAuthor(i18n("Karol Szwed"), QString(), QStringLiteral("gallium@kde.org")); about->addAuthor(i18n("Daniel Molkentin"), QString(), QStringLiteral("molkentin@kde.org")); setAboutData( about ); // Setup pages and mainLayout mainLayout = new QVBoxLayout( this ); mainLayout->setMargin(0); tabWidget = new QTabWidget( this ); mainLayout->addWidget( tabWidget ); // Add Page1 (Applications Style) // ----------------- //gbWidgetStyle = new QGroupBox( i18n("Widget Style"), page1 ); page1 = new QWidget; page1Layout = new QVBoxLayout( page1 ); QWidget* gbWidgetStyle = new QWidget( page1 ); QVBoxLayout *widgetLayout = new QVBoxLayout(gbWidgetStyle); gbWidgetStyleLayout = new QVBoxLayout; widgetLayout->addLayout( gbWidgetStyleLayout ); gbWidgetStyleLayout->setAlignment( Qt::AlignTop ); hbLayout = new QHBoxLayout( ); hbLayout->setObjectName( QStringLiteral("hbLayout") ); QLabel* label=new QLabel(i18n("Widget style:"),this); hbLayout->addWidget( label ); cbStyle = new KComboBox( gbWidgetStyle ); cbStyle->setObjectName( QStringLiteral("cbStyle") ); cbStyle->setEditable( false ); hbLayout->addWidget( cbStyle ); hbLayout->setStretchFactor( cbStyle, 1 ); label->setBuddy(cbStyle); pbConfigStyle = new QPushButton( QIcon::fromTheme(QStringLiteral("configure")), i18n("Con&figure..."), gbWidgetStyle ); pbConfigStyle->setEnabled( false ); hbLayout->addWidget( pbConfigStyle ); gbWidgetStyleLayout->addLayout( hbLayout ); lblStyleDesc = new QLabel( gbWidgetStyle ); gbWidgetStyleLayout->addWidget( lblStyleDesc ); QGroupBox *gbPreview = new QGroupBox( i18n( "Preview" ), page1 ); QVBoxLayout *previewLayout = new QVBoxLayout(gbPreview); previewLayout->setMargin( 0 ); stylePreview = new StylePreview( gbPreview ); gbPreview->layout()->addWidget( stylePreview ); page1Layout->addWidget( gbWidgetStyle ); page1Layout->addWidget( gbPreview ); page1Layout->addStretch(); connect( cbStyle, SIGNAL(activated(int)), this, SLOT(styleChanged()) ); connect( cbStyle, SIGNAL(activated(int)), this, SLOT(updateConfigButton())); connect( pbConfigStyle, &QAbstractButton::clicked, this, &KCMStyle::styleSpecificConfig); // Add Page2 (Effects) // ------------------- page2 = new QWidget; fineTuningUi.setupUi(page2); connect(cbStyle, SIGNAL(activated(int)), this, SLOT(setStyleDirty())); connect(fineTuningUi.cbIconsOnButtons, &QAbstractButton::toggled, this, &KCMStyle::setEffectsDirty); connect(fineTuningUi.cbIconsInMenus, &QAbstractButton::toggled, this, &KCMStyle::setEffectsDirty); connect(fineTuningUi.comboToolbarIcons, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); connect(fineTuningUi.comboSecondaryToolbarIcons, SIGNAL(activated(int)), this, SLOT(setEffectsDirty())); addWhatsThis(); // Insert the pages into the tabWidget tabWidget->addTab(page1, i18nc("@title:tab", "&Applications")); tabWidget->addTab(page2, i18nc("@title:tab", "&Fine Tuning")); } KCMStyle::~KCMStyle() { qDeleteAll(styleEntries); delete appliedStyle; } void KCMStyle::updateConfigButton() { if (!styleEntries[currentStyle()] || styleEntries[currentStyle()]->configPage.isEmpty()) { pbConfigStyle->setEnabled(false); return; } // We don't check whether it's loadable here - // lets us report an error and not waste time // loading things if the user doesn't click the button pbConfigStyle->setEnabled( true ); } void KCMStyle::styleSpecificConfig() { QString libname = styleEntries[currentStyle()]->configPage; KLibrary library(libname); if (!library.load()) { KMessageBox::detailedError(this, i18n("There was an error loading the configuration dialog for this style."), library.errorString(), i18n("Unable to Load Dialog")); return; } KLibrary::void_function_ptr allocPtr = library.resolveFunction("allocate_kstyle_config"); if (!allocPtr) { KMessageBox::detailedError(this, i18n("There was an error loading the configuration dialog for this style."), library.errorString(), i18n("Unable to Load Dialog")); return; } //Create the container dialog StyleConfigDialog* dial = new StyleConfigDialog(this, styleEntries[currentStyle()]->name); typedef QWidget*(* factoryRoutine)( QWidget* parent ); //Get the factory, and make the widget. factoryRoutine factory = (factoryRoutine)(allocPtr); //Grmbl. So here I am on my //"never use C casts" moralizing streak, and I find that one can't go void* -> function ptr //even with a reinterpret_cast. QWidget* pluginConfig = factory( dial ); //Insert it in... dial->setMainWidget( pluginConfig ); //..and connect it to the wrapper connect(pluginConfig, SIGNAL(changed(bool)), dial, SLOT(setDirty(bool))); connect(dial, SIGNAL(defaults()), pluginConfig, SLOT(defaults())); connect(dial, SIGNAL(save()), pluginConfig, SLOT(save())); if (dial->exec() == QDialog::Accepted && dial->isDirty() ) { // Force re-rendering of the preview, to apply settings switchStyle(currentStyle(), true); //For now, ask all KDE apps to recreate their styles to apply the setitngs KGlobalSettings::self()->emitChange(KGlobalSettings::StyleChanged); // We call setStyleDirty here to make sure we force style re-creation setStyleDirty(); } delete dial; } void KCMStyle::changeEvent( QEvent *event ) { KCModule::changeEvent( event ); if ( event->type() == QEvent::PaletteChange ) { // Force re-rendering of the preview, to apply new palette switchStyle(currentStyle(), true); } } void KCMStyle::load() { KConfig config( QStringLiteral("kdeglobals"), KConfig::FullConfig ); loadStyle( config ); loadEffects( config ); m_bStyleDirty= false; m_bEffectsDirty = false; //Enable/disable the button for the initial style updateConfigButton(); emit changed( false ); } void KCMStyle::save() { // Don't do anything if we don't need to. if ( !(m_bStyleDirty | m_bEffectsDirty ) ) return; // Save effects. KConfig _config(QStringLiteral("kdeglobals"), KConfig::NoGlobals); KConfigGroup config(&_config, "KDE"); // Effects page config.writeEntry( "ShowIconsOnPushButtons", fineTuningUi.cbIconsOnButtons->isChecked()); config.writeEntry( "ShowIconsInMenuItems", fineTuningUi.cbIconsInMenus->isChecked()); config.writeEntry("widgetStyle", currentStyle()); KConfigGroup toolbarStyleGroup(&_config, "Toolbar style"); toolbarStyleGroup.writeEntry("ToolButtonStyle", toolbarButtonText(fineTuningUi.comboToolbarIcons->currentIndex())); toolbarStyleGroup.writeEntry("ToolButtonStyleOtherToolbars", toolbarButtonText(fineTuningUi.comboSecondaryToolbarIcons->currentIndex())); _config.sync(); // Export the changes we made to qtrc, and update all qt-only // applications on the fly, ensuring that we still follow the user's // export fonts/colors settings. if (m_bStyleDirty || m_bEffectsDirty) // Export only if necessary { uint flags = KRdbExportQtSettings | KRdbExportGtkTheme; KConfig _kconfig( QStringLiteral("kcmdisplayrc"), KConfig::NoGlobals ); KConfigGroup kconfig(&_kconfig, "X11"); bool exportKDEColors = kconfig.readEntry("exportKDEColors", true); if (exportKDEColors) flags |= KRdbExportColors; runRdb( flags ); } // Now allow KDE apps to reconfigure themselves. if ( m_bStyleDirty ) KGlobalSettings::self()->emitChange(KGlobalSettings::StyleChanged); if ( m_bEffectsDirty ) { KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_STYLE); // ##### FIXME - Doesn't apply all settings correctly due to bugs in // KApplication/KToolbar KGlobalSettings::self()->emitChange(KGlobalSettings::ToolbarStyleChanged); #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig")); QDBusConnection::sessionBus().send(message); #endif } // Clean up m_bStyleDirty = false; m_bEffectsDirty = false; emit changed( false ); } bool KCMStyle::findStyle( const QString& str, int& combobox_item ) { StyleEntry* se = styleEntries[str.toLower()]; QString name = se ? se->name : str; combobox_item = 0; //look up name for( int i = 0; i < cbStyle->count(); i++ ) { if ( cbStyle->itemText(i) == name ) { combobox_item = i; return true; } } return false; } void KCMStyle::defaults() { // Select default style int item = 0; bool found; found = findStyle( defaultStyle(), item ); if (!found) found = findStyle( QStringLiteral("oxygen"), item ); if (!found) found = findStyle( QStringLiteral("plastique"), item ); if (!found) found = findStyle( QStringLiteral("windows"), item ); if (!found) found = findStyle( QStringLiteral("platinum"), item ); if (!found) found = findStyle( QStringLiteral("motif"), item ); cbStyle->setCurrentIndex( item ); m_bStyleDirty = true; switchStyle( currentStyle() ); // make resets visible // Effects fineTuningUi.comboToolbarIcons->setCurrentIndex(toolbarButtonIndex(QStringLiteral("TextBesideIcon"))); fineTuningUi.comboSecondaryToolbarIcons->setCurrentIndex(toolbarButtonIndex(QStringLiteral("TextBesideIcon"))); fineTuningUi.cbIconsOnButtons->setChecked(true); fineTuningUi.cbIconsInMenus->setChecked(true); emit changed(true); } void KCMStyle::setEffectsDirty() { m_bEffectsDirty = true; emit changed(true); } void KCMStyle::setStyleDirty() { m_bStyleDirty = true; emit changed(true); } // ---------------------------------------------------------------- // All the Style Switching / Preview stuff // ---------------------------------------------------------------- void KCMStyle::loadStyle( KConfig& config ) { cbStyle->clear(); // Create a dictionary of WidgetStyle to Name and Desc. mappings, // as well as the config page info qDeleteAll(styleEntries); styleEntries.clear(); QString strWidgetStyle; QStringList list = KGlobal::dirs()->findAllResources("themes", QStringLiteral("*.themerc"), KStandardDirs::Recursive | KStandardDirs::NoDuplicates); for (QStringList::iterator it = list.begin(); it != list.end(); ++it) { KConfig config( *it, KConfig::SimpleConfig); if ( !(config.hasGroup("KDE") && config.hasGroup("Misc")) ) continue; KConfigGroup configGroup = config.group("KDE"); strWidgetStyle = configGroup.readEntry("WidgetStyle"); if (strWidgetStyle.isNull()) continue; // We have a widgetstyle, so lets read the i18n entries for it... StyleEntry* entry = new StyleEntry; configGroup = config.group("Misc"); entry->name = configGroup.readEntry("Name"); entry->desc = configGroup.readEntry("Comment", i18n("No description available.")); entry->configPage = configGroup.readEntry("ConfigPage", QString()); // Check if this style should be shown configGroup = config.group("Desktop Entry"); entry->hidden = configGroup.readEntry("Hidden", false); // Insert the entry into our dictionary. styleEntries.insert(strWidgetStyle.toLower(), entry); } // Obtain all style names QStringList allStyles = QStyleFactory::keys(); // Get translated names, remove all hidden style entries. QStringList styles; StyleEntry* entry; for (QStringList::iterator it = allStyles.begin(); it != allStyles.end(); ++it) { QString id = (*it).toLower(); // Find the entry. - if ( (entry = styleEntries[id]) != 0 ) + if ( (entry = styleEntries[id]) != nullptr ) { // Do not add hidden entries if (entry->hidden) continue; styles += entry->name; nameToStyleKey[entry->name] = id; } else { styles += (*it); //Fall back to the key (but in original case) nameToStyleKey[*it] = id; } } // Sort the style list, and add it to the combobox styles.sort(); cbStyle->addItems( styles ); // Find out which style is currently being used KConfigGroup configGroup = config.group( "KDE" ); QString defaultStyle = KCMStyle::defaultStyle(); QString cfgStyle = configGroup.readEntry( "widgetStyle", defaultStyle ); // Select the current style // Do not use cbStyle->listBox() as this may be NULL for some styles when // they use QPopupMenus for the drop-down list! // ##### Since Trolltech likes to seemingly copy & paste code, // QStringList::findItem() doesn't have a Qt::StringComparisonMode field. // We roll our own (yuck) cfgStyle = cfgStyle.toLower(); int item = 0; for( int i = 0; i < cbStyle->count(); i++ ) { QString id = nameToStyleKey[cbStyle->itemText(i)]; item = i; if ( id == cfgStyle ) // ExactMatch break; else if ( id.contains( cfgStyle ) ) break; else if ( id.contains( QApplication::style()->metaObject()->className() ) ) break; item = 0; } cbStyle->setCurrentIndex( item ); m_bStyleDirty = false; switchStyle( currentStyle() ); // make resets visible } QString KCMStyle::currentStyle() { return nameToStyleKey[cbStyle->currentText()]; } void KCMStyle::styleChanged() { switchStyle( currentStyle() ); } void KCMStyle::switchStyle(const QString& styleName, bool force) { // Don't flicker the preview if the same style is chosen in the cb if (!force && appliedStyle && appliedStyle->objectName() == styleName) return; // Create an instance of the new style... QStyle* style = QStyleFactory::create(styleName); if (!style) return; // Prevent Qt from wrongly caching radio button images QPixmapCache::clear(); setStyleRecursive( stylePreview, style ); // this flickers, but reliably draws the widgets correctly. stylePreview->resize( stylePreview->sizeHint() ); delete appliedStyle; appliedStyle = style; // Set the correct style description StyleEntry* entry = styleEntries[ styleName ]; QString desc; desc = i18n("Description: %1", entry ? entry->desc : i18n("No description available.") ); lblStyleDesc->setText( desc ); } void KCMStyle::setStyleRecursive(QWidget* w, QStyle* s) { // Don't let broken styles kill the palette // for other styles being previewed. (e.g SGI style) w->setPalette(QPalette()); QPalette newPalette(KGlobalSettings::createApplicationPalette()); s->polish( newPalette ); w->setPalette(newPalette); // Apply the new style. w->setStyle(s); // Recursively update all children. const QObjectList children = w->children(); // Apply the style to each child widget. foreach (QObject* child, children) { if (child->isWidgetType()) setStyleRecursive((QWidget *) child, s); } } // ---------------------------------------------------------------- // All the Effects stuff // ---------------------------------------------------------------- QString KCMStyle::toolbarButtonText(int index) { switch (index) { case 1: return QStringLiteral("TextOnly"); case 2: return QStringLiteral("TextBesideIcon"); case 3: return QStringLiteral("TextUnderIcon"); default: break; } return QStringLiteral("NoText"); } int KCMStyle::toolbarButtonIndex(const QString &text) { if (text == QLatin1String("TextOnly")) { return 1; } else if (text == QLatin1String("TextBesideIcon")) { return 2; } else if (text == QLatin1String("TextUnderIcon")) { return 3; } return 0; } QString KCMStyle::menuBarStyleText(int index) { switch (index) { case 1: return QStringLiteral("Decoration"); case 2: return QStringLiteral("Widget"); } return QStringLiteral("InApplication"); } int KCMStyle::menuBarStyleIndex(const QString &text) { if (text == QLatin1String("Decoration")) { return 1; } else if (text == QLatin1String("Widget")) { return 2; } return 0; } void KCMStyle::loadEffects( KConfig& config ) { // KDE's Part via KConfig KConfigGroup configGroup = config.group("Toolbar style"); QString tbIcon = configGroup.readEntry("ToolButtonStyle", "TextBesideIcon"); fineTuningUi.comboToolbarIcons->setCurrentIndex(toolbarButtonIndex(tbIcon)); tbIcon = configGroup.readEntry("ToolButtonStyleOtherToolbars", "TextBesideIcon"); fineTuningUi.comboSecondaryToolbarIcons->setCurrentIndex(toolbarButtonIndex(tbIcon)); configGroup = config.group("KDE"); fineTuningUi.cbIconsOnButtons->setChecked(configGroup.readEntry("ShowIconsOnPushButtons", true)); fineTuningUi.cbIconsInMenus->setChecked(configGroup.readEntry("ShowIconsInMenuItems", true)); m_bEffectsDirty = false; } void KCMStyle::addWhatsThis() { // Page1 cbStyle->setWhatsThis( i18n("Here you can choose from a list of" " predefined widget styles (e.g. the way buttons are drawn) which" " may or may not be combined with a theme (additional information" " like a marble texture or a gradient).") ); stylePreview->setWhatsThis( i18n("This area shows a preview of the currently selected style " "without having to apply it to the whole desktop.") ); // Page2 page2->setWhatsThis( i18n("This page allows you to choose details about the widget style options") ); fineTuningUi.comboToolbarIcons->setWhatsThis( i18n( "

    No Text: Shows only icons on toolbar buttons. " "Best option for low resolutions.

    " "

    Text Only: Shows only text on toolbar buttons.

    " "

    Text Beside Icons: Shows icons and text on toolbar buttons. " "Text is aligned beside the icon.

    " "Text Below Icons: Shows icons and text on toolbar buttons. " "Text is aligned below the icon.") ); fineTuningUi.cbIconsOnButtons->setWhatsThis( i18n( "If you enable this option, KDE Applications will " "show small icons alongside some important buttons.") ); fineTuningUi.cbIconsInMenus->setWhatsThis( i18n( "If you enable this option, KDE Applications will " "show small icons alongside most menu items.") ); } #include "kcmstyle.moc" // vim: set noet ts=4: