diff --git a/applets/taskmanager/plugin/backend.cpp b/applets/taskmanager/plugin/backend.cpp index d8cc4eafa..ea972e9d9 100644 --- a/applets/taskmanager/plugin/backend.cpp +++ b/applets/taskmanager/plugin/backend.cpp @@ -1,588 +1,588 @@ /*************************************************************************** * Copyright (C) 2012-2016 by Eike Hein * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "backend.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KAStats = KActivities::Stats; using namespace KAStats; using namespace KAStats::Terms; Backend::Backend(QObject* parent) : QObject(parent) , m_panelWinId(0) , m_highlightWindows(false) , m_actionGroup(new QActionGroup(this)) { } Backend::~Backend() { } QQuickItem *Backend::taskManagerItem() const { return m_taskManagerItem; } void Backend::setTaskManagerItem(QQuickItem* item) { if (item != m_taskManagerItem) { m_taskManagerItem = item; emit taskManagerItemChanged(); } } QQuickItem *Backend::toolTipItem() const { return m_toolTipItem; } void Backend::setToolTipItem(QQuickItem *item) { if (item != m_toolTipItem) { m_toolTipItem = item; - connect(item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(toolTipWindowChanged(QQuickWindow*))); + connect(item, &QQuickItem::windowChanged, this, &Backend::toolTipWindowChanged); emit toolTipItemChanged(); } } QQuickWindow *Backend::groupDialog() const { return m_groupDialog; } void Backend::setGroupDialog(QQuickWindow *dialog) { if (dialog != m_groupDialog) { m_groupDialog = dialog; emit groupDialogChanged(); } } bool Backend::highlightWindows() const { return m_highlightWindows; } void Backend::setHighlightWindows(bool highlight) { if (highlight != m_highlightWindows) { m_highlightWindows = highlight; updateWindowHighlight(); emit highlightWindowsChanged(); } } QUrl Backend::tryDecodeApplicationsUrl(const QUrl &launcherUrl) { if (launcherUrl.isValid() && launcherUrl.scheme() == QLatin1String("applications")) { const KService::Ptr service = KService::serviceByMenuId(launcherUrl.path()); if (service) { return QUrl::fromLocalFile(service->entryPath()); } } return launcherUrl; } QVariantList Backend::jumpListActions(const QUrl &launcherUrl, QObject *parent) { if (!parent) { return QVariantList(); } QUrl desktopEntryUrl = tryDecodeApplicationsUrl(launcherUrl); if (!desktopEntryUrl.isValid() || !desktopEntryUrl.isLocalFile() || !KDesktopFile::isDesktopFile(desktopEntryUrl.toLocalFile())) { return QVariantList(); } QVariantList actions; KDesktopFile desktopFile(desktopEntryUrl.toLocalFile()); const QStringList &jumpListActions = desktopFile.readActions(); const QLatin1String kde("KDE"); foreach (const QString &actionName, jumpListActions) { const KConfigGroup &actionGroup = desktopFile.actionGroup(actionName); if (!actionGroup.isValid() || !actionGroup.exists()) { continue; } const QStringList ¬ShowIn = actionGroup.readXdgListEntry(QStringLiteral("NotShowIn")); if (notShowIn.contains(kde)) { continue; } const QStringList &onlyShowIn = actionGroup.readXdgListEntry(QStringLiteral("OnlyShowIn")); if (!onlyShowIn.isEmpty() && !onlyShowIn.contains(kde)) { continue; } const QString &name = actionGroup.readEntry(QStringLiteral("Name")); const QString &exec = actionGroup.readEntry(QStringLiteral("Exec")); if (name.isEmpty() || exec.isEmpty()) { continue; } QAction *action = new QAction(parent); action->setText(name); action->setIcon(QIcon::fromTheme(actionGroup.readEntry("Icon"))); action->setProperty("exec", exec); // so we can show the proper application name and icon when it launches action->setProperty("applicationName", desktopFile.readName()); action->setProperty("applicationIcon", desktopFile.readIcon()); connect(action, &QAction::triggered, this, &Backend::handleJumpListAction); actions << QVariant::fromValue(action); } return actions; } QVariantList Backend::placesActions(const QUrl &launcherUrl, bool showAllPlaces, QObject *parent) { if (!parent) { return QVariantList(); } QUrl desktopEntryUrl = tryDecodeApplicationsUrl(launcherUrl); if (!desktopEntryUrl.isValid() || !desktopEntryUrl.isLocalFile() || !KDesktopFile::isDesktopFile(desktopEntryUrl.toLocalFile())) { return QVariantList(); } QVariantList actions; KDesktopFile desktopFile(desktopEntryUrl.toLocalFile()); // Since we can't have dynamic jump list actions, at least add the user's "Places" for file managers. const QStringList &categories = desktopFile.desktopGroup().readXdgListEntry(QStringLiteral("Categories")); if (!categories.contains(QLatin1String("FileManager"))) { return actions; } QString previousGroup; QMenu *subMenu = nullptr; QScopedPointer placesModel(new KFilePlacesModel()); for (int i = 0; i < placesModel->rowCount(); ++i) { QModelIndex idx = placesModel->index(i, 0); if (placesModel->isHidden(idx)) { continue; } const QString &title = idx.data(Qt::DisplayRole).toString(); const QIcon &icon = idx.data(Qt::DecorationRole).value(); const QUrl &url = idx.data(KFilePlacesModel::UrlRole).toUrl(); QAction *placeAction = new QAction(icon, title, parent); connect(placeAction, &QAction::triggered, this, [url, desktopEntryUrl] { KService::Ptr service = KService::serviceByDesktopPath(desktopEntryUrl.toLocalFile()); if (!service) { return; } KRun::runService(*service, {url}, QApplication::activeWindow()); }); const QString &groupName = idx.data(KFilePlacesModel::GroupRole).toString(); if (previousGroup.isEmpty()) { // Skip first group heading. previousGroup = groupName; } // Put all subsequent categories into a submenu. if (previousGroup != groupName) { QAction *subMenuAction = new QAction(groupName, parent); subMenu = new QMenu(); // Cannot parent a QMenu to a QAction, need to delete it manually. connect(parent, &QObject::destroyed, subMenu, &QObject::deleteLater); subMenuAction->setMenu(subMenu); actions << QVariant::fromValue(subMenuAction); previousGroup = groupName; } if (subMenu) { subMenu->addAction(placeAction); } else { actions << QVariant::fromValue(placeAction); } } // There is nothing more frustrating than having a "More" entry that ends up showing just one or two // additional entries. Therefore we truncate to max. 5 entries only if there are more than 7 in total. if (!showAllPlaces && actions.count() > 7) { const int totalActionCount = actions.count(); while (actions.count() > 5) { actions.removeLast(); } QAction *action = new QAction(parent); action->setText(i18ncp("Show all user Places", "%1 more Place", "%1 more Places", totalActionCount - actions.count())); connect(action, &QAction::triggered, this, &Backend::showAllPlaces); actions << QVariant::fromValue(action); } return actions; } QVariantList Backend::recentDocumentActions(const QUrl &launcherUrl, QObject *parent) { if (!parent) { return QVariantList(); } QUrl desktopEntryUrl = tryDecodeApplicationsUrl(launcherUrl); if (!desktopEntryUrl.isValid() || !desktopEntryUrl.isLocalFile() || !KDesktopFile::isDesktopFile(desktopEntryUrl.toLocalFile())) { return QVariantList(); } QVariantList actions; QString desktopName = desktopEntryUrl.fileName(); QString storageId = desktopName; if (storageId.endsWith(QLatin1String(".desktop"))) { storageId = storageId.left(storageId.length() - 8); } auto query = UsedResources | RecentlyUsedFirst | Agent(storageId) | Type::any() | Activity::current() | Url::file(); ResultSet results(query); ResultSet::const_iterator resultIt = results.begin(); int actionCount = 0; while (actionCount < 5 && resultIt != results.end()) { const QString resource = (*resultIt).resource(); ++resultIt; const QUrl url(resource); if (!url.isValid()) { continue; } const KFileItem fileItem(url); if (!fileItem.isFile()) { continue; } QAction *action = new QAction(parent); action->setText(url.fileName()); action->setIcon(QIcon::fromTheme(fileItem.iconName(), QIcon::fromTheme(QStringLiteral("unknown")))); action->setProperty("agent", storageId); action->setProperty("entryPath", desktopEntryUrl); action->setData(resource); connect(action, &QAction::triggered, this, &Backend::handleRecentDocumentAction); actions << QVariant::fromValue(action); ++actionCount; } if (actionCount > 0) { QAction *action = new QAction(parent); action->setText(i18n("Forget Recent Documents")); action->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear-history"))); action->setProperty("agent", storageId); connect(action, &QAction::triggered, this, &Backend::handleRecentDocumentAction); actions << QVariant::fromValue(action); } return actions; } void Backend::toolTipWindowChanged(QQuickWindow *window) { Q_UNUSED(window) updateWindowHighlight(); } void Backend::handleJumpListAction() const { const QAction *action = qobject_cast(sender()); if (!action) { return; } KRun::run(action->property("exec").toString(), {}, nullptr, action->property("applicationName").toString(), action->property("applicationIcon").toString()); } void Backend::handleRecentDocumentAction() const { const QAction *action = qobject_cast(sender()); if (!action) { return; } const QString agent = action->property("agent").toString(); if (agent.isEmpty()) { return; } const QString desktopPath = action->property("entryPath").toUrl().toLocalFile(); const QString resource = action->data().toString(); if (desktopPath.isEmpty() || resource.isEmpty()) { auto query = UsedResources | Agent(agent) | Type::any() | Activity::current() | Url::file(); KAStats::forgetResources(query); return; } KService::Ptr service = KService::serviceByDesktopPath(desktopPath); qDebug() << service; if (!service) { return; } KRun::runService(*service, QList() << QUrl(resource), QApplication::activeWindow()); } void Backend::setActionGroup(QAction *action) const { if (action) { action->setActionGroup(m_actionGroup); } } QRect Backend::globalRect(QQuickItem *item) const { if (!item || !item->window()) { return QRect(); } QRect iconRect(item->x(), item->y(), item->width(), item->height()); iconRect.moveTopLeft(item->parentItem()->mapToScene(iconRect.topLeft()).toPoint()); iconRect.moveTopLeft(item->window()->mapToGlobal(iconRect.topLeft())); return iconRect; } void Backend::ungrabMouse(QQuickItem *item) const { //this is a workaround where Qt will fail to realize a mouse has been released // this happens if a window which does not accept focus spawns a new window that takes focus and X grab // whilst the mouse is depressed // https://bugreports.qt.io/browse/QTBUG-59044 // this causes the next click to go missing //by releasing manually we avoid that situation auto ungrabMouseHack = [item]() { if (item && item->window() && item->window()->mouseGrabberItem()) { item->window()->mouseGrabberItem()->ungrabMouse(); } }; //pre 5.8.0 QQuickWindow code is "item->grabMouse(); sendEvent(item, mouseEvent)" //post 5.8.0 QQuickWindow code is sendEvent(item, mouseEvent); item->grabMouse() if (QVersionNumber::fromString(QString::fromLatin1(qVersion())) > QVersionNumber(5, 8, 0)) { QTimer::singleShot(0, item, ungrabMouseHack); } else { ungrabMouseHack(); } //end workaround } bool Backend::canPresentWindows() const { return (KWindowSystem::compositingActive() && KWindowEffects::isEffectAvailable(KWindowEffects::PresentWindowsGroup)); } void Backend::presentWindows(const QVariant &_winIds) { if (!m_taskManagerItem || !m_taskManagerItem->window()) { return; } QList winIds; const QVariantList &_winIdsList = _winIds.toList(); foreach(const QVariant &_winId, _winIdsList) { bool ok = false; qlonglong winId = _winId.toLongLong(&ok); if (ok) { winIds.append(winId); } } if (winIds.isEmpty()) { return; } if (m_windowsToHighlight.count()) { m_windowsToHighlight.clear(); updateWindowHighlight(); } KWindowEffects::presentWindows(m_taskManagerItem->window()->winId(), winIds); } bool Backend::isApplication(const QUrl &url) const { if (!url.isValid() || !url.isLocalFile()) { return false; } const QString &localPath = url.toLocalFile(); if (!KDesktopFile::isDesktopFile(localPath)) { return false; } KDesktopFile desktopFile(localPath); return desktopFile.hasApplicationType(); } QList Backend::jsonArrayToUrlList(const QJsonArray &array) const { QList urls; urls.reserve(array.count()); for (auto it = array.constBegin(), end = array.constEnd(); it != end; ++it) { urls << QUrl(it->toString()); } return urls; } void Backend::cancelHighlightWindows() { m_windowsToHighlight.clear(); updateWindowHighlight(); } void Backend::windowsHovered(const QVariant &_winIds, bool hovered) { m_windowsToHighlight.clear(); if (hovered) { const QVariantList &winIds = _winIds.toList(); foreach(const QVariant &_winId, winIds) { bool ok = false; qlonglong winId = _winId.toLongLong(&ok); if (ok) { m_windowsToHighlight.append(winId); } } } updateWindowHighlight(); } void Backend::updateWindowHighlight() { if (!m_highlightWindows) { if (m_panelWinId) { KWindowEffects::highlightWindows(m_panelWinId, QList()); m_panelWinId = 0; } return; } if (m_taskManagerItem && m_taskManagerItem->window()) { m_panelWinId = m_taskManagerItem->window()->winId(); } else { return; } QList windows = m_windowsToHighlight; if (!windows.isEmpty() && m_toolTipItem && m_toolTipItem->window()) { windows.append(m_toolTipItem->window()->winId()); } if (!windows.isEmpty() && m_groupDialog) { windows.append(m_groupDialog->winId()); } KWindowEffects::highlightWindows(m_panelWinId, windows); } diff --git a/containments/desktop/plugins/folder/foldermodel.cpp b/containments/desktop/plugins/folder/foldermodel.cpp index df0f85f71..c3ec2c46c 100644 --- a/containments/desktop/plugins/folder/foldermodel.cpp +++ b/containments/desktop/plugins/folder/foldermodel.cpp @@ -1,2107 +1,2107 @@ /*************************************************************************** * Copyright (C) 2006 David Faure * * Copyright (C) 2008 Fredrik Höglund * * Copyright (C) 2008 Rafael Fernández López * * Copyright (C) 2011 Marco Martin * * Copyright (C) 2014 by Eike Hein * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "foldermodel.h" #include "itemviewadapter.h" #include "positioner.h" #include "screenmapper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_LOGGING_CATEGORY(FOLDERMODEL, "plasma.containments.desktop.folder.foldermodel") DirLister::DirLister(QObject *parent) : KDirLister(parent) { } DirLister:: ~DirLister() { } void DirLister::handleError(KIO::Job *job) { if (!autoErrorHandlingEnabled()) { emit error(job->errorString()); return; } KDirLister::handleError(job); } FolderModel::FolderModel(QObject *parent) : QSortFilterProxyModel(parent), m_dirWatch(nullptr), m_dragInProgress(false), m_urlChangedWhileDragging(false), m_dropTargetPositionsCleanup(new QTimer(this)), m_previewGenerator(nullptr), m_viewAdapter(nullptr), m_actionCollection(this), m_newMenu(nullptr), m_fileItemActions(nullptr), m_usedByContainment(false), m_locked(true), m_sortMode(0), m_sortDesc(false), m_sortDirsFirst(true), m_parseDesktopFiles(false), m_previews(false), m_filterMode(NoFilter), m_filterPatternMatchAll(true), m_screenMapper(ScreenMapper::instance()), m_complete(false), m_screenUsed(false) { //needed to pass the job around with qml qmlRegisterType(); DirLister *dirLister = new DirLister(this); dirLister->setDelayedMimeTypes(true); dirLister->setAutoErrorHandlingEnabled(false, nullptr); connect(dirLister, &DirLister::error, this, &FolderModel::dirListFailed); connect(dirLister, &KCoreDirLister::itemsDeleted, this, &FolderModel::evictFromIsDirCache); connect(dirLister, &KCoreDirLister::started, this, std::bind(&FolderModel::setStatus, this, Status::Listing)); void (KCoreDirLister::*myCompletedSignal)() = &KCoreDirLister::completed; QObject::connect(dirLister, myCompletedSignal, this, [this] { setStatus(Status::Ready); emit listingCompleted(); }); void (KCoreDirLister::*myCanceledSignal)() = &KCoreDirLister::canceled; QObject::connect(dirLister, myCanceledSignal, this, [this] { setStatus(Status::Canceled); emit listingCanceled(); }); m_dirModel = new KDirModel(this); m_dirModel->setDirLister(dirLister); m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory | KDirModel::DropOnLocalExecutable); // If we have dropped items queued for moving, go unsorted now. connect(this, &QAbstractItemModel::rowsAboutToBeInserted, this, [this]() { if (!m_dropTargetPositions.isEmpty()) { setSortMode(-1); } }); // Position dropped items at the desired target position. connect(this, &QAbstractItemModel::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) { for (int i = first; i <= last; ++i) { const auto idx = index(i, 0, parent); const auto url = itemForIndex(idx).url(); auto it = m_dropTargetPositions.find(url.fileName()); if (it != m_dropTargetPositions.end()) { const auto pos = it.value(); m_dropTargetPositions.erase(it); emit move(pos.x(), pos.y(), {url}); } } }); /* * Dropped files may not actually show up as new files, e.g. when we overwrite * an existing file. Or files that fail to be listed by the dirLister, or... * To ensure we don't grow the map indefinitely, clean it up periodically. * The cleanup timer is (re)started whenever we modify the map. We use a quite * high interval of 10s. This should ensure, that we don't accidentally wipe * the mapping when we actually still want to use it. Since the time between * adding an entry in the map and it showing up in the model should be * small, this should rarely, if ever happen. */ m_dropTargetPositionsCleanup->setInterval(10000); m_dropTargetPositionsCleanup->setSingleShot(true); connect(m_dropTargetPositionsCleanup, &QTimer::timeout, this, [this]() { if (!m_dropTargetPositions.isEmpty()) { qCDebug(FOLDERMODEL) << "clearing drop target positions after timeout:" << m_dropTargetPositions; m_dropTargetPositions.clear(); } }); m_selectionModel = new QItemSelectionModel(this, this); connect(m_selectionModel, &QItemSelectionModel::selectionChanged, this, &FolderModel::selectionChanged); setSourceModel(m_dirModel); setSortLocaleAware(true); setFilterCaseSensitivity(Qt::CaseInsensitive); setDynamicSortFilter(true); sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder); createActions(); } FolderModel::~FolderModel() { if (m_usedByContainment) { // disconnect so we don't handle signals from the screen mapper when // removeScreen is called m_screenMapper->disconnect(this); m_screenMapper->removeScreen(m_screen, resolvedUrl()); } } QHash< int, QByteArray > FolderModel::roleNames() const { return staticRoleNames(); } QHash< int, QByteArray > FolderModel::staticRoleNames() { QHash roleNames; roleNames[Qt::DisplayRole] = "display"; roleNames[Qt::DecorationRole] = "decoration"; roleNames[BlankRole] = "blank"; roleNames[OverlaysRole] = "overlays"; roleNames[SelectedRole] = "selected"; roleNames[IsDirRole] = "isDir"; roleNames[IsLinkRole] = "isLink"; roleNames[IsHiddenRole] = "isHidden"; roleNames[UrlRole] = "url"; roleNames[LinkDestinationUrl] = "linkDestinationUrl"; roleNames[SizeRole] = "size"; roleNames[TypeRole] = "type"; return roleNames; } void FolderModel::classBegin() { } void FolderModel::componentComplete() { m_complete = true; invalidate(); } void FolderModel::invalidateIfComplete() { if (!m_complete) { return; } invalidate(); } void FolderModel::invalidateFilterIfComplete() { if (!m_complete) { return; } invalidateFilter(); } void FolderModel::newFileMenuItemCreated(const QUrl &url) { if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { m_screenMapper->addMapping(url, m_screen, ScreenMapper::DelayedSignal); m_dropTargetPositions.insert(url.fileName(), m_menuPosition); m_menuPosition = {}; m_dropTargetPositionsCleanup->start(); } } QString FolderModel::url() const { return m_url; } void FolderModel::setUrl(const QString& url) { const QUrl &resolvedNewUrl = resolve(url); if (url == m_url) { m_dirModel->dirLister()->updateDirectory(resolvedNewUrl); return; } const auto oldUrl = resolvedUrl(); beginResetModel(); m_url = url; m_isDirCache.clear(); m_dirModel->dirLister()->openUrl(resolvedNewUrl); clearDragImages(); m_dragIndexes.clear(); endResetModel(); emit urlChanged(); emit resolvedUrlChanged(); m_errorString.clear(); emit errorStringChanged(); if (m_dirWatch) { delete m_dirWatch; m_dirWatch = nullptr; } if (resolvedNewUrl.isValid()) { m_dirWatch = new KDirWatch(this); connect(m_dirWatch, &KDirWatch::created, this, &FolderModel::iconNameChanged); connect(m_dirWatch, &KDirWatch::dirty, this, &FolderModel::iconNameChanged); m_dirWatch->addFile(resolvedNewUrl.toLocalFile() + QLatin1String("/.directory")); } if (m_dragInProgress) { m_urlChangedWhileDragging = true; } emit iconNameChanged(); if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { m_screenMapper->removeScreen(m_screen, oldUrl); m_screenMapper->addScreen(m_screen, resolvedUrl()); } } QUrl FolderModel::resolvedUrl() const { return m_dirModel->dirLister()->url(); } QUrl FolderModel::resolve(const QString& url) { QUrl resolvedUrl; if (url.startsWith(QLatin1Char('~'))) { resolvedUrl = QUrl::fromLocalFile(KShell::tildeExpand(url)); } else { resolvedUrl = QUrl::fromUserInput(url); } return resolvedUrl; } QString FolderModel::iconName() const { const KFileItem rootItem(m_dirModel->dirLister()->url()); if (!rootItem.isFinalIconKnown()) { rootItem.determineMimeType(); } return rootItem.iconName(); } FolderModel::Status FolderModel::status() const { return m_status; } void FolderModel::setStatus(Status status) { if (m_status != status) { m_status = status; emit statusChanged(); } } QString FolderModel::errorString() const { return m_errorString; } bool FolderModel::dragging() const { return m_dragInProgress; } bool FolderModel::usedByContainment() const { return m_usedByContainment; } void FolderModel::setUsedByContainment(bool used) { if (m_usedByContainment != used) { m_usedByContainment = used; QAction *action = m_actionCollection.action(QStringLiteral("refresh")); if (action) { action->setText(m_usedByContainment ? i18n("&Refresh Desktop") : i18n("&Refresh View")); action->setIcon(m_usedByContainment ? QIcon::fromTheme(QStringLiteral("user-desktop")) : QIcon::fromTheme(QStringLiteral("view-refresh"))); } m_screenMapper->disconnect(this); connect(m_screenMapper, &ScreenMapper::screensChanged, this, &FolderModel::invalidateFilterIfComplete); connect(m_screenMapper, &ScreenMapper::screenMappingChanged, this, &FolderModel::invalidateFilterIfComplete); emit usedByContainmentChanged(); } } bool FolderModel::locked() const { return m_locked; } void FolderModel::setLocked(bool locked) { if (m_locked != locked) { m_locked = locked; emit lockedChanged(); } } void FolderModel::dirListFailed(const QString& error) { m_errorString = error; emit errorStringChanged(); } int FolderModel::sortMode() const { return m_sortMode; } void FolderModel::setSortMode(int mode) { if (m_sortMode != mode) { m_sortMode = mode; if (mode == -1 /* Unsorted */) { setDynamicSortFilter(false); } else { invalidateIfComplete(); sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder); setDynamicSortFilter(true); } emit sortModeChanged(); } } bool FolderModel::sortDesc() const { return m_sortDesc; } void FolderModel::setSortDesc(bool desc) { if (m_sortDesc != desc) { m_sortDesc = desc; if (m_sortMode != -1 /* Unsorted */) { invalidateIfComplete(); sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder); } emit sortDescChanged(); } } bool FolderModel::sortDirsFirst() const { return m_sortDirsFirst; } void FolderModel::setSortDirsFirst(bool enable) { if (m_sortDirsFirst != enable) { m_sortDirsFirst = enable; if (m_sortMode != -1 /* Unsorted */) { invalidateIfComplete(); sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder); } emit sortDirsFirstChanged(); } } bool FolderModel::parseDesktopFiles() const { return m_parseDesktopFiles; } void FolderModel::setParseDesktopFiles(bool enable) { if (m_parseDesktopFiles != enable) { m_parseDesktopFiles = enable; emit parseDesktopFilesChanged(); } } QObject* FolderModel::viewAdapter() const { return m_viewAdapter; } void FolderModel::setViewAdapter(QObject* adapter) { if (m_viewAdapter != adapter) { KAbstractViewAdapter *abstractViewAdapter = dynamic_cast(adapter); m_viewAdapter = abstractViewAdapter; if (m_viewAdapter && !m_previewGenerator) { m_previewGenerator = new KFilePreviewGenerator(abstractViewAdapter, this); m_previewGenerator->setPreviewShown(m_previews); m_previewGenerator->setEnabledPlugins(m_effectivePreviewPlugins); } emit viewAdapterChanged(); } } bool FolderModel::previews() const { return m_previews; } void FolderModel::setPreviews(bool previews) { if (m_previews != previews) { m_previews = previews; if (m_previewGenerator) { m_previewGenerator->setPreviewShown(m_previews); } emit previewsChanged(); } } QStringList FolderModel::previewPlugins() const { return m_previewPlugins; } void FolderModel::setPreviewPlugins(const QStringList& previewPlugins) { QStringList effectivePlugins = previewPlugins; if (effectivePlugins.isEmpty()) { effectivePlugins = KIO::PreviewJob::defaultPlugins(); } if (m_effectivePreviewPlugins != effectivePlugins) { m_effectivePreviewPlugins = effectivePlugins; if (m_previewGenerator) { m_previewGenerator->setPreviewShown(false); m_previewGenerator->setEnabledPlugins(m_effectivePreviewPlugins); m_previewGenerator->setPreviewShown(true); } } if (m_previewPlugins != previewPlugins) { m_previewPlugins = previewPlugins; emit previewPluginsChanged(); } } int FolderModel::filterMode() const { return m_filterMode; } void FolderModel::setFilterMode(int filterMode) { if (m_filterMode != (FilterMode)filterMode) { m_filterMode = (FilterMode)filterMode; invalidateFilterIfComplete(); emit filterModeChanged(); } } QString FolderModel::filterPattern() const { return m_filterPattern; } void FolderModel::setFilterPattern(const QString &pattern) { if (m_filterPattern == pattern) { return; } m_filterPattern = pattern; m_filterPatternMatchAll = (pattern == QLatin1String("*")); const QStringList patterns = pattern.split(QLatin1Char(' ')); m_regExps.clear(); m_regExps.reserve(patterns.count()); foreach (const QString &pattern, patterns) { QRegExp rx(pattern); rx.setPatternSyntax(QRegExp::Wildcard); rx.setCaseSensitivity(Qt::CaseInsensitive); m_regExps.append(rx); } invalidateFilterIfComplete(); emit filterPatternChanged(); } QStringList FolderModel::filterMimeTypes() const { return m_mimeSet.toList(); } void FolderModel::setFilterMimeTypes(const QStringList &mimeList) { const QSet &set = QSet::fromList(mimeList); if (m_mimeSet != set) { m_mimeSet = set; invalidateFilterIfComplete(); emit filterMimeTypesChanged(); } } void FolderModel::setScreen(int screen) { m_screenUsed = (screen != -1); if (!m_screenUsed || m_screen == screen) return; m_screen = screen; if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { m_screenMapper->addScreen(screen, resolvedUrl()); } emit screenChanged(); } bool FolderModel::eventFilter(QObject *watched, QEvent *event) { Q_UNUSED(watched) // Catching Shift modifier usage on open context menus to swap the // Trash/Delete actions. if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Shift) { m_actionCollection.action(QStringLiteral("trash"))->setVisible(false); m_actionCollection.action(QStringLiteral("del"))->setVisible(true); } } else if (event->type() == QEvent::KeyRelease) { QKeyEvent *keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Shift) { m_actionCollection.action(QStringLiteral("trash"))->setVisible(true); m_actionCollection.action(QStringLiteral("del"))->setVisible(false); } } return false; } KFileItem FolderModel::rootItem() const { return m_dirModel->dirLister()->rootItem(); } void FolderModel::up() { const QUrl &up = KIO::upUrl(resolvedUrl()); if (up.isValid()) { setUrl(up.toString()); } } void FolderModel::cd(int row) { if (row < 0) { return; } const QModelIndex idx = index(row, 0); bool isDir = data(idx, IsDirRole).toBool(); if (isDir) { const KFileItem item = itemForIndex(idx); if (m_parseDesktopFiles && item.isDesktopFile()) { const KDesktopFile file(item.targetUrl().path()); if (file.hasLinkType()) { setUrl(file.readUrl()); } } else { setUrl(item.targetUrl().toString()); } } } void FolderModel::run(int row) { if (row < 0) { return; } KFileItem item = itemForIndex(index(row, 0)); QUrl url(item.targetUrl()); // FIXME TODO: This can go once we depend on a KIO w/ fe1f50caaf2. if (url.scheme().isEmpty()) { url.setScheme(QStringLiteral("file")); } KRun *run = new KRun(url, nullptr); // On desktop:/ we want to be able to run .desktop files right away, // otherwise ask for security reasons. We also don't use the targetUrl() // from above since we don't want the resolved /home/foo/Desktop URL. run->setShowScriptExecutionPrompt(item.url().scheme() != QLatin1String("desktop") || item.url().adjusted(QUrl::RemoveFilename).path() != QLatin1String("/")); } void FolderModel::runSelected() { if (!m_selectionModel->hasSelection()) { return; } if (m_selectionModel->selectedIndexes().count() == 1) { run(m_selectionModel->selectedIndexes().constFirst().row()); return; } KFileItemActions fileItemActions(this); KFileItemList items; foreach (const QModelIndex &index, m_selectionModel->selectedIndexes()) { // Skip over directories. if (!index.data(IsDirRole).toBool()) { items << itemForIndex(index); } } fileItemActions.runPreferredApplications(items, QString()); } void FolderModel::rename(int row, const QString& name) { if (row < 0) { return; } QModelIndex idx = index(row, 0); m_dirModel->setData(mapToSource(idx), name, Qt::EditRole); } int FolderModel::fileExtensionBoundary(int row) { const QModelIndex idx = index(row, 0); const QString &name = data(idx, Qt::DisplayRole).toString(); int boundary = name.length(); if (data(idx, IsDirRole).toBool()) { return boundary; } QMimeDatabase db; const QString &ext = db.suffixForFileName(name); if (ext.isEmpty()) { boundary = name.lastIndexOf(QLatin1Char('.')); if (boundary < 1) { boundary = name.length(); } } else { boundary -= ext.length() + 1; } return boundary; } bool FolderModel::hasSelection() const { return m_selectionModel->hasSelection(); } bool FolderModel::isSelected(int row) { if (row < 0) { return false; } return m_selectionModel->isSelected(index(row, 0)); } void FolderModel::setSelected(int row) { if (row < 0) { return; } m_selectionModel->select(index(row, 0), QItemSelectionModel::Select); } void FolderModel::toggleSelected(int row) { if (row < 0) { return; } m_selectionModel->select(index(row, 0), QItemSelectionModel::Toggle); } void FolderModel::setRangeSelected(int anchor, int to) { if (anchor < 0 || to < 0) { return; } QItemSelection selection(index(anchor, 0), index(to, 0)); m_selectionModel->select(selection, QItemSelectionModel::ClearAndSelect); } void FolderModel::updateSelection(const QVariantList &rows, bool toggle) { QItemSelection newSelection; int iRow = -1; foreach (const QVariant &row, rows) { iRow = row.toInt(); if (iRow < 0) { return; } const QModelIndex &idx = index(iRow, 0); newSelection.select(idx, idx); } if (toggle) { QItemSelection pinnedSelection = m_pinnedSelection; pinnedSelection.merge(newSelection, QItemSelectionModel::Toggle); m_selectionModel->select(pinnedSelection, QItemSelectionModel::ClearAndSelect); } else { m_selectionModel->select(newSelection, QItemSelectionModel::ClearAndSelect); } } void FolderModel::clearSelection() { if (m_selectionModel->hasSelection()) { m_selectionModel->clear(); } } void FolderModel::pinSelection() { m_pinnedSelection = m_selectionModel->selection(); } void FolderModel::unpinSelection() { m_pinnedSelection = QItemSelection(); } void FolderModel::addItemDragImage(int row, int x, int y, int width, int height, const QVariant &image) { if (row < 0) { return; } delete m_dragImages.take(row); DragImage *dragImage = new DragImage(); dragImage->row = row; dragImage->rect = QRect(x, y, width, height); dragImage->image = image.value(); dragImage->blank = false; m_dragImages.insert(row, dragImage); } void FolderModel::clearDragImages() { qDeleteAll(m_dragImages); m_dragImages.clear(); } void FolderModel::setDragHotSpotScrollOffset(int x, int y) { m_dragHotSpotScrollOffset.setX(x); m_dragHotSpotScrollOffset.setY(y); } QPoint FolderModel::dragCursorOffset(int row) { DragImage *image = m_dragImages.value(row); if (!image) { return QPoint(0, 0); } return image->cursorOffset; } void FolderModel::addDragImage(QDrag *drag, int x, int y) { if (!drag || m_dragImages.isEmpty()) { return; } QRegion region; foreach (DragImage *image, m_dragImages) { image->blank = isBlank(image->row); image->rect.translate(-m_dragHotSpotScrollOffset.x(), -m_dragHotSpotScrollOffset.y()); if (!image->blank && !image->image.isNull()) { region = region.united(image->rect); } } QRect rect = region.boundingRect(); QPoint offset = rect.topLeft(); rect.translate(-offset.x(), -offset.y()); QImage dragImage(rect.size(), QImage::Format_RGBA8888); dragImage.fill(Qt::transparent); QPainter painter(&dragImage); QPoint pos; foreach (DragImage *image, m_dragImages) { if (!image->blank && !image->image.isNull()) { pos = image->rect.translated(-offset.x(), -offset.y()).topLeft(); image->cursorOffset.setX(pos.x() - (x - offset.x())); image->cursorOffset.setY(pos.y() - (y - offset.y())); painter.drawImage(pos, image->image); } // FIXME HACK: Operate on copy. image->rect.translate(m_dragHotSpotScrollOffset.x(), m_dragHotSpotScrollOffset.y()); } drag->setPixmap(QPixmap::fromImage(dragImage)); drag->setHotSpot(QPoint(x - offset.x(), y - offset.y())); } void FolderModel::dragSelected(int x, int y) { if (m_dragInProgress) { return; } m_dragInProgress = true; emit draggingChanged(); m_urlChangedWhileDragging = false; // Avoid starting a drag synchronously in a mouse handler or interferes with // child event filtering in parent items (and thus e.g. press-and-hold hand- // ling in a containment). QMetaObject::invokeMethod(this, "dragSelectedInternal", Qt::QueuedConnection, Q_ARG(int, x), Q_ARG(int, y)); } void FolderModel::dragSelectedInternal(int x, int y) { if (!m_viewAdapter || !m_selectionModel->hasSelection()) { m_dragInProgress = false; emit draggingChanged(); return; } ItemViewAdapter *adapter = qobject_cast(m_viewAdapter); QQuickItem *item = qobject_cast(adapter->adapterView()); QDrag *drag = new QDrag(item); addDragImage(drag, x, y); m_dragIndexes = m_selectionModel->selectedIndexes(); std::sort(m_dragIndexes.begin(), m_dragIndexes.end()); // TODO: Optimize to emit contiguous groups. emit dataChanged(m_dragIndexes.first(), m_dragIndexes.last(), QVector() << BlankRole); QModelIndexList sourceDragIndexes; sourceDragIndexes.reserve(m_dragIndexes.count()); foreach (const QModelIndex &index, m_dragIndexes) { sourceDragIndexes.append(mapToSource(index)); } drag->setMimeData(m_dirModel->mimeData(sourceDragIndexes)); // Due to spring-loading (aka auto-expand), the URL might change // while the drag is in-flight - in that case we don't want to // unnecessarily emit dataChanged() for (possibly invalid) indices // after it ends. const QUrl currentUrl(m_dirModel->dirLister()->url()); item->grabMouse(); drag->exec(supportedDragActions()); item->ungrabMouse(); m_dragInProgress = false; emit draggingChanged(); m_urlChangedWhileDragging = false; if (m_dirModel->dirLister()->url() == currentUrl) { const QModelIndex first(m_dragIndexes.first()); const QModelIndex last(m_dragIndexes.last()); m_dragIndexes.clear(); // TODO: Optimize to emit contiguous groups. emit dataChanged(first, last, QVector() << BlankRole); } } static bool isDropBetweenSharedViews(const QList &urls, const QUrl &folderUrl) { for (const auto &url : urls) { if (folderUrl.adjusted(QUrl::StripTrailingSlash) != url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash)) { return false; } } return true; } void FolderModel::drop(QQuickItem *target, QObject* dropEvent, int row) { QMimeData *mimeData = qobject_cast(dropEvent->property("mimeData").value()); if (!mimeData) { return; } QModelIndex idx; KFileItem item; if (row > -1 && row < rowCount()) { idx = index(row, 0); item = itemForIndex(idx); } QUrl dropTargetUrl; // So we get to run mostLocalUrl() over the current URL. if (item.isNull()) { item = rootItem(); } if (item.isNull()) { dropTargetUrl = m_dirModel->dirLister()->url(); } else if (m_parseDesktopFiles && item.isDesktopFile()) { const KDesktopFile file(item.targetUrl().path()); if (file.hasLinkType()) { dropTargetUrl = QUrl(file.readUrl()); } else { dropTargetUrl = item.mostLocalUrl(); } } else { dropTargetUrl = item.mostLocalUrl(); } auto dropTargetFolderUrl = dropTargetUrl; if (dropTargetFolderUrl.fileName() == QLatin1Char('.')) { // the target URL for desktop:/ is e.g. 'file://home/user/Desktop/.' dropTargetFolderUrl = dropTargetFolderUrl.adjusted(QUrl::RemoveFilename); } // use dropTargetUrl to resolve desktop:/ to the actual file location which is also used by the mime data /* QMimeData operates on local URLs, but the dir lister and thus screen mapper and positioner may * use a fancy scheme like desktop:/ instead. Ensure we always use the latter to properly map URLs, * i.e. go from file:///home/user/Desktop/file to desktop:/file */ auto mappableUrl = [this, dropTargetFolderUrl](const QUrl &url) -> QUrl { if (dropTargetFolderUrl != m_dirModel->dirLister()->url()) { QString mappedUrl = url.toString(); const auto local = dropTargetFolderUrl.toString(); const auto internal = m_dirModel->dirLister()->url().toString(); if (mappedUrl.startsWith(local)) { mappedUrl.replace(0, local.size(), internal); } return ScreenMapper::stringToUrl(mappedUrl); } return url; }; const int x = dropEvent->property("x").toInt(); const int y = dropEvent->property("y").toInt(); const QPoint dropPos = {x, y}; if (m_dragInProgress && row == -1 && !m_urlChangedWhileDragging) { if (m_locked || mimeData->urls().isEmpty()) { return; } setSortMode(-1); for (const auto &url : mimeData->urls()) { m_dropTargetPositions.insert(url.fileName(), dropPos); m_screenMapper->addMapping(mappableUrl(url), m_screen, ScreenMapper::DelayedSignal); m_screenMapper->removeItemFromDisabledScreen(mappableUrl(url)); } emit move(x, y, mimeData->urls()); return; } if (mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-service")) && mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-path"))) { const QString remoteDBusClient = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-service")); const QString remoteDBusPath = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-path")); QDBusMessage message = QDBusMessage::createMethodCall(remoteDBusClient, remoteDBusPath, QStringLiteral("org.kde.ark.DndExtract"), QStringLiteral("extractSelectedFilesTo")); message.setArguments({dropTargetUrl.toDisplayString(QUrl::PreferLocalFile)}); QDBusConnection::sessionBus().call(message, QDBus::NoBlock); return; } if (idx.isValid() && !(flags(idx) & Qt::ItemIsDropEnabled)) { return; } // Catch drops from a Task Manager and convert to usable URL. if (!mimeData->hasUrls() && mimeData->hasFormat(QStringLiteral("text/x-orgkdeplasmataskmanager_taskurl"))) { QList urls = {QUrl(QString::fromUtf8(mimeData->data(QStringLiteral("text/x-orgkdeplasmataskmanager_taskurl"))))}; mimeData->setUrls(urls); } if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { if (isDropBetweenSharedViews(mimeData->urls(), dropTargetFolderUrl)) { setSortMode(-1); for (const auto &url : mimeData->urls()) { m_dropTargetPositions.insert(url.fileName(), dropPos); m_screenMapper->addMapping(mappableUrl(url), m_screen, ScreenMapper::DelayedSignal); m_screenMapper->removeItemFromDisabledScreen(mappableUrl(url)); } m_dropTargetPositionsCleanup->start(); return; } } Qt::DropAction proposedAction((Qt::DropAction)dropEvent->property("proposedAction").toInt()); Qt::DropActions possibleActions(dropEvent->property("possibleActions").toInt()); Qt::MouseButtons buttons(dropEvent->property("buttons").toInt()); Qt::KeyboardModifiers modifiers(dropEvent->property("modifiers").toInt()); auto pos = target->mapToScene(dropPos).toPoint(); pos = target->window()->mapToGlobal(pos); QDropEvent ev(pos, possibleActions, mimeData, buttons, modifiers); ev.setDropAction(proposedAction); KIO::DropJob *dropJob = KIO::drop(&ev, dropTargetUrl); dropJob->uiDelegate()->setAutoErrorHandlingEnabled(true); // The QMimeData we extract from the DropArea's drop event is deleted as soon as this method // ends but we need to keep a copy for when popupMenuAboutToShow fires. QMimeData *mimeCopy = new QMimeData(); for (const QString &format : mimeData->formats()) { mimeCopy->setData(format, mimeData->data(format)); } connect(dropJob, &KIO::DropJob::popupMenuAboutToShow, this, [this, mimeCopy, x, y, dropJob](const KFileItemListProperties &) { emit popupMenuAboutToShow(dropJob, mimeCopy, x, y); mimeCopy->deleteLater(); }); /* * Position files that come from a drag'n'drop event at the drop event * target position. To do so, we first listen to copy job to figure out * the target URL. Then we store the position of this drop event in the * hash and eventually trigger a move request when we get notified about * the new file event from the source model. */ connect(dropJob, &KIO::DropJob::copyJobStarted, this, [this, dropPos, dropTargetUrl](KIO::CopyJob* copyJob) { auto map = [this, dropPos, dropTargetUrl](const QUrl &targetUrl) { m_dropTargetPositions.insert(targetUrl.fileName(), dropPos); m_dropTargetPositionsCleanup->start(); if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { // assign a screen for the item before the copy is actually done, so // filterAcceptsRow doesn't assign the default screen to it QUrl url = resolvedUrl(); // if the folderview's folder is a standard path, just use the targetUrl for mapping if (targetUrl.toString().startsWith(url.toString())) { m_screenMapper->addMapping(targetUrl, m_screen, ScreenMapper::DelayedSignal); } else if (targetUrl.toString().startsWith(dropTargetUrl.toString())) { // if the folderview's folder is a special path, like desktop:// , we need to convert // the targetUrl file:// path to a desktop:/ path for mapping auto destPath = dropTargetUrl.path(); auto filePath = targetUrl.path(); if (filePath.startsWith(destPath)) { url.setPath(filePath.remove(0, destPath.length())); m_screenMapper->addMapping(url, m_screen, ScreenMapper::DelayedSignal); } } } }; // remember drop target position for target URL and forget about the source URL connect(copyJob, &KIO::CopyJob::copyingDone, - this, [this, map](KIO::Job *, const QUrl &, const QUrl &targetUrl, const QDateTime &, bool, bool) { + this, [ map](KIO::Job *, const QUrl &, const QUrl &targetUrl, const QDateTime &, bool, bool) { map(targetUrl); }); connect(copyJob, &KIO::CopyJob::copyingLinkDone, - this, [this, map](KIO::Job *, const QUrl &, const QString &, const QUrl &targetUrl) { + this, [ map](KIO::Job *, const QUrl &, const QString &, const QUrl &targetUrl) { map(targetUrl); }); }); } void FolderModel::dropCwd(QObject* dropEvent) { QMimeData *mimeData = qobject_cast(dropEvent->property("mimeData").value()); if (!mimeData) { return; } if (mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-service")) && mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-path"))) { const QString remoteDBusClient = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-service")); const QString remoteDBusPath = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-path")); QDBusMessage message = QDBusMessage::createMethodCall(remoteDBusClient, remoteDBusPath, QStringLiteral("org.kde.ark.DndExtract"), QStringLiteral("extractSelectedFilesTo")); message.setArguments(QVariantList() << m_dirModel->dirLister()->url().adjusted(QUrl::PreferLocalFile).toString()); QDBusConnection::sessionBus().call(message, QDBus::NoBlock); } else { Qt::DropAction proposedAction((Qt::DropAction)dropEvent->property("proposedAction").toInt()); Qt::DropActions possibleActions(dropEvent->property("possibleActions").toInt()); Qt::MouseButtons buttons(dropEvent->property("buttons").toInt()); Qt::KeyboardModifiers modifiers(dropEvent->property("modifiers").toInt()); QDropEvent ev(QPoint(), possibleActions, mimeData, buttons, modifiers); ev.setDropAction(proposedAction); KIO::DropJob *dropJob = KIO::drop(&ev, m_dirModel->dirLister()->url().adjusted(QUrl::PreferLocalFile)); dropJob->uiDelegate()->setAutoErrorHandlingEnabled(true); } } void FolderModel::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { QModelIndexList indices = selected.indexes(); indices.append(deselected.indexes()); QVector roles; roles.append(SelectedRole); foreach(const QModelIndex &index, indices) { emit dataChanged(index, index, roles); } if (!m_selectionModel->hasSelection()) { clearDragImages(); } else { foreach (const QModelIndex &idx, deselected.indexes()) { delete m_dragImages.take(idx.row()); } } updateActions(); } bool FolderModel::isBlank(int row) const { if (row < 0) { return true; } return data(index(row, 0), BlankRole).toBool(); } QVariant FolderModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == BlankRole) { return m_dragIndexes.contains(index); } else if (role == OverlaysRole) { const KFileItem item = itemForIndex(index); return item.overlays(); } else if (role == SelectedRole) { return m_selectionModel->isSelected(index); } else if (role == IsDirRole) { return isDir(mapToSource(index), m_dirModel); } else if (role == IsLinkRole) { const KFileItem item = itemForIndex(index); return item.isLink(); } else if (role == IsHiddenRole) { const KFileItem item = itemForIndex(index); return item.isHidden(); } else if (role == UrlRole) { return itemForIndex(index).url(); } else if (role == LinkDestinationUrl) { const KFileItem item = itemForIndex(index); if (m_parseDesktopFiles && item.isDesktopFile()) { const KDesktopFile file(item.targetUrl().path()); if (file.hasLinkType()) { return file.readUrl(); } } return item.targetUrl(); } else if (role == SizeRole) { bool isDir = data(index, IsDirRole).toBool(); if (!isDir) { return m_dirModel->data(mapToSource(QSortFilterProxyModel::index(index.row(), 1)), Qt::DisplayRole); } } else if (role == TypeRole) { return m_dirModel->data(mapToSource(QSortFilterProxyModel::index(index.row(), 6)), Qt::DisplayRole); } else if (role == FileNameRole) { return itemForIndex(index).url().fileName(); } return QSortFilterProxyModel::data(index, role); } int FolderModel::indexForUrl(const QUrl& url) const { return mapFromSource(m_dirModel->indexForUrl(url)).row(); } KFileItem FolderModel::itemForIndex(const QModelIndex &index) const { return m_dirModel->itemForIndex(mapToSource(index)); } bool FolderModel::isDir(const QModelIndex &index, const KDirModel *dirModel) const { KFileItem item = dirModel->itemForIndex(index); if (item.isDir()) { return true; } auto it = m_isDirCache.constFind(item.url()); if (it != m_isDirCache.constEnd()) { return *it; } if (m_parseDesktopFiles && item.isDesktopFile()) { // Check if the desktop file is a link to a directory KDesktopFile file(item.targetUrl().path()); if (!file.hasLinkType()) { return false; } const QUrl url(file.readUrl()); // Check if we already have a running StatJob for this URL. if (m_isDirJobs.contains(item.url())) { return false; } // Assume the root folder of a protocol is always a folder. // This avoids spinning up e.g. trash KIO slave just to check whether trash:/ is a folder. if (url.path() == QLatin1String("/")) { m_isDirCache.insert(item.url(), true); return true; } if (KProtocolInfo::protocolClass(url.scheme()) != QLatin1String(":local")) { return false; } KIO::StatJob *job = KIO::stat(url, KIO::HideProgressInfo); job->setProperty("org.kde.plasma.folder_url", item.url()); job->setSide(KIO::StatJob::SourceSide); job->setDetails(0); connect(job, &KJob::result, this, &FolderModel::statResult); m_isDirJobs.insert(item.url(), job); } return false; } void FolderModel::statResult(KJob *job) { KIO::StatJob *statJob = static_cast(job); const QUrl &url = statJob->property("org.kde.plasma.folder_url").toUrl(); const QModelIndex &idx = index(indexForUrl(url), 0); if (idx.isValid() && statJob->error() == KJob::NoError) { m_isDirCache[url] = statJob->statResult().isDir(); emit dataChanged(idx, idx, QVector() << IsDirRole); } m_isDirJobs.remove(url); } void FolderModel::evictFromIsDirCache(const KFileItemList& items) { foreach (const KFileItem &item, items) { m_screenMapper->removeFromMap(item.url()); m_isDirCache.remove(item.url()); } } bool FolderModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { const KDirModel *dirModel = static_cast(sourceModel()); if (m_sortDirsFirst || left.column() == KDirModel::Size) { bool leftIsDir = isDir(left, dirModel); bool rightIsDir = isDir(right, dirModel); if (leftIsDir && !rightIsDir) { return (sortOrder() == Qt::AscendingOrder); } if (!leftIsDir && rightIsDir) { return (sortOrder() == Qt::DescendingOrder); } } const KFileItem leftItem = dirModel->data(left, KDirModel::FileItemRole).value(); const KFileItem rightItem = dirModel->data(right, KDirModel::FileItemRole).value(); const int column = left.column(); int result = 0; switch (column) { case KDirModel::Size: { if (isDir(left, dirModel) && isDir(right, dirModel)) { const int leftChildCount = dirModel->data(left, KDirModel::ChildCountRole).toInt(); const int rightChildCount = dirModel->data(right, KDirModel::ChildCountRole).toInt(); if (leftChildCount < rightChildCount) result = -1; else if (leftChildCount > rightChildCount) result = +1; } else { const KIO::filesize_t leftSize = leftItem.size(); const KIO::filesize_t rightSize = rightItem.size(); if (leftSize < rightSize) result = -1; else if (leftSize > rightSize) result = +1; } break; } case KDirModel::ModifiedTime: { const long long leftTime = leftItem.entry().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1); const long long rightTime = rightItem.entry().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1); if (leftTime < rightTime) result = -1; else if (leftTime > rightTime) result = +1; break; } case KDirModel::Type: result = QString::compare(dirModel->data(left, Qt::DisplayRole).toString(), dirModel->data(right, Qt::DisplayRole).toString()); break; default: break; } if (result != 0) return result < 0; QCollator collator; result = collator.compare(leftItem.text(), rightItem.text()); if (result != 0) return result < 0; result = collator.compare(leftItem.name(), rightItem.name()); if (result != 0) return result < 0; return QString::compare(leftItem.url().url(), rightItem.url().url(), Qt::CaseSensitive); } Qt::DropActions FolderModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; } Qt::DropActions FolderModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; } inline bool FolderModel::matchMimeType(const KFileItem &item) const { if (m_mimeSet.isEmpty()) { return false; } if (m_mimeSet.contains(QLatin1String("all/all")) || m_mimeSet.contains(QLatin1String("all/allfiles"))) { return true; } const QString mimeType = item.determineMimeType().name(); return m_mimeSet.contains(mimeType); } inline bool FolderModel::matchPattern(const KFileItem &item) const { if (m_filterPatternMatchAll) { return true; } const QString name = item.name(); QListIterator i(m_regExps); while (i.hasNext()) { if (i.next().exactMatch(name)) { return true; } } return false; } bool FolderModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { const KDirModel *dirModel = static_cast(sourceModel()); const KFileItem item = dirModel->itemForIndex(dirModel->index(sourceRow, KDirModel::Name, sourceParent)); if (m_usedByContainment && !m_screenMapper->sharedDesktops()) { const QUrl url = item.url(); const int screen = m_screenMapper->screenForItem(url); // don't do anything if the folderview is not associated with a screen if (m_screenUsed && screen == -1) { // The item is not associated with a screen, probably because this is the first // time we see it or the folderview was previously used as a regular applet. // Associated with this folderview if the view is on the first available screen if (m_screen == m_screenMapper->firstAvailableScreen(resolvedUrl())) { m_screenMapper->addMapping(url, m_screen, ScreenMapper::DelayedSignal); } else { return false; } } else if (m_screen != screen) { // the item belongs to a different screen, filter it out return false; } } if (m_filterMode == NoFilter) { return true; } if (m_filterMode == FilterShowMatches) { return (matchPattern(item) && matchMimeType(item)); } else { return !(matchPattern(item) && matchMimeType(item)); } } void FolderModel::createActions() { KIO::FileUndoManager *manager = KIO::FileUndoManager::self(); QAction *cut = KStandardAction::cut(this, &FolderModel::cut, this); QAction *copy = KStandardAction::copy(this, &FolderModel::copy, this); QAction *undo = KStandardAction::undo(manager, &KIO::FileUndoManager::undo, this); undo->setEnabled(manager->undoAvailable()); undo->setShortcutContext(Qt::WidgetShortcut); connect(manager, SIGNAL(undoAvailable(bool)), undo, SLOT(setEnabled(bool))); connect(manager, &KIO::FileUndoManager::undoTextChanged, this, &FolderModel::undoTextChanged); QAction *paste = KStandardAction::paste(this, &FolderModel::paste, this); QAction *pasteTo = KStandardAction::paste(this, &FolderModel::pasteTo, this); QAction *refresh = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18n("&Refresh View"), this); refresh->setShortcut(QKeySequence(QKeySequence::Refresh)); connect(refresh, &QAction::triggered, this, &FolderModel::refresh); QAction *rename = KStandardAction::renameFile(this, &FolderModel::requestRename, this); QAction *trash = KStandardAction::moveToTrash(this, &FolderModel::moveSelectedToTrash, this); QAction *emptyTrash = new QAction(QIcon::fromTheme(QStringLiteral("trash-empty")), i18n("&Empty Trash"), this); connect(emptyTrash, &QAction::triggered, this, &FolderModel::emptyTrashBin); QAction *restoreFromTrash = new QAction(i18nc("Restore from trash", "Restore"), this); connect(restoreFromTrash, &QAction::triggered, this, &FolderModel::restoreSelectedFromTrash); QAction *del = KStandardAction::deleteFile(this, &FolderModel::deleteSelected, this); QAction *actOpen = new QAction(QIcon::fromTheme(QStringLiteral("window-new")), i18n("&Open"), this); connect(actOpen, &QAction::triggered, this, &FolderModel::openSelected); m_actionCollection.addAction(QStringLiteral("open"), actOpen); m_actionCollection.addAction(QStringLiteral("cut"), cut); m_actionCollection.addAction(QStringLiteral("undo"), undo); m_actionCollection.addAction(QStringLiteral("copy"), copy); m_actionCollection.addAction(QStringLiteral("paste"), paste); m_actionCollection.addAction(QStringLiteral("pasteto"), pasteTo); m_actionCollection.addAction(QStringLiteral("refresh"), refresh); m_actionCollection.addAction(QStringLiteral("rename"), rename); m_actionCollection.addAction(QStringLiteral("trash"), trash); m_actionCollection.addAction(QStringLiteral("del"), del); m_actionCollection.addAction(QStringLiteral("restoreFromTrash"), restoreFromTrash); m_actionCollection.addAction(QStringLiteral("emptyTrash"), emptyTrash); m_newMenu = new KNewFileMenu(&m_actionCollection, QStringLiteral("newMenu"), this); m_newMenu->setModal(false); connect(m_newMenu, &KNewFileMenu::directoryCreated, this, &FolderModel::newFileMenuItemCreated); connect(m_newMenu, &KNewFileMenu::fileCreated, this, &FolderModel::newFileMenuItemCreated); m_copyToMenu = new KFileCopyToMenu(nullptr); } QAction* FolderModel::action(const QString &name) const { return m_actionCollection.action(name); } QObject* FolderModel::newMenu() const { return m_newMenu->menu(); } void FolderModel::updateActions() { const QModelIndexList indexes = m_selectionModel->selectedIndexes(); KFileItemList items; QList urls; bool hasRemoteFiles = false; bool isTrashLink = false; const bool isTrash = (resolvedUrl().scheme() == QLatin1String("trash")); if (indexes.isEmpty()) { items << rootItem(); } else { items.reserve(indexes.count()); urls.reserve(indexes.count()); for (const QModelIndex &index : indexes) { KFileItem item = itemForIndex(index); if (!item.isNull()) { hasRemoteFiles |= item.localPath().isEmpty(); items.append(item); urls.append(item.url()); } } } KFileItemListProperties itemProperties(items); // Check if we're showing the menu for the trash link if (items.count() == 1 && items.at(0).isDesktopFile()) { KDesktopFile file(items.at(0).localPath()); if (file.hasLinkType() && file.readUrl() == QLatin1String("trash:/")) { isTrashLink = true; } } if (m_newMenu) { m_newMenu->checkUpToDate(); m_newMenu->setPopupFiles(m_dirModel->dirLister()->url()); // we need to set here as well, when the menu is shown via AppletInterface::eventFilter m_menuPosition = QCursor::pos(); if (QAction *newMenuAction = m_actionCollection.action(QStringLiteral("newMenu"))) { newMenuAction->setEnabled(itemProperties.supportsWriting()); newMenuAction->setVisible(!isTrash); } } if (QAction *emptyTrash = m_actionCollection.action(QStringLiteral("emptyTrash"))) { if (isTrash || isTrashLink) { emptyTrash->setVisible(true); emptyTrash->setEnabled(!isTrashEmpty()); } else { emptyTrash->setVisible(false); } } if (QAction *restoreFromTrash = m_actionCollection.action(QStringLiteral("restoreFromTrash"))) { restoreFromTrash->setVisible(isTrash); } if (QAction *moveToTrash = m_actionCollection.action(QStringLiteral("trash"))) { moveToTrash->setVisible(!hasRemoteFiles && itemProperties.supportsMoving()); } if (QAction *del = m_actionCollection.action(QStringLiteral("del"))) { del->setVisible(itemProperties.supportsDeleting()); } if (QAction *cut = m_actionCollection.action(QStringLiteral("cut"))) { cut->setEnabled(itemProperties.supportsDeleting()); cut->setVisible(!isTrash); } if (QAction *paste = m_actionCollection.action(QStringLiteral("paste"))) { bool enable = false; const QString pasteText = KIO::pasteActionText(QApplication::clipboard()->mimeData(), &enable, rootItem()); if (enable) { paste->setText(pasteText); paste->setEnabled(true); } else { paste->setText(i18n("&Paste")); paste->setEnabled(false); } if (QAction *pasteTo = m_actionCollection.action(QStringLiteral("pasteto"))) { pasteTo->setVisible(itemProperties.isDirectory() && itemProperties.supportsWriting()); pasteTo->setEnabled(paste->isEnabled()); pasteTo->setText(paste->text()); } } if (QAction *rename = m_actionCollection.action(QStringLiteral("rename"))) { rename->setEnabled(itemProperties.supportsMoving()); rename->setVisible(!isTrash); } } void FolderModel::openContextMenu(QQuickItem *visualParent, Qt::KeyboardModifiers modifiers) { if (m_usedByContainment && !KAuthorized::authorize(QStringLiteral("action/kdesktop_rmb"))) { return; } updateActions(); const QModelIndexList indexes = m_selectionModel->selectedIndexes(); QMenu *menu = new QMenu(); if (!m_fileItemActions) { m_fileItemActions = new KFileItemActions(this); m_fileItemActions->setParentWidget(QApplication::desktop()); } if (indexes.isEmpty()) { menu->addAction(m_actionCollection.action(QStringLiteral("newMenu"))); menu->addSeparator(); menu->addAction(m_actionCollection.action(QStringLiteral("paste"))); menu->addAction(m_actionCollection.action(QStringLiteral("undo"))); menu->addAction(m_actionCollection.action(QStringLiteral("refresh"))); menu->addAction(m_actionCollection.action(QStringLiteral("emptyTrash"))); menu->addSeparator(); KFileItemListProperties itemProperties(KFileItemList() << rootItem()); m_fileItemActions->setItemListProperties(itemProperties); menu->addAction(m_fileItemActions->preferredOpenWithAction(QString())); } else { KFileItemList items; QList urls; items.reserve(indexes.count()); urls.reserve(indexes.count()); for (const QModelIndex &index : indexes) { KFileItem item = itemForIndex(index); if (!item.isNull()) { items.append(item); urls.append(item.url()); } } KFileItemListProperties itemProperties(items); // Start adding the actions: // "Open" and "Open with" actions m_fileItemActions->setItemListProperties(itemProperties); m_fileItemActions->addOpenWithActionsTo(menu); menu->addSeparator(); menu->addAction(m_actionCollection.action(QStringLiteral("cut"))); menu->addAction(m_actionCollection.action(QStringLiteral("copy"))); menu->addAction(m_actionCollection.action(QStringLiteral("paste"))); menu->addSeparator(); menu->addAction(m_actionCollection.action(QStringLiteral("rename"))); menu->addAction(m_actionCollection.action(QStringLiteral("restoreFromTrash"))); KConfigGroup cg(KSharedConfig::openConfig(), "KDE"); bool showDeleteCommand = cg.readEntry("ShowDeleteCommand", false); menu->addAction(m_actionCollection.action(QStringLiteral("emptyTrash"))); QAction *trashAction = m_actionCollection.action(QStringLiteral("trash")); menu->addAction(trashAction); trashAction->setVisible(!modifiers.testFlag(Qt::ShiftModifier)); QAction *deleteAction = m_actionCollection.action(QStringLiteral("del")); menu->addAction(deleteAction); deleteAction->setVisible(showDeleteCommand || !trashAction->isVisible()); menu->addSeparator(); // Service actions m_fileItemActions->addServiceActionsTo(menu); menu->addSeparator(); // Plugin actions m_fileItemActions->addPluginActionsTo(menu); // Copy To, Move To KSharedConfig::Ptr dolphin = KSharedConfig::openConfig(QStringLiteral("dolphinrc")); if (KConfigGroup(dolphin, "General").readEntry("ShowCopyMoveMenu", false)) { m_copyToMenu->setUrls(urls); m_copyToMenu->setReadOnly(!itemProperties.supportsMoving()); m_copyToMenu->addActionsTo(menu); menu->addSeparator(); } // Properties if (KPropertiesDialog::canDisplay(items)) { menu->addSeparator(); QAction *act = new QAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18n("&Properties"), menu); act->setShortcuts({Qt::ALT + Qt::Key_Return, Qt::ALT + Qt::Key_Enter}); QObject::connect(act, &QAction::triggered, this, &FolderModel::openPropertiesDialog); menu->addAction(act); } } if (visualParent) { m_menuPosition = visualParent->mapToGlobal(QPointF(0, visualParent->height())).toPoint(); } else { m_menuPosition = QCursor::pos(); } // Used to monitor Shift modifier usage while the menu is open, to // swap the Trash and Delete actions. menu->installEventFilter(this); menu->setAttribute(Qt::WA_TranslucentBackground); menu->winId(); //force surface creation before ensurePolish call in menu::Popup which happens before show menu->popup(m_menuPosition); connect(menu, &QMenu::aboutToHide, [menu]() { menu->deleteLater(); }); } void FolderModel::openPropertiesDialog() { const QModelIndexList indexes = m_selectionModel->selectedIndexes(); if (indexes.isEmpty()) { return; } KFileItemList items; items.reserve(indexes.count()); for (const QModelIndex &index : indexes) { KFileItem item = itemForIndex(index); if (!item.isNull()) { items.append(item); } } if (!KPropertiesDialog::canDisplay(items)) { return; } KPropertiesDialog::showDialog(items, nullptr, false /*non modal*/); } void FolderModel::linkHere(const QUrl &sourceUrl) { KIO::CopyJob *job = KIO::link(sourceUrl, m_dirModel->dirLister()->url()); KIO::FileUndoManager::self()->recordCopyJob(job); } QList FolderModel::selectedUrls() const { const auto indexes = m_selectionModel->selectedIndexes(); QList urls; urls.reserve(indexes.count()); for (const QModelIndex &index : indexes) { urls.append(itemForIndex(index).url()); } return urls; } void FolderModel::copy() { if (!m_selectionModel->hasSelection()) { return; } if (QAction *action = m_actionCollection.action(QStringLiteral("copy"))) { if (!action->isEnabled()) { return; } } QMimeData *mimeData = QSortFilterProxyModel::mimeData(m_selectionModel->selectedIndexes()); QApplication::clipboard()->setMimeData(mimeData); } void FolderModel::cut() { if (!m_selectionModel->hasSelection()) { return; } if (QAction *action = m_actionCollection.action(QStringLiteral("cut"))) { if (!action->isEnabled()) { return; } } QMimeData *mimeData = QSortFilterProxyModel::mimeData(m_selectionModel->selectedIndexes()); KIO::setClipboardDataCut(mimeData, true); QApplication::clipboard()->setMimeData(mimeData); } void FolderModel::paste() { if (QAction *action = m_actionCollection.action(QStringLiteral("paste"))) { if (!action->isEnabled()) { return; } } KIO::paste(QApplication::clipboard()->mimeData(), m_dirModel->dirLister()->url()); } void FolderModel::pasteTo() { const QList urls = selectedUrls(); Q_ASSERT(urls.count() == 1); KIO::paste(QApplication::clipboard()->mimeData(), urls.first()); } void FolderModel::refresh() { m_errorString.clear(); emit errorStringChanged(); m_dirModel->dirLister()->updateDirectory(m_dirModel->dirLister()->url()); } QObject *FolderModel::appletInterface() const { return m_appletInterface; } void FolderModel::setAppletInterface(QObject *appletInterface) { if (m_appletInterface != appletInterface) { Q_ASSERT(!m_appletInterface); m_appletInterface = appletInterface; if (appletInterface) { Plasma::Applet *applet = appletInterface->property("_plasma_applet").value(); if (applet) { Plasma::Containment *containment = applet->containment(); if (containment) { Plasma::Corona *corona = containment->corona(); if (corona) { m_screenMapper->setCorona(corona); } setScreen(containment->screen()); connect(containment, &Plasma::Containment::screenChanged, this, &FolderModel::setScreen); } } } emit appletInterfaceChanged(); } } void FolderModel::moveSelectedToTrash() { if (!m_selectionModel->hasSelection()) { return; } if (QAction *action = m_actionCollection.action(QStringLiteral("trash"))) { if (!action->isEnabled()) { return; } } const QList urls = selectedUrls(); KIO::JobUiDelegate uiDelegate; if (uiDelegate.askDeleteConfirmation(urls, KIO::JobUiDelegate::Trash, KIO::JobUiDelegate::DefaultConfirmation)) { KIO::Job* job = KIO::trash(urls); job->uiDelegate()->setAutoErrorHandlingEnabled(true); KIO::FileUndoManager::self()->recordJob(KIO::FileUndoManager::Trash, urls, QUrl(QStringLiteral("trash:/")), job); } } void FolderModel::deleteSelected() { if (!m_selectionModel->hasSelection()) { return; } if (QAction *action = m_actionCollection.action(QStringLiteral("del"))) { if (!action->isEnabled()) { return; } } const QList urls = selectedUrls(); KIO::JobUiDelegate uiDelegate; if (uiDelegate.askDeleteConfirmation(urls, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::DefaultConfirmation)) { KIO::Job* job = KIO::del(urls); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } } void FolderModel::openSelected() { if (!m_selectionModel->hasSelection()) { return; } const QList urls = selectedUrls(); for (const QUrl &url : urls) { (void) new KRun(url, nullptr); } } void FolderModel::undo() { if (QAction *action = m_actionCollection.action(QStringLiteral("undo"))) { // trigger() doesn't check enabled and would crash if invoked nonetheless. if (action->isEnabled()) { action->trigger(); } } } void FolderModel::emptyTrashBin() { KIO::JobUiDelegate uiDelegate; uiDelegate.setWindow(QApplication::desktop()); if (uiDelegate.askDeleteConfirmation(QList(), KIO::JobUiDelegate::EmptyTrash, KIO::JobUiDelegate::DefaultConfirmation)) { KIO::Job* job = KIO::emptyTrash(); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } } void FolderModel::restoreSelectedFromTrash() { if (!m_selectionModel->hasSelection()) { return; } const auto &urls = selectedUrls(); KIO::RestoreJob *job = KIO::restoreFromTrash(urls); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } bool FolderModel::isTrashEmpty() { KConfig trashConfig(QStringLiteral("trashrc"), KConfig::SimpleConfig); return trashConfig.group("Status").readEntry("Empty", true); } void FolderModel::undoTextChanged(const QString &text) { if (QAction *action = m_actionCollection.action(QStringLiteral("undo"))) { action->setText(text); } } diff --git a/containments/desktop/plugins/folder/viewpropertiesmenu.cpp b/containments/desktop/plugins/folder/viewpropertiesmenu.cpp index b89b20706..17a787406 100644 --- a/containments/desktop/plugins/folder/viewpropertiesmenu.cpp +++ b/containments/desktop/plugins/folder/viewpropertiesmenu.cpp @@ -1,286 +1,286 @@ /*************************************************************************** * 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 "viewpropertiesmenu.h" #include #include #include ViewPropertiesMenu::ViewPropertiesMenu(QObject *parent) : QObject(parent) { m_menu = new QMenu(); m_arrangementMenu = m_menu->addMenu(i18n("Arrange In")); m_arrangement = new QActionGroup(this); connect(m_arrangement, &QActionGroup::triggered, this, &ViewPropertiesMenu::arrangementChanged); QAction *action = m_arrangementMenu->addAction(i18n("Rows")); action->setCheckable(true); action->setData(0); m_arrangement->addAction(action); action = m_arrangementMenu->addAction(i18n("Columns")); action->setData(1); action->setCheckable(true); m_arrangement->addAction(action); m_alignmentMenu = m_menu->addMenu(i18n("Align")); m_alignment = new QActionGroup(this); connect(m_alignment, &QActionGroup::triggered, this, &ViewPropertiesMenu::alignmentChanged); action = m_alignmentMenu->addAction(i18n("Left")); action->setCheckable(true); action->setData(0); m_alignment->addAction(action); action = m_alignmentMenu->addAction(i18n("Right")); action->setCheckable(true); action->setData(1); m_alignment->addAction(action); QMenu *menu = m_menu->addMenu(i18n("Sort By")); m_sortMode = new QActionGroup(this); connect(m_sortMode, &QActionGroup::triggered, this, &ViewPropertiesMenu::sortModeChanged); action = menu->addAction(i18n("Unsorted")); action->setCheckable(true); action->setData(-1); m_sortMode->addAction(action); action = menu->addAction(i18n("Name")); action->setCheckable(true); action->setData(int(KDirModel::Name)); m_sortMode->addAction(action); action = menu->addAction(i18n("Size")); action->setCheckable(true); action->setData(int(KDirModel::Size)); m_sortMode->addAction(action); action = menu->addAction(i18n("Type")); action->setCheckable(true); action->setData(int(KDirModel::Type)); m_sortMode->addAction(action); action = menu->addAction(i18n("Date")); action->setCheckable(true); action->setData(int(KDirModel::ModifiedTime)); m_sortMode->addAction(action); menu->addSeparator(); - m_sortDesc = menu->addAction(i18n("Descending"), this, SIGNAL(sortDescChanged())); + m_sortDesc = menu->addAction(i18n("Descending"), this, &ViewPropertiesMenu::sortDescChanged); m_sortDesc->setCheckable(true); - m_sortDirsFirst = menu->addAction(i18n("Folders First"), this, SIGNAL(sortDirsFirstChanged())); + m_sortDirsFirst = menu->addAction(i18n("Folders First"), this, &ViewPropertiesMenu::sortDirsFirstChanged); m_sortDirsFirst->setCheckable(true); m_iconSizeMenu = m_menu->addMenu(i18n("Icon Size")); m_iconSize = new QActionGroup(this); connect(m_iconSize, &QActionGroup::triggered, this, &ViewPropertiesMenu::iconSizeChanged); const QStringList iconSizes{ i18n("Tiny"), i18n("Small"), i18n("Small Medium"), i18n("Medium"), i18n("Large"), i18n("Huge") }; for (int i = 0; i < iconSizes.count(); ++i) { action = m_iconSizeMenu->addAction(iconSizes.at(i)); action->setCheckable(true); action->setData(i); m_iconSize->addAction(action); } m_previews = m_menu->addAction(QIcon::fromTheme(QStringLiteral("view-preview")), i18n("Show Previews"), this, &ViewPropertiesMenu::previewsChanged); m_previews->setCheckable(true); - m_locked = m_menu->addAction(QIcon::fromTheme(QStringLiteral("lock")), i18n("Locked"), this, SIGNAL(lockedChanged())); + m_locked = m_menu->addAction(QIcon::fromTheme(QStringLiteral("lock")), i18n("Locked"), this, &ViewPropertiesMenu::lockedChanged); m_locked->setCheckable(true); } ViewPropertiesMenu::~ViewPropertiesMenu() { delete m_menu; } QObject* ViewPropertiesMenu::menu() const { return m_menu; } bool ViewPropertiesMenu::showLayoutActions() const { return m_alignmentMenu->menuAction()->isVisible() && m_arrangementMenu->menuAction()->isVisible(); } void ViewPropertiesMenu::setShowLayoutActions(bool show) { if (showLayoutActions() != show) { m_arrangementMenu->menuAction()->setVisible(show); m_alignmentMenu->menuAction()->setVisible(show); emit showLayoutActionsChanged(); } } bool ViewPropertiesMenu::showLockAction() const { return m_locked->isVisible(); } void ViewPropertiesMenu::setShowLockAction(bool show) { if (m_locked->isVisible() != show) { m_locked->setVisible(show); emit showLockActionChanged(); } } bool ViewPropertiesMenu::showIconSizeActions() const { return m_iconSizeMenu->menuAction()->isVisible(); } void ViewPropertiesMenu::setShowIconSizeActions(bool show) { if (showIconSizeActions() != show) { m_iconSizeMenu->menuAction()->setVisible(show); emit showIconSizeActionsChanged(); } } int ViewPropertiesMenu::arrangement() const { return m_arrangement->checkedAction()->data().toInt(); } void ViewPropertiesMenu::setArrangement(int arrangement) { if (!m_arrangement->checkedAction() || m_arrangement->checkedAction()->data().toInt() != arrangement) { foreach (QAction *action, m_arrangement->actions()) { if (action->data().toInt() == arrangement) { action->setChecked(true); break; } } } } int ViewPropertiesMenu::alignment() const { return m_alignment->checkedAction()->data().toInt(); } void ViewPropertiesMenu::setAlignment(int alignment) { if (!m_alignment->checkedAction() || m_alignment->checkedAction()->data().toInt() != alignment) { foreach (QAction *action, m_alignment->actions()) { if (action->data().toInt() == alignment) { action->setChecked(true); break; } } } } bool ViewPropertiesMenu::previews() const { return m_previews->isChecked(); } void ViewPropertiesMenu::setPreviews(bool previews) { if (m_previews->isChecked() != previews) { m_previews->setChecked(previews); } } bool ViewPropertiesMenu::locked() const { return m_locked->isChecked(); } void ViewPropertiesMenu::setLocked(bool locked) { if (m_locked->isChecked() != locked) { m_locked->setChecked(locked); } } bool ViewPropertiesMenu::lockedEnabled() const { return m_locked->isEnabled(); } void ViewPropertiesMenu::setLockedEnabled(bool enabled) { if (m_locked->isEnabled() != enabled) { m_locked->setEnabled(enabled); emit lockedEnabledChanged(); } } int ViewPropertiesMenu::sortMode() const { return m_sortMode->checkedAction()->data().toInt(); } void ViewPropertiesMenu::setSortMode(int sortMode) { if (!m_sortMode->checkedAction() || m_sortMode->checkedAction()->data().toInt() != sortMode) { foreach (QAction *action, m_sortMode->actions()) { if (action->data().toInt() == sortMode) { action->setChecked(true); break; } } } } bool ViewPropertiesMenu::sortDesc() const { return m_sortDesc->isChecked(); } void ViewPropertiesMenu::setSortDesc(bool sortDesc) { if (m_sortDesc->isChecked() != sortDesc) { m_sortDesc->setChecked(sortDesc); } } bool ViewPropertiesMenu::sortDirsFirst() const { return m_sortDirsFirst->isChecked(); } void ViewPropertiesMenu::setSortDirsFirst(bool sortDirsFirst) { if (m_sortDirsFirst->isChecked() != sortDirsFirst) { m_sortDirsFirst->setChecked(sortDirsFirst); } } int ViewPropertiesMenu::iconSize() const { return m_iconSize->checkedAction()->data().toInt(); } void ViewPropertiesMenu::setIconSize(int iconSize) { if (!m_iconSize->checkedAction() || m_iconSize->checkedAction()->data().toInt() != iconSize) { QAction *action = m_iconSize->actions().value(iconSize); if (action) { action->setChecked(true); } } } diff --git a/dataengines/kimpanel/kimpanelagent.cpp b/dataengines/kimpanel/kimpanelagent.cpp index b406a9852..80fff54b8 100644 --- a/dataengines/kimpanel/kimpanelagent.cpp +++ b/dataengines/kimpanel/kimpanelagent.cpp @@ -1,297 +1,297 @@ /*************************************************************************** * Copyright (C) 2009 by Wang Hoi * * Copyright (C) 2011 by CSSlayer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "kimpanelagent.h" #include "impaneladaptor.h" // Qt #include #include #include #include #include #include #include #include PanelAgent::PanelAgent(QObject *parent) : QObject(parent) ,adaptor(new ImpanelAdaptor(this)) ,adaptor2(new Impanel2Adaptor(this)) ,watcher(new QDBusServiceWatcher(this)) { watcher->setConnection(QDBusConnection::sessionBus()); watcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); QDBusConnection::connectToBus(QDBusConnection::SessionBus, QStringLiteral("kimpanel_bus")).registerObject(QStringLiteral("/org/kde/impanel"), this); QDBusConnection::connectToBus(QDBusConnection::SessionBus, QStringLiteral("kimpanel_bus")).registerService(QStringLiteral("org.kde.impanel")); // directly connect to corresponding signal QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("Enable"), this, SIGNAL(enable(bool))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ShowPreedit"), this, SIGNAL(showPreedit(bool))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ShowAux"), this, SIGNAL(showAux(bool))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ShowLookupTable"), this, SIGNAL(showLookupTable(bool))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdateLookupTableCursor"), this, SIGNAL(updateLookupTableCursor(int))); // do some serialization QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdateLookupTable"), this, SLOT(UpdateLookupTable(QStringList, QStringList, QStringList, bool, bool))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdatePreeditCaret"), this, SIGNAL(updatePreeditCaret(int))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdatePreeditText"), this, SLOT(UpdatePreeditText(QString, QString))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdateAux"), this, SLOT(UpdateAux(QString, QString))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdateSpotLocation"), this, SIGNAL(updateSpotLocation(int, int))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdateScreen"), this, SLOT(UpdateScreen(int))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdateProperty"), this, SLOT(UpdateProperty(QString))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("RegisterProperties"), this, SLOT(RegisterProperties(QStringList))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ExecDialog"), this, SLOT(ExecDialog(QString))); QDBusConnection(QStringLiteral("kimpanel_bus")).connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ExecMenu"), this, SLOT(ExecMenu(QStringList))); - connect(watcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(serviceUnregistered(QString))); + connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, &PanelAgent::serviceUnregistered); } PanelAgent::~PanelAgent() { // destructor QDBusConnection::disconnectFromBus(QStringLiteral("kimpanel_bus")); } void PanelAgent::serviceUnregistered(const QString& service) { if (service == m_currentService) { watcher->setWatchedServices(QStringList()); cached_props.clear(); m_currentService = QString(); emit showAux(false); emit showPreedit(false); emit showLookupTable(false); emit registerProperties(QList()); } } void PanelAgent::configure() { emit Configure(); } void PanelAgent::lookupTablePageDown() { emit LookupTablePageDown(); } void PanelAgent::lookupTablePageUp() { emit LookupTablePageUp(); } void PanelAgent::movePreeditCaret(int pos) { emit MovePreeditCaret(pos); } void PanelAgent::triggerProperty(const QString& key) { emit TriggerProperty(key); } void PanelAgent::selectCandidate(int idx) { emit SelectCandidate(idx); } static QList String2AttrList(const QString &str) { QList result; if (str.isEmpty()) { return result; } foreach(const QString & s, str.split(QLatin1Char(';'))) { TextAttribute attr; QStringList list = s.split(QLatin1Char(':')); if (list.size() < 4) continue; switch (list.at(0).toInt()) { case 0: attr.type = TextAttribute::None; break; case 1: attr.type = TextAttribute::Decorate; break; case 2: attr.type = TextAttribute::Foreground; break; case 3: attr.type = TextAttribute::Background; break; default: attr.type = TextAttribute::None; } attr.start = list.at(1).toInt(); attr.length = list.at(2).toInt(); attr.value = list.at(3).toInt(); result << attr; } return result; } static KimpanelProperty String2Property(const QString &str) { KimpanelProperty result; QStringList list = str.split(QLatin1Char(':')); if (list.size() < 4) return result; result.key = list.at(0); result.label = list.at(1); result.icon = list.at(2); result.tip = list.at(3); result.hint = list.size() > 4 ? list.at(4) : QString(); return result; } static KimpanelLookupTable Args2LookupTable(const QStringList &labels, const QStringList &candis, const QStringList &attrs, bool has_prev, bool has_next) { Q_ASSERT(labels.size() == candis.size()); Q_ASSERT(labels.size() == attrs.size()); KimpanelLookupTable result; for (int i = 0; i < labels.size(); i++) { KimpanelLookupTable::Entry entry; entry.label = labels.at(i); entry.text = candis.at(i); entry.attr = String2AttrList(attrs.at(i)); result.entries << entry; } result.has_prev = has_prev; result.has_next = has_next; return result; } void PanelAgent::created() { emit PanelCreated(); emit PanelCreated2(); } void PanelAgent::exit() { emit Exit(); } void PanelAgent::reloadConfig() { emit ReloadConfig(); } void PanelAgent::UpdateLookupTable(const QStringList &labels, const QStringList &candis, const QStringList &attrlists, bool has_prev, bool has_next) { emit updateLookupTable(Args2LookupTable(labels, candis, attrlists, has_prev, has_next)); } void PanelAgent::UpdatePreeditText(const QString &text, const QString &attr) { emit updatePreeditText(text, String2AttrList(attr)); } void PanelAgent::UpdateAux(const QString &text, const QString &attr) { emit updateAux(text, String2AttrList(attr)); } void PanelAgent::UpdateScreen(int screen_id) { Q_UNUSED(screen_id); } void PanelAgent::UpdateProperty(const QString &prop) { emit updateProperty(String2Property(prop)); } void PanelAgent::RegisterProperties(const QStringList &props) { const QDBusMessage& msg = message(); if (msg.service() != m_currentService) { watcher->removeWatchedService(m_currentService); if (m_currentService.isEmpty()) { emit PanelRegistered(); } m_currentService = msg.service(); watcher->addWatchedService(m_currentService); } if (cached_props != props) { cached_props = props; QList list; foreach(const QString & prop, props) { list << String2Property(prop); } emit registerProperties(list); } } void PanelAgent::ExecDialog(const QString &prop) { emit execDialog(String2Property(prop)); } void PanelAgent::ExecMenu(const QStringList &entries) { QList list; foreach(const QString & entry, entries) { list << String2Property(entry); } emit execMenu(list); } void PanelAgent::SetSpotRect(int x, int y, int w, int h) { emit updateSpotRect(x, y, w, h); } void PanelAgent::SetLookupTable(const QStringList& labels, const QStringList& candis, const QStringList& attrlists, bool hasPrev, bool hasNext, int cursor, int layout) { emit updateLookupTableFull(Args2LookupTable(labels, candis, attrlists, hasPrev, hasNext), cursor, layout); } diff --git a/dataengines/kimpanel/kimpanelinputpanelcontainer.cpp b/dataengines/kimpanel/kimpanelinputpanelcontainer.cpp index 73a944e0d..de92b3cd1 100644 --- a/dataengines/kimpanel/kimpanelinputpanelcontainer.cpp +++ b/dataengines/kimpanel/kimpanelinputpanelcontainer.cpp @@ -1,136 +1,136 @@ /*************************************************************************** * Copyright (C) 2011 by CSSlayer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "kimpanelinputpanelcontainer.h" #include "kimpanelservice.h" #include "kimpanelagent.h" #include "kimpaneldataengine.h" KimpanelInputPanelContainer::KimpanelInputPanelContainer(QObject* parent, PanelAgent* panelAgent): DataContainer(parent), m_panelAgent(panelAgent) { - connect(m_panelAgent, SIGNAL(updateAux(QString, QList)), this, SLOT(updateAux(QString, QList))); - connect(m_panelAgent, SIGNAL(updatePreeditText(QString, QList)), this, SLOT(updatePreeditText(QString, QList))); - connect(m_panelAgent, SIGNAL(updatePreeditCaret(int)), this, SLOT(updatePreeditCaret(int))); - connect(m_panelAgent, SIGNAL(updateLookupTable(KimpanelLookupTable)), this, SLOT(updateLookupTable(KimpanelLookupTable))); - connect(m_panelAgent, SIGNAL(updateSpotLocation(int,int)), this, SLOT(updateSpotLocation(int,int))); - connect(m_panelAgent, SIGNAL(updateSpotRect(int, int, int, int)), this, SLOT(updateSpotRect(int, int, int, int))); - connect(m_panelAgent, SIGNAL(showAux(bool)), this, SLOT(showAux(bool))); - connect(m_panelAgent, SIGNAL(showPreedit(bool)), this, SLOT(showPreedit(bool))); - connect(m_panelAgent, SIGNAL(showLookupTable(bool)), this, SLOT(showLookupTable(bool))); - connect(m_panelAgent, SIGNAL(updateLookupTableCursor(int)), this, SLOT(updateLookupTableCursor(int))); - connect(m_panelAgent, SIGNAL(updateLookupTableFull(KimpanelLookupTable,int,int)), this, SLOT(updateLookupTableFull(KimpanelLookupTable,int,int))); + connect(m_panelAgent, &PanelAgent::updateAux, this, &KimpanelInputPanelContainer::updateAux); + connect(m_panelAgent, &PanelAgent::updatePreeditText, this, &KimpanelInputPanelContainer::updatePreeditText); + connect(m_panelAgent, &PanelAgent::updatePreeditCaret, this, &KimpanelInputPanelContainer::updatePreeditCaret); + connect(m_panelAgent, &PanelAgent::updateLookupTable, this, &KimpanelInputPanelContainer::updateLookupTable); + connect(m_panelAgent, &PanelAgent::updateSpotLocation, this, &KimpanelInputPanelContainer::updateSpotLocation); + connect(m_panelAgent, &PanelAgent::updateSpotRect, this, &KimpanelInputPanelContainer::updateSpotRect); + connect(m_panelAgent, &PanelAgent::showAux, this, &KimpanelInputPanelContainer::showAux); + connect(m_panelAgent, &PanelAgent::showPreedit, this, &KimpanelInputPanelContainer::showPreedit); + connect(m_panelAgent, &PanelAgent::showLookupTable, this, &KimpanelInputPanelContainer::showLookupTable); + connect(m_panelAgent, &PanelAgent::updateLookupTableCursor, this, &KimpanelInputPanelContainer::updateLookupTableCursor); + connect(m_panelAgent, &PanelAgent::updateLookupTableFull, this, &KimpanelInputPanelContainer::updateLookupTableFull); } Plasma::Service* KimpanelInputPanelContainer::service(QObject* parent) { KimpanelService *controller = new KimpanelService(parent, QLatin1String(INPUTPANEL_SOURCE_NAME), m_panelAgent); - connect(this, SIGNAL(updateRequested(DataContainer*)), - controller, SLOT(enableKimpanelOperations())); + connect(this, &Plasma::DataContainer::updateRequested, + controller, &KimpanelService::enableKimpanelOperations); return controller; } void KimpanelInputPanelContainer::updateAux(const QString& text, const QList< TextAttribute >& attrList) { Q_UNUSED(attrList); setData(QStringLiteral("AuxText"), text); checkForUpdate(); } void KimpanelInputPanelContainer::updatePreeditText(const QString& text, const QList& attrList) { Q_UNUSED(attrList); setData(QStringLiteral("PreeditText"), text); checkForUpdate(); } void KimpanelInputPanelContainer::updatePreeditCaret(int pos) { setData(QStringLiteral("CaretPos"), pos); checkForUpdate(); } void KimpanelInputPanelContainer::updateLookupTable(const KimpanelLookupTable& lookupTable) { QVariantList candidateList; Q_FOREACH(const KimpanelLookupTable::Entry & entry, lookupTable.entries) { QVariantMap map; map[QStringLiteral("label")] = entry.label; map[QStringLiteral("text")] = entry.text; candidateList += map; } setData(QStringLiteral("LookupTable"), candidateList); setData(QStringLiteral("HasPrev"), lookupTable.has_prev); setData(QStringLiteral("HasNext"), lookupTable.has_next); checkForUpdate(); } void KimpanelInputPanelContainer::updateSpotLocation(int x, int y) { updateSpotRect(x, y, 0, 0); } void KimpanelInputPanelContainer::updateSpotRect(int x, int y, int w, int h) { setData(QStringLiteral("Position"), QRect(x, y, w, h)); checkForUpdate(); } void KimpanelInputPanelContainer::showAux(bool visible) { setData(QStringLiteral("AuxVisible"), visible); checkForUpdate(); } void KimpanelInputPanelContainer::showPreedit(bool visible) { setData(QStringLiteral("PreeditVisible"), visible); checkForUpdate(); } void KimpanelInputPanelContainer::showLookupTable(bool visible) { setData(QStringLiteral("LookupTableVisible"), visible); checkForUpdate(); } void KimpanelInputPanelContainer::updateLookupTableCursor(int cursor) { setData(QStringLiteral("LookupTableCursor"), cursor); checkForUpdate(); } void KimpanelInputPanelContainer::updateLookupTableFull(const KimpanelLookupTable& lookupTable, int cursor, int layout) { QVariantList candidateList; Q_FOREACH(const KimpanelLookupTable::Entry & entry, lookupTable.entries) { QVariantMap map; map[QStringLiteral("label")] = entry.label; map[QStringLiteral("text")] = entry.text; candidateList += map; } setData(QStringLiteral("LookupTable"), candidateList); setData(QStringLiteral("HasPrev"), lookupTable.has_prev); setData(QStringLiteral("HasNext"), lookupTable.has_next); setData(QStringLiteral("LookupTableCursor"), cursor); setData(QStringLiteral("LookupTableLayout"), layout); checkForUpdate(); } diff --git a/dataengines/kimpanel/kimpanelstatusbarcontainer.cpp b/dataengines/kimpanel/kimpanelstatusbarcontainer.cpp index ecb0635c6..0308eaeb7 100644 --- a/dataengines/kimpanel/kimpanelstatusbarcontainer.cpp +++ b/dataengines/kimpanel/kimpanelstatusbarcontainer.cpp @@ -1,87 +1,87 @@ /*************************************************************************** * Copyright (C) 2011 by CSSlayer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "kimpanelstatusbarcontainer.h" #include "kimpanelservice.h" #include "kimpanelagent.h" #include "kimpaneldataengine.h" KimpanelStatusBarContainer::KimpanelStatusBarContainer(QObject* parent, PanelAgent* panelAgent): DataContainer(parent), m_panelAgent(panelAgent) { - connect(m_panelAgent, SIGNAL(updateProperty(KimpanelProperty)), this, SLOT(updateProperty(KimpanelProperty))); - connect(m_panelAgent, SIGNAL(registerProperties(QList)), this, SLOT(registerProperties(QList))); - connect(m_panelAgent, SIGNAL(execMenu(QList)), this, SLOT(execMenu(QList))); - connect(m_panelAgent, SIGNAL(execDialog(KimpanelProperty)), this, SLOT(execDialog(KimpanelProperty))); + connect(m_panelAgent, &PanelAgent::updateProperty, this, &KimpanelStatusBarContainer::updateProperty); + connect(m_panelAgent, &PanelAgent::registerProperties, this, &KimpanelStatusBarContainer::registerProperties); + connect(m_panelAgent, &PanelAgent::execMenu, this, &KimpanelStatusBarContainer::execMenu); + connect(m_panelAgent, &PanelAgent::execDialog, this, &KimpanelStatusBarContainer::execDialog); } Plasma::Service* KimpanelStatusBarContainer::service(QObject* parent) { KimpanelService *controller = new KimpanelService(parent, QLatin1String(STATUSBAR_SOURCE_NAME), m_panelAgent); - connect(this, SIGNAL(updateRequested(DataContainer*)), - controller, SLOT(enableKimpanelOperations())); + connect(this, &Plasma::DataContainer::updateRequested, + controller, &KimpanelService::enableKimpanelOperations); return controller; } void KimpanelStatusBarContainer::updateProperty(const KimpanelProperty& property) { int i = 0; for (i = 0; i < m_props.size(); i ++) { if (m_props[i].key == property.key) { m_props[i] = property; QList varList; Q_FOREACH(const KimpanelProperty & prop, m_props) { varList << prop.toMap(); } setData(QStringLiteral("Properties"), varList); checkForUpdate(); break; } } } void KimpanelStatusBarContainer::registerProperties(const QList< KimpanelProperty >& props) { m_props = props; QList varList; Q_FOREACH(const KimpanelProperty & prop, m_props) { varList << prop.toMap(); } setData(QStringLiteral("Properties"), varList); checkForUpdate(); } void KimpanelStatusBarContainer::execMenu(const QList< KimpanelProperty >& props) { QList varList; Q_FOREACH(const KimpanelProperty & prop, props) { varList << prop.toMap(); } QVariantMap map; map[QStringLiteral("props")] = varList; map[QStringLiteral("timestamp")] = QDateTime::currentMSecsSinceEpoch(); setData(QStringLiteral("Menu"), map); checkForUpdate(); } void KimpanelStatusBarContainer::execDialog(const KimpanelProperty& prop) { Q_UNUSED(prop) } diff --git a/kcms/activities/PrivacyTab.cpp b/kcms/activities/PrivacyTab.cpp index c64056af1..3036d97ec 100644 --- a/kcms/activities/PrivacyTab.cpp +++ b/kcms/activities/PrivacyTab.cpp @@ -1,230 +1,230 @@ /* * Copyright (C) 2012 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "PrivacyTab.h" #include #include #include #include #include #include #include #include #include #include "ui_PrivacyTabBase.h" #include "BlacklistedApplicationsModel.h" #include "definitions.h" #include #include "kactivities-kcm-features.h" #include "common/dbus/common.h" #include "utils.h" class PrivacyTab::Private : public Ui::PrivacyTabBase { public: KSharedConfig::Ptr mainConfig; KSharedConfig::Ptr pluginConfig; BlacklistedApplicationsModel *blacklistedApplicationsModel; QObject *viewBlacklistedApplicationsRoot; std::unique_ptr viewBlacklistedApplications; Private() : viewBlacklistedApplicationsRoot(nullptr) , viewBlacklistedApplications(nullptr) { } }; PrivacyTab::PrivacyTab(QWidget *parent) : QWidget(parent) , d() { d->setupUi(this); d->mainConfig = KSharedConfig::openConfig(QStringLiteral("kactivitymanagerdrc")); d->pluginConfig = KSharedConfig::openConfig(QStringLiteral("kactivitymanagerd-pluginsrc")); // Keep history initialization d->spinKeepHistory->setRange(0, INT_MAX); d->spinKeepHistory->setSpecialValueText(i18nc("unlimited number of months", "Forever")); connect(d->spinKeepHistory, SIGNAL(valueChanged(int)), this, SLOT(spinKeepHistoryValueChanged(int))); spinKeepHistoryValueChanged(0); // Clear recent history button auto menu = new QMenu(this); connect(menu->addAction(i18n("Forget the last hour")), &QAction::triggered, this, &PrivacyTab::forgetLastHour); connect(menu->addAction(i18n("Forget the last two hours")), &QAction::triggered, this, &PrivacyTab::forgetTwoHours); connect(menu->addAction(i18n("Forget a day")), &QAction::triggered, this, &PrivacyTab::forgetDay); connect(menu->addAction(i18n("Forget everything")), &QAction::triggered, this, &PrivacyTab::forgetAll); d->buttonClearRecentHistory->setMenu(menu); // Blacklist applications d->blacklistedApplicationsModel = new BlacklistedApplicationsModel(this); new QGridLayout(d->viewBlacklistedApplicationsContainer); d->viewBlacklistedApplications = createView(d->viewBlacklistedApplicationsContainer); d->viewBlacklistedApplications->rootContext()->setContextProperty( QStringLiteral("applicationModel"), d->blacklistedApplicationsModel); setViewSource(d->viewBlacklistedApplications, QStringLiteral("/qml/privacyTab/BlacklistApplicationView.qml")); // React to changes - connect(d->radioRememberAllApplications, SIGNAL(toggled(bool)), this, SIGNAL(changed())); - connect(d->radioDontRememberApplications, SIGNAL(toggled(bool)), this, SIGNAL(changed())); + connect(d->radioRememberAllApplications, &QAbstractButton::toggled, this, &PrivacyTab::changed); + connect(d->radioDontRememberApplications, &QAbstractButton::toggled, this, &PrivacyTab::changed); connect(d->spinKeepHistory, SIGNAL(valueChanged(int)), this, SIGNAL(changed())); - connect(d->blacklistedApplicationsModel, SIGNAL(changed()), this, SIGNAL(changed())); + connect(d->blacklistedApplicationsModel, &BlacklistedApplicationsModel::changed, this, &PrivacyTab::changed); - connect(d->radioRememberSpecificApplications, SIGNAL(toggled(bool)), - d->blacklistedApplicationsModel, SLOT(setEnabled(bool))); + connect(d->radioRememberSpecificApplications, &QAbstractButton::toggled, + d->blacklistedApplicationsModel, &BlacklistedApplicationsModel::setEnabled); - connect(d->radioRememberSpecificApplications, SIGNAL(toggled(bool)), - d->viewBlacklistedApplicationsContainer, SLOT(setEnabled(bool))); + connect(d->radioRememberSpecificApplications, &QAbstractButton::toggled, + d->viewBlacklistedApplicationsContainer, &QWidget::setEnabled); - connect(d->radioRememberSpecificApplications, SIGNAL(toggled(bool)), - d->checkBlacklistAllNotOnList, SLOT(setEnabled(bool))); + connect(d->radioRememberSpecificApplications, &QAbstractButton::toggled, + d->checkBlacklistAllNotOnList, &QWidget::setEnabled); defaults(); d->checkBlacklistAllNotOnList->setEnabled(false); d->blacklistedApplicationsModel->setEnabled(false); d->viewBlacklistedApplicationsContainer->setEnabled(false); d->messageWidget->setVisible(false); } PrivacyTab::~PrivacyTab() { } void PrivacyTab::defaults() { d->radioRememberAllApplications->click(); d->spinKeepHistory->setValue(0); d->blacklistedApplicationsModel->defaults(); } void PrivacyTab::load() { d->blacklistedApplicationsModel->load(); const auto statisticsConfig = d->pluginConfig->group(SQLITE_PLUGIN_CONFIG_KEY); const auto whatToRemember = static_cast(statisticsConfig.readEntry( "what-to-remember", static_cast(AllApplications))); d->radioRememberAllApplications->setChecked(whatToRemember == AllApplications); d->radioRememberSpecificApplications->setChecked(whatToRemember == SpecificApplications); d->radioDontRememberApplications->setChecked(whatToRemember == NoApplications); d->spinKeepHistory->setValue( statisticsConfig.readEntry("keep-history-for", 0)); d->checkBlacklistAllNotOnList->setChecked( statisticsConfig.readEntry("blocked-by-default", false)); } void PrivacyTab::save() { d->blacklistedApplicationsModel->save(); auto statisticsConfig = d->pluginConfig->group(SQLITE_PLUGIN_CONFIG_KEY); const auto whatToRemember = d->radioRememberSpecificApplications->isChecked() ? SpecificApplications : d->radioDontRememberApplications->isChecked() ? NoApplications : /* otherwise */ AllApplications; statisticsConfig.writeEntry("what-to-remember", static_cast(whatToRemember)); statisticsConfig.writeEntry("keep-history-for", d->spinKeepHistory->value()); statisticsConfig.writeEntry("blocked-by-default", d->checkBlacklistAllNotOnList->isChecked()); statisticsConfig.sync(); auto pluginListConfig = d->mainConfig->group("Plugins"); pluginListConfig.writeEntry("org.kde.ActivityManager.ResourceScoringEnabled", whatToRemember != NoApplications); pluginListConfig.sync(); } void PrivacyTab::forget(int count, const QString &what) { KAMD_DBUS_DECL_INTERFACE(rankingsservice, Resources/Scoring, ResourcesScoring); rankingsservice.asyncCall(QStringLiteral("DeleteRecentStats"), QString(), count, what); d->messageWidget->animatedShow(); } void PrivacyTab::forgetLastHour() { forget(1, QStringLiteral("h")); } void PrivacyTab::forgetTwoHours() { forget(2, QStringLiteral("h")); } void PrivacyTab::forgetDay() { forget(1, QStringLiteral("d")); } void PrivacyTab::forgetAll() { forget(0, QStringLiteral("everything")); } void PrivacyTab::spinKeepHistoryValueChanged(int value) { static auto months = ki18ncp("unit of time. months to keep the history", " month", " months"); if (value) { d->spinKeepHistory->setPrefix( i18nc("for in 'keep history for 5 months'", "For ")); d->spinKeepHistory->setSuffix(months.subs(value).toString()); } } diff --git a/kcms/activities/SwitchingTab.cpp b/kcms/activities/SwitchingTab.cpp index 3adc8ad1e..e12edb00b 100644 --- a/kcms/activities/SwitchingTab.cpp +++ b/kcms/activities/SwitchingTab.cpp @@ -1,129 +1,129 @@ /* * Copyright (C) 2012 - 2016 by Ivan Cukic * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "SwitchingTab.h" #include #include #include #include #include "ui_SwitchingTabBase.h" #include #include class SwitchingTab::Private : public Ui::SwitchingTabBase { public: KSharedConfig::Ptr mainConfig; KActionCollection *mainActionCollection; KActivities::Consumer activities; void createAction(const QString &actionName, const QString &actionText, const QList &sequence) { auto action = mainActionCollection->addAction(actionName); action->setProperty("isConfigurationAction", true); action->setText(actionText); KGlobalAccel::self()->setShortcut(action, sequence); } Private() : mainActionCollection(nullptr) { } }; SwitchingTab::SwitchingTab(QWidget *parent) : QWidget(parent) , d() { d->setupUi(this); d->mainConfig = KSharedConfig::openConfig(QStringLiteral("kactivitymanagerdrc")); // Shortcut config. The shortcut belongs to the component "plasmashell"! d->mainActionCollection = new KActionCollection(this, QStringLiteral("plasmashell")); d->mainActionCollection->setComponentDisplayName(i18n("Activity switching")); d->mainActionCollection->setConfigGlobal(true); d->createAction(QStringLiteral("next activity"), i18nc("@action", "Walk through activities"), { Qt::META + Qt::Key_Tab }); d->createAction(QStringLiteral("previous activity"), i18nc("@action", "Walk through activities (Reverse)"), { Qt::META + Qt::SHIFT + Qt::Key_Tab } ); d->scActivities->setActionTypes(KShortcutsEditor::GlobalAction); d->scActivities->addCollection(d->mainActionCollection); connect(d->scActivities, &KShortcutsEditor::keyChange, this, [this] { changed(); }); - connect(d->checkRememberVirtualDesktop, SIGNAL(toggled(bool)), - this, SIGNAL(changed())); + connect(d->checkRememberVirtualDesktop, &QAbstractButton::toggled, + this, &SwitchingTab::changed); defaults(); } SwitchingTab::~SwitchingTab() { } void SwitchingTab::shortcutChanged(const QKeySequence &sequence) { QString actionName = sender() ? sender()->property("shortcutAction").toString() : QString(); if (actionName.isEmpty()) return; auto action = d->mainActionCollection->action(actionName); KGlobalAccel::self()->setShortcut(action, { sequence }, KGlobalAccel::NoAutoloading); d->mainActionCollection->writeSettings(); emit changed(); } void SwitchingTab::defaults() { d->checkRememberVirtualDesktop->setChecked(false); } void SwitchingTab::load() { auto pluginListConfig = d->mainConfig->group("Plugins"); d->checkRememberVirtualDesktop->setChecked(pluginListConfig.readEntry( "org.kde.ActivityManager.VirtualDesktopSwitchEnabled", false)); } void SwitchingTab::save() { auto pluginListConfig = d->mainConfig->group("Plugins"); pluginListConfig.writeEntry( "org.kde.ActivityManager.VirtualDesktopSwitchEnabled", d->checkRememberVirtualDesktop->isChecked()); pluginListConfig.sync(); } diff --git a/kcms/colors/colorsmodel.cpp b/kcms/colors/colorsmodel.cpp index 62371052a..836ca8c16 100644 --- a/kcms/colors/colorsmodel.cpp +++ b/kcms/colors/colorsmodel.cpp @@ -1,242 +1,242 @@ /* * Copyright (C) 2007 Matthew Woehlke * Copyright (C) 2007 Jeremy Whiting * Copyright (C) 2016 Olivier Churlaud * Copyright (C) 2019 Kai Uwe Broulik * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) 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 "colorsmodel.h" #include #include #include #include #include #include #include ColorsModel::ColorsModel(QObject *parent) : QAbstractListModel(parent) { } ColorsModel::~ColorsModel() = default; int ColorsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_data.count(); } QVariant ColorsModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= m_data.count()) { return QVariant(); } const auto &item = m_data.at(index.row()); switch (role) { case Qt::DisplayRole: return item.display; case SchemeNameRole: return item.schemeName; case PaletteRole: return item.palette; case ActiveTitleBarBackgroundRole: return item.activeTitleBarBackground; case ActiveTitleBarForegroundRole: return item.activeTitleBarForeground; case PendingDeletionRole: return item.pendingDeletion; case RemovableRole: return item.removable; } return QVariant(); } bool ColorsModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || index.row() >= m_data.count()) { return false; } if (role == PendingDeletionRole) { auto &item = m_data[index.row()]; const bool pendingDeletion = value.toBool(); if (item.pendingDeletion != pendingDeletion) { item.pendingDeletion = pendingDeletion; emit dataChanged(index, index, {PendingDeletionRole}); // move to the next non-pending theme const auto nonPending = match(index, PendingDeletionRole, false); if (!nonPending.isEmpty()) { setSelectedScheme(nonPending.first().data(SchemeNameRole).toString()); } emit pendingDeletionsChanged(); return true; } } return false; } QHash ColorsModel::roleNames() const { return { {Qt::DisplayRole, QByteArrayLiteral("display")}, {SchemeNameRole, QByteArrayLiteral("schemeName")}, {PaletteRole, QByteArrayLiteral("palette")}, {ActiveTitleBarBackgroundRole, QByteArrayLiteral("activeTitleBarBackground")}, {ActiveTitleBarForegroundRole, QByteArrayLiteral("activeTitleBarForeground")}, {RemovableRole, QByteArrayLiteral("removable")}, {PendingDeletionRole, QByteArrayLiteral("pendingDeletion")} }; } QString ColorsModel::selectedScheme() const { return m_selectedScheme; } void ColorsModel::setSelectedScheme(const QString &scheme) { if (m_selectedScheme == scheme) { return; } const bool firstTime = m_selectedScheme.isNull(); m_selectedScheme = scheme; if (!firstTime) { emit selectedSchemeChanged(scheme); } emit selectedSchemeIndexChanged(); } int ColorsModel::indexOfScheme(const QString &scheme) const { - auto it = std::find_if(m_data.begin(), m_data.end(), [this, &scheme](const ColorsModelData &item) { + auto it = std::find_if(m_data.begin(), m_data.end(), [ &scheme](const ColorsModelData &item) { return item.schemeName == scheme; }); if (it != m_data.end()) { return std::distance(m_data.begin(), it); } return -1; } int ColorsModel::selectedSchemeIndex() const { return indexOfScheme(m_selectedScheme); } void ColorsModel::load() { beginResetModel(); const int oldCount = m_data.count(); m_data.clear(); QStringList schemeFiles; const QStringList schemeDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("color-schemes"), QStandardPaths::LocateDirectory); for (const QString &dir : schemeDirs) { const QStringList fileNames = QDir(dir).entryList(QStringList{QStringLiteral("*.colors")}); for (const QString &file : fileNames) { const QString suffixedFileName = QLatin1String("color-schemes/") + file; // can't use QSet because of the transform below (passing const QString as this argument discards qualifiers) if (!schemeFiles.contains(suffixedFileName)) { schemeFiles.append(suffixedFileName); } } } std::transform(schemeFiles.begin(), schemeFiles.end(), schemeFiles.begin(), [](const QString &item) { return QStandardPaths::locate(QStandardPaths::GenericDataLocation, item); }); for (const QString &schemeFile : schemeFiles) { const QFileInfo fi(schemeFile); const QString baseName = fi.baseName(); KSharedConfigPtr config = KSharedConfig::openConfig(schemeFile, KConfig::SimpleConfig); KConfigGroup group(config, "General"); const QString name = group.readEntry("Name", baseName); const QPalette palette = KColorScheme::createApplicationPalette(config); // from kwin/decorations/decorationpalette.cpp KConfigGroup wmConfig(config, QStringLiteral("WM")); const QColor activeTitleBarBackground = wmConfig.readEntry("activeBackground", palette.color(QPalette::Active, QPalette::Highlight)); const QColor activeTitleBarForeground = wmConfig.readEntry("activeForeground", palette.color(QPalette::Active, QPalette::HighlightedText)); ColorsModelData item{ name, baseName, palette, activeTitleBarBackground, activeTitleBarForeground, fi.isWritable(), false, // pending deletion }; m_data.append(item); } QCollator collator; std::sort(m_data.begin(), m_data.end(), [&collator](const ColorsModelData &a, const ColorsModelData &b) { return collator.compare(a.display, b.display) < 0; }); endResetModel(); // an item might have been added before the currently selected one if (oldCount != m_data.count()) { emit selectedSchemeIndexChanged(); } } QStringList ColorsModel::pendingDeletions() const { QStringList pendingDeletions; for (const auto &item : m_data) { if (item.pendingDeletion) { pendingDeletions.append(item.schemeName); } } return pendingDeletions; } void ColorsModel::removeItemsPendingDeletion() { for (int i = m_data.count() - 1; i >= 0; --i) { if (m_data.at(i).pendingDeletion) { beginRemoveRows(QModelIndex(), i, i); m_data.remove(i); endRemoveRows(); } } } diff --git a/kcms/keys/export_scheme_dialog.cpp b/kcms/keys/export_scheme_dialog.cpp index 0ed5472cd..9b3d84baa 100644 --- a/kcms/keys/export_scheme_dialog.cpp +++ b/kcms/keys/export_scheme_dialog.cpp @@ -1,85 +1,85 @@ /** * 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 "export_scheme_dialog.h" #include #include #include #include #include ExportSchemeDialog::ExportSchemeDialog(QStringList components, QWidget *parent) : QDialog(parent), ui(), mComponents(components) { QWidget *w = new QWidget(this); ui.setupUi(w); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(w); // We allow to check more than one button mButtons.setExclusive(false); // A grid layout for the buttons QGridLayout *vb = new QGridLayout(this); int item=0; Q_FOREACH(QString component, mComponents) { QCheckBox *cb = new QCheckBox(component); vb->addWidget(cb, item / 2, item % 2); mButtons.addButton(cb, item); ++item; } ui.components->setLayout(vb); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); mainLayout->addWidget(buttonBox); } ExportSchemeDialog::~ExportSchemeDialog() {} QStringList ExportSchemeDialog::selectedComponents() const { QStringList rc; Q_FOREACH(QAbstractButton const *button, mButtons.buttons()) { if (button->isChecked()) { // Remove the '&' added by KAcceleratorManager magically rc.append(KLocalizedString::removeAcceleratorMarker(button->text())); } } return rc; } #include "moc_export_scheme_dialog.cpp" diff --git a/kcms/keys/kglobalshortcutseditor.cpp b/kcms/keys/kglobalshortcutseditor.cpp index 8f71d0d4c..2e958f0ea 100644 --- a/kcms/keys/kglobalshortcutseditor.cpp +++ b/kcms/keys/kglobalshortcutseditor.cpp @@ -1,846 +1,846 @@ /* * 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 #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())); + menu->addAction( QIcon::fromTheme(QStringLiteral("document-import")), i18n("Import Scheme..."), q, &KGlobalShortcutsEditor::importScheme); + menu->addAction( QIcon::fromTheme(QStringLiteral("document-export")), i18n("Export Scheme..."), q, &KGlobalShortcutsEditor::exportScheme); + menu->addAction( i18n("Set All Shortcuts to None"), q, &KGlobalShortcutsEditor::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) + QLatin1String("/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 QIcon icon = QIcon::fromTheme(id); if (icon.isNull()) { KService::Ptr service = KService::serviceByStorageId(id); if (service) { icon = QIcon::fromTheme(service->icon()); } } // if NULL icon is returned, use the F.D.O "system-run" icon if (icon.isNull()) { icon = QIcon::fromTheme(QStringLiteral("system-run")); } // Add to the component list QStandardItem *item = new QStandardItem(icon, 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)); const QString name = d->proxyModel->data(d->proxyModel->index(0, 0)).toString(); activateComponent(name); } } void KGlobalShortcutsEditor::clearConfiguration() { const QString name = d->proxyModel->data(d->ui.components->currentIndex()).toString(); d->components[name]->editor()->clearConfiguration(); } void KGlobalShortcutsEditor::defaults(ComponentScope scope) { switch (scope) { case AllComponents: for (ComponentData *cd : qAsConst(d->components)) { // The editors are responsible for the reset cd->editor()->allDefault(); } break; case CurrentComponent: { const 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(); std::sort(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()) { 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 += QLatin1String("|") + 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/Printer.cpp b/kcms/kfontinst/apps/Printer.cpp index 3d1e5f63c..b42b9a842 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())); + connect(thread, &CPrintThread::progress, this, &CPrinter::progress); + connect(thread, &QThread::finished, this, &QDialog::accept); + connect(this, &CPrinter::cancelled, thread, &CPrintThread::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.isEmpty()) { 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.isEmpty()) { CPrinter(createParent(parser.value(embedOption).toInt(nullptr, 16))).print(fonts, size); return 0; } } return -1; } diff --git a/kcms/kfontinst/apps/Viewer.cpp b/kcms/kfontinst/apps/Viewer.cpp index e1920c7d8..b3fcb1ed3 100644 --- a/kcms/kfontinst/apps/Viewer.cpp +++ b/kcms/kfontinst/apps/Viewer.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 "config-workspace.h" #include "Viewer.h" #include "KfiConstants.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KFI { CViewer::CViewer() { KPluginFactory *factory=KPluginLoader("kfontviewpart").factory(); if(factory) { itsPreview=factory->create(this); actionCollection()->addAction(KStandardAction::Open, this, SLOT(fileOpen())); actionCollection()->addAction(KStandardAction::Quit, this, SLOT(close())); actionCollection()->addAction(KStandardAction::KeyBindings, this, SLOT(configureKeys())); itsPrintAct=actionCollection()->addAction(KStandardAction::Print, itsPreview, SLOT(print())); itsPrintAct->setEnabled(false); if(itsPreview->browserExtension()) - connect(itsPreview->browserExtension(), SIGNAL(enableAction(const char*,bool)), - this, SLOT(enableAction(const char*,bool))); + connect(itsPreview->browserExtension(), &KParts::BrowserExtension::enableAction, + this, &CViewer::enableAction); setCentralWidget(itsPreview->widget()); createGUI(itsPreview); setAutoSaveSettings(); applyMainWindowSettings(KSharedConfig::openConfig()->group("MainWindow")); } else exit(0); } void CViewer::fileOpen() { QFileDialog dlg(this, i18n("Select Font to View")); dlg.setFileMode(QFileDialog::ExistingFile); dlg.setMimeTypeFilters(QStringList() << "application/x-font-ttf" << "application/x-font-otf" << "application/x-font-type1" << "application/x-font-bdf" << "application/x-font-pcf"); if (dlg.exec() == QDialog::Accepted) { QUrl url = dlg.selectedUrls().value(0); if (url.isValid()) showUrl(url); } } void CViewer::showUrl(const QUrl &url) { if(url.isValid()) itsPreview->openUrl(url); } void CViewer::configureKeys() { KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this); dlg.addCollection(actionCollection()); dlg.configure(); } void CViewer::enableAction(const char *name, bool enable) { if(0==qstrcmp("print", name)) itsPrintAct->setEnabled(enable); } class ViewerApplication : public QApplication { public: ViewerApplication(int &argc, char **argv) : QApplication(argc, argv) { cmdParser.addVersionOption(); cmdParser.addHelpOption(); cmdParser.addPositionalArgument(QLatin1String("[URL]"), i18n("URL to open")); } QCommandLineParser *parser() { return &cmdParser; } public Q_SLOTS: void activate(const QStringList &args, const QString &workingDirectory) { KFI::CViewer *viewer=new KFI::CViewer; viewer->show(); if (!args.isEmpty()) { cmdParser.process(args); bool first = true; foreach (const QString &arg, cmdParser.positionalArguments()) { QUrl url(QUrl::fromUserInput(arg, workingDirectory)); if (!first) { viewer=new KFI::CViewer; viewer->show(); } viewer->showUrl(url); first = false; } } } private: QCommandLineParser cmdParser; }; } int main(int argc, char **argv) { QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); KFI::ViewerApplication app(argc, argv); KLocalizedString::setApplicationDomain(KFI_CATALOGUE); KAboutData aboutData("kfontview", i18n("Font Viewer"), WORKSPACE_VERSION_STRING, i18n("Simple font viewer"), KAboutLicense::GPL, i18n("(C) Craig Drummond, 2004-2007")); KAboutData::setApplicationData(aboutData); QCommandLineParser *parser = app.parser(); aboutData.setupCommandLine(parser); parser->process(app); aboutData.processCommandLine(parser); KDBusService dbusService(KDBusService::Unique); QGuiApplication::setWindowIcon(QIcon::fromTheme("kfontview")); app.activate(app.arguments(), QDir::currentPath()); QObject::connect(&dbusService, &KDBusService::activateRequested, &app, &KFI::ViewerApplication::activate); return app.exec(); } diff --git a/kcms/kfontinst/dbus/FontInst.cpp b/kcms/kfontinst/dbus/FontInst.cpp index 3d32b173b..21c37b285 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(nullptr) 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, 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())); + connect(itsConnectionsTimer, &QTimer::timeout, this, &FontInst::connectionsTimeout); + connect(itsFontListTimer, &QTimer::timeout, this, &FontInst::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(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*)nullptr); 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/kcmfontinst/ActionLabel.cpp b/kcms/kfontinst/kcmfontinst/ActionLabel.cpp index 37d5c29aa..6bbd74917 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/DuplicatesDialog.cpp b/kcms/kfontinst/kcmfontinst/DuplicatesDialog.cpp index bfeaa597f..32a19418b 100644 --- a/kcms/kfontinst/kcmfontinst/DuplicatesDialog.cpp +++ b/kcms/kfontinst/kcmfontinst/DuplicatesDialog.cpp @@ -1,696 +1,696 @@ /* * 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 "DuplicatesDialog.h" #include "ActionLabel.h" #include "Misc.h" #include "Fc.h" #include "FcEngine.h" #include "FontList.h" #include "JobRunner.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined USE_POLICYKIT && USE_POLICYKIT==1 #include #endif namespace KFI { enum EDialogColumns { COL_FILE, COL_TRASH, COL_SIZE, COL_DATE, COL_LINK }; CDuplicatesDialog::CDuplicatesDialog(QWidget *parent, CFontList *fl) : QDialog(parent), itsFontList(fl) { setWindowTitle(i18n("Duplicate Fonts")); itsButtonBox = new QDialogButtonBox(QDialogButtonBox::Cancel); connect(itsButtonBox, &QDialogButtonBox::clicked, this, &CDuplicatesDialog::slotButtonClicked); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); setModal(true); QFrame *page = new QFrame(this); mainLayout->addWidget(page); mainLayout->addWidget(itsButtonBox); QGridLayout *layout=new QGridLayout(page); layout->setContentsMargins(0, 0, 0, 0); itsLabel=new QLabel(page); itsView=new CFontFileListView(page); itsView->hide(); layout->addWidget(itsActionLabel = new CActionLabel(this), 0, 0); layout->addWidget(itsLabel, 0, 1); itsLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); layout->addWidget(itsView, 1, 0, 1, 2); itsFontFileList=new CFontFileList(this); connect(itsFontFileList, SIGNAL(finished()), SLOT(scanFinished())); - connect(itsView, SIGNAL(haveDeletions(bool)), SLOT(enableButtonOk(bool))); + connect(itsView, &CFontFileListView::haveDeletions, this, &CDuplicatesDialog::enableButtonOk); } int CDuplicatesDialog::exec() { itsActionLabel->startAnimation(); itsLabel->setText(i18n("Scanning for duplicate fonts. Please wait...")); itsFontFileList->start(); return QDialog::exec(); } void CDuplicatesDialog::scanFinished() { itsActionLabel->stopAnimation(); if(itsFontFileList->wasTerminated()) { itsFontFileList->wait(); reject(); } else { CFontFileList::TFontMap duplicates; itsFontFileList->getDuplicateFonts(duplicates); if(0==duplicates.count()) { itsButtonBox->setStandardButtons(QDialogButtonBox::Close); itsLabel->setText(i18n("No duplicate fonts found.")); } else { QSize sizeB4(size()); itsButtonBox->setStandardButtons(QDialogButtonBox::Ok|QDialogButtonBox::Close); QPushButton *okButton = itsButtonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); okButton->setText(i18n("Delete Marked Files")); okButton->setEnabled(false); itsLabel->setText(i18np("%1 duplicate font found.", "%1 duplicate fonts found.", duplicates.count())); itsView->show(); CFontFileList::TFontMap::ConstIterator it(duplicates.begin()), end(duplicates.end()); QFont boldFont(font()); boldFont.setBold(true); for(; it!=end; ++it) { QStringList details; details << FC::createName(it.key().family, it.key().styleInfo); CFontFileListView::StyleItem *top=new CFontFileListView::StyleItem(itsView, details, it.key().family, it.key().styleInfo); QSet::ConstIterator fit((*it).begin()), fend((*it).end()); int tt(0), t1(0); for(; fit!=fend; ++fit) { QFileInfo info(*fit); details.clear(); details.append(*fit); details.append(""); details.append(KFormat().formatByteSize(info.size())); details.append(QLocale().toString(info.created())); if(info.isSymLink()) details.append(info.symLinkTarget()); new QTreeWidgetItem(top, details); if(Misc::checkExt(*fit, "pfa") || Misc::checkExt(*fit, "pfb")) t1++; else tt++; } top->setData(COL_FILE, Qt::DecorationRole, QVariant(SmallIcon(t1>tt ? "application-x-font-type1" : "application-x-font-ttf"))); top->setFont(COL_FILE, boldFont); } QTreeWidgetItem *item= nullptr; for(int i=0; (item=itsView->topLevelItem(i)); ++i) item->setExpanded(true); itsView->setSortingEnabled(true); itsView->header()->resizeSections(QHeaderView::ResizeToContents); int width=(itsView->frameWidth()+8)*2 + style()->pixelMetric(QStyle::PM_LayoutLeftMargin) + style()->pixelMetric(QStyle::PM_LayoutRightMargin); for(int i=0; iheader()->count(); ++i) width+=itsView->header()->sectionSize(i); width=qMin(QApplication::desktop()->screenGeometry(this).width(), width); resize(width, height()); QSize sizeNow(size()); if(sizeNow.width()>sizeB4.width()) { int xmod=(sizeNow.width()-sizeB4.width())/2, ymod=(sizeNow.height()-sizeB4.height())/2; move(pos().x()-xmod, pos().y()-ymod); } } } } enum EStatus { STATUS_NO_FILES, STATUS_ALL_REMOVED, STATUS_ERROR, STATUS_USER_CANCELLED }; void CDuplicatesDialog::slotButtonClicked(QAbstractButton *button) { switch(itsButtonBox->standardButton(button)) { case QDialogButtonBox::Ok: { QSet files=itsView->getMarkedFiles(); int fCount=files.count(); if(1==fCount ? KMessageBox::Yes==KMessageBox::warningYesNo(this, i18n("Are you sure you wish to delete:\n%1", files.toList().first())) : KMessageBox::Yes==KMessageBox::warningYesNoList(this, i18n("Are you sure you wish to delete:"), files.toList())) { itsFontList->setSlowUpdates(true); CJobRunner runner(this); - connect(&runner, SIGNAL(configuring()), itsFontList, SLOT(unsetSlowUpdates())); + connect(&runner, &CJobRunner::configuring, itsFontList, &CFontList::unsetSlowUpdates); runner.exec(CJobRunner::CMD_REMOVE_FILE, itsView->getMarkedItems(), false); itsFontList->setSlowUpdates(false); itsView->removeFiles(); files=itsView->getMarkedFiles(); if(fCount!=files.count()) CFcEngine::setDirty(); if(0==files.count()) accept(); } break; } case QDialogButtonBox::Cancel: case QDialogButtonBox::Close: if(!itsFontFileList->wasTerminated()) { if(itsFontFileList->isRunning()) { if(KMessageBox::Yes==KMessageBox::warningYesNo(this, i18n("Cancel font scan?"))) { itsLabel->setText(i18n("Canceling...")); if(itsFontFileList->isRunning()) itsFontFileList->terminate(); else reject(); } } else reject(); } break; default: break; } } void CDuplicatesDialog::enableButtonOk(bool on) { QPushButton *okButton = itsButtonBox->button(QDialogButtonBox::Ok); if (okButton) okButton->setEnabled(on); } static uint qHash(const CFontFileList::TFile &key) { return qHash(key.name.toLower()); } CFontFileList::CFontFileList(CDuplicatesDialog *parent) : QThread(parent), itsTerminated(false) { } void CFontFileList::start() { if(!isRunning()) { itsTerminated=false; QThread::start(); } } void CFontFileList::terminate() { itsTerminated=true; } void CFontFileList::getDuplicateFonts(TFontMap &map) { map=itsMap; if(!map.isEmpty()) { TFontMap::Iterator it(map.begin()), end(map.end()); // Now re-iterate, and remove any entries that only have 1 file... for(it=map.begin(); it!=end; ) if((*it).count()<2) it=map.erase(it); else ++it; } } void CFontFileList::run() { const QList &families(((CDuplicatesDialog *)parent())->fontList()->families()); QList::ConstIterator it(families.begin()), end(families.end()); for(; it!=end; ++it) { QList::ConstIterator fontIt((*it)->fonts().begin()), fontEnd((*it)->fonts().end()); for(; fontIt!=fontEnd; ++fontIt) if(!(*fontIt)->isBitmap()) { Misc::TFont font((*fontIt)->family(), (*fontIt)->styleInfo()); FileCont::ConstIterator fileIt((*fontIt)->files().begin()), fileEnd((*fontIt)->files().end()); for(; fileIt!=fileEnd; ++fileIt) if(!Misc::isMetrics((*fileIt).path()) && !Misc::isBitmap((*fileIt).path())) itsMap[font].insert((*fileIt).path()); } } // if we have 2 fonts: /wibble/a.ttf and /wibble/a.TTF fontconfig only returns the 1st, so we // now iterate over fontconfig's list, and look for other matching fonts... if(!itsMap.isEmpty() && !itsTerminated) { // Create a map of folder -> set TFontMap::Iterator it(itsMap.begin()), end(itsMap.end()); QHash > folderMap; for(int n=0; it!=end && !itsTerminated; ++it) { QStringList add; QSet::const_iterator fIt((*it).begin()), fEnd((*it).end()); for(; fIt!=fEnd && !itsTerminated; ++fIt, ++n) folderMap[Misc::getDir(*fIt)].insert(TFile(Misc::getFile(*fIt), it)); } // Go through our folder map, and check for file duplicates... QHash >::Iterator folderIt(folderMap.begin()), folderEnd(folderMap.end()); for(; folderIt!=folderEnd && !itsTerminated; ++folderIt) fileDuplicates(folderIt.key(), *folderIt); } emit finished(); } void CFontFileList::fileDuplicates(const QString &folder, const QSet &files) { QDir dir(folder); dir.setFilter(QDir::Files|QDir::Hidden); QFileInfoList list(dir.entryInfoList()); for (int i = 0; i < list.size() && !itsTerminated; ++i) { QFileInfo fileInfo(list.at(i)); // Check if this file is already know about - this will do a case-sensitive comparison if(!files.contains(TFile(fileInfo.fileName()))) { // OK, not found - this means it is a duplicate, but different case. So, find the // FontMap iterator, and update its list of files. QSet::ConstIterator entry=files.find(TFile(fileInfo.fileName(), true)); if(entry!=files.end()) (*((*entry).it)).insert(fileInfo.absoluteFilePath()); } } } inline void markItem(QTreeWidgetItem *item) { item->setData(COL_TRASH, Qt::DecorationRole, QVariant(SmallIcon("list-remove"))); } inline void unmarkItem(QTreeWidgetItem *item) { item->setData(COL_TRASH, Qt::DecorationRole, QVariant()); } inline bool isMarked(QTreeWidgetItem *item) { return item->data(COL_TRASH, Qt::DecorationRole).isValid(); } CFontFileListView::CFontFileListView(QWidget *parent) : QTreeWidget(parent) { QStringList headers; headers.append(i18n("Font/File")); headers.append(""); headers.append(i18n("Size")); headers.append(i18n("Date")); headers.append(i18n("Links To")); setHeaderLabels(headers); headerItem()->setData(COL_TRASH, Qt::DecorationRole, QVariant(SmallIcon("user-trash"))); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); setSelectionMode(ExtendedSelection); sortByColumn(COL_FILE, Qt::AscendingOrder); setSelectionBehavior(SelectRows); setSortingEnabled(true); setAllColumnsShowFocus(true); setAlternatingRowColors(true); itsMenu=new QMenu(this); if(!Misc::app(KFI_VIEWER).isEmpty()) itsMenu->addAction(QIcon::fromTheme("kfontview"), i18n("Open in Font Viewer"), - this, SLOT(openViewer())); + this, &CFontFileListView::openViewer); itsMenu->addAction(QIcon::fromTheme("document-properties"), i18n("Properties"), - this, SLOT(properties())); + this, &CFontFileListView::properties); itsMenu->addSeparator(); itsUnMarkAct=itsMenu->addAction(i18n("Unmark for Deletion"), - this, SLOT(unmark())); + this, &CFontFileListView::unmark); itsMarkAct=itsMenu->addAction(QIcon::fromTheme("edit-delete"), i18n("Mark for Deletion"), - this, SLOT(mark())); + this, &CFontFileListView::mark); connect(this, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged())); connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SLOT(clicked(QTreeWidgetItem*,int))); } QSet CFontFileListView::getMarkedFiles() { QTreeWidgetItem *root=invisibleRootItem(); QSet files; for(int t=0; tchildCount(); ++t) { QList removeFiles; QTreeWidgetItem *font=root->child(t); for(int c=0; cchildCount(); ++c) { QTreeWidgetItem *file=font->child(c); if(isMarked(file)) files.insert(file->text(0)); } } return files; } CJobRunner::ItemList CFontFileListView::getMarkedItems() { QTreeWidgetItem *root=invisibleRootItem(); CJobRunner::ItemList items; QString home(Misc::dirSyntax(QDir::homePath())); for(int t=0; tchildCount(); ++t) { QList removeFiles; StyleItem *style=(StyleItem *)root->child(t); for(int c=0; cchildCount(); ++c) { QTreeWidgetItem *file=style->child(c); if(isMarked(file)) items.append(CJobRunner::Item(file->text(0), style->family(), style->value(), 0!=file->text(0).indexOf(home))); } } return items; } void CFontFileListView::removeFiles() { QTreeWidgetItem *root=invisibleRootItem(); QList removeFonts; for(int t=0; tchildCount(); ++t) { QList removeFiles; QTreeWidgetItem *font=root->child(t); for(int c=0; cchildCount(); ++c) { QTreeWidgetItem *file=font->child(c); if(!Misc::fExists(file->text(0))) removeFiles.append(file); } QList::ConstIterator it(removeFiles.begin()), end(removeFiles.end()); for(; it!=end; ++it) delete (*it); if(0==font->childCount()) removeFonts.append(font); } QList::ConstIterator it(removeFonts.begin()), end(removeFonts.end()); for(; it!=end; ++it) delete (*it); } void CFontFileListView::openViewer() { // Number of fonts user has selected, before we ask if they really want to view them all... static const int constMaxBeforePrompt=10; QList items(selectedItems()); QTreeWidgetItem *item; QSet files; foreach(item, items) if(item->parent()) // Then it is a file, not font name :-) files.insert(item->text(0)); if(!files.isEmpty() && (files.count()::ConstIterator it(files.begin()), end(files.end()); for(; it!=end; ++it) { QStringList args; args << (*it); QProcess::startDetached(Misc::app(KFI_VIEWER), args); } } } void CFontFileListView::properties() { QList items(selectedItems()); QTreeWidgetItem *item; KFileItemList files; QMimeDatabase db; foreach(item, items) if(item->parent()) files.append(KFileItem(QUrl::fromLocalFile(item->text(0)), db.mimeTypeForFile(item->text(0)).name(), item->text(COL_LINK).isEmpty() ? S_IFREG : S_IFLNK)); if(!files.isEmpty()) { KPropertiesDialog dlg(files, this); dlg.exec(); } } void CFontFileListView::mark() { QList items(selectedItems()); QTreeWidgetItem *item; foreach(item, items) if(item->parent()) markItem(item); checkFiles(); } void CFontFileListView::unmark() { QList items(selectedItems()); QTreeWidgetItem *item; foreach(item, items) if(item->parent()) unmarkItem(item); checkFiles(); } void CFontFileListView::selectionChanged() { QList items(selectedItems()); QTreeWidgetItem *item; foreach(item, items) if(!item->parent() && item->isSelected()) item->setSelected(false); } void CFontFileListView::clicked(QTreeWidgetItem *item, int col) { if(item && COL_TRASH==col && item->parent()) { if(isMarked(item)) unmarkItem(item); else markItem(item); checkFiles(); } } void CFontFileListView::contextMenuEvent(QContextMenuEvent *ev) { QTreeWidgetItem *item(itemAt(ev->pos())); if(item && item->parent()) { if(!item->isSelected()) item->setSelected(true); bool haveUnmarked(false), haveMarked(false); QList items(selectedItems()); QTreeWidgetItem *item; foreach(item, items) { if(item->parent() && item->isSelected()) { if(isMarked(item)) haveMarked=true; else haveUnmarked=true; } if(haveUnmarked && haveMarked) break; } itsMarkAct->setEnabled(haveUnmarked); itsUnMarkAct->setEnabled(haveMarked); itsMenu->popup(ev->globalPos()); } } void CFontFileListView::checkFiles() { // Need to check that if we mark a file that is linked to, then we also need // to mark the sym link. QSet marked(getMarkedFiles()); if(marked.count()) { QTreeWidgetItem *root=invisibleRootItem(); for(int t=0; tchildCount(); ++t) { QTreeWidgetItem *font=root->child(t); for(int c=0; cchildCount(); ++c) { QTreeWidgetItem *file=font->child(c); QString link(font->child(c)->text(COL_LINK)); if(!link.isEmpty() && marked.contains(link)) if(!isMarked(file)) markItem(file); } } emit haveDeletions(true); } else emit haveDeletions(false); } } diff --git a/kcms/kfontinst/kcmfontinst/FcQuery.cpp b/kcms/kfontinst/kcmfontinst/FcQuery.cpp index e8d84051c..30676d267 100644 --- a/kcms/kfontinst/kcmfontinst/FcQuery.cpp +++ b/kcms/kfontinst/kcmfontinst/FcQuery.cpp @@ -1,119 +1,119 @@ /* * 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 "FcQuery.h" #include "Fc.h" #include #include namespace KFI { // key: 0(i)(s) static int getInt(const QString &str) { int rv=KFI_NULL_SETTING, start=str.lastIndexOf(':')+1, end=str.lastIndexOf("(i)(s)"); if(end>start) rv=str.mid(start, end-start).trimmed().toInt(); return rv; } CFcQuery::~CFcQuery() { } void CFcQuery::run(const QString &query) { QStringList args; itsFile=itsFont=QString(); itsBuffer=QByteArray(); if(itsProc) itsProc->kill(); else itsProc=new QProcess(this); args << "-v" << query; connect(itsProc, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(procExited())); - connect(itsProc, SIGNAL(readyReadStandardOutput()), SLOT(data())); + connect(itsProc, &QProcess::readyReadStandardOutput, this, &CFcQuery::data); itsProc->start("fc-match", args); } void CFcQuery::procExited() { QString family; int weight(KFI_NULL_SETTING), slant(KFI_NULL_SETTING), width(KFI_NULL_SETTING); QStringList results(QString::fromUtf8(itsBuffer, itsBuffer.length()).split(QLatin1Char('\n'))); if(!results.isEmpty()) { QStringList::ConstIterator it(results.begin()), end(results.end()); for(; it!=end; ++it) { QString line((*it).trimmed()); if(0==line.indexOf("file:")) // file: "Wibble"(s) { int endPos=line.indexOf("\"(s)"); if(-1!=endPos) itsFile=line.mid(7, endPos-7); } else if(0==line.indexOf("family:")) // family: "Wibble"(s) { int endPos=line.indexOf("\"(s)"); if(-1!=endPos) family=line.mid(9, endPos-9); } else if(0==line.indexOf("slant:")) // slant: 0(i)(s) slant=getInt(line); else if(0==line.indexOf("weight:")) // weight: 0(i)(s) weight=getInt(line); else if(0==line.indexOf("width:")) // width: 0(i)(s) width=getInt(line); } } if(!family.isEmpty()) itsFont=FC::createName(family, weight, width, slant); emit finished(); } void CFcQuery::data() { itsBuffer+=itsProc->readAllStandardOutput(); } } diff --git a/kcms/kfontinst/kcmfontinst/FontFilter.cpp b/kcms/kfontinst/kcmfontinst/FontFilter.cpp index 407940152..66bec0ef0 100644 --- a/kcms/kfontinst/kcmfontinst/FontFilter.cpp +++ b/kcms/kfontinst/kcmfontinst/FontFilter.cpp @@ -1,373 +1,373 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2007 Craig Drummond * 2019 Guo Yunhe * * ---- * * 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 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); } std::sort(sorted.begin(), sorted.end()); QList::ConstIterator s(sorted.constBegin()), sEnd(sorted.constEnd()); for(; s!=sEnd; ++s) group->addAction((*s).action); } } CFontFilter::CFontFilter(QWidget *parent) : QWidget(parent) { itsIcons[CRIT_FAMILY] = QIcon::fromTheme("draw-text"); itsTexts[CRIT_FAMILY] = i18n("Family"); itsIcons[CRIT_STYLE] = QIcon::fromTheme("format-text-bold"); itsTexts[CRIT_STYLE] = i18n("Style"); itsIcons[CRIT_FOUNDRY] = QIcon::fromTheme("user-identity"); itsTexts[CRIT_FOUNDRY] = i18n("Foundry"); itsIcons[CRIT_FONTCONFIG] = QIcon::fromTheme("system-search"); itsTexts[CRIT_FONTCONFIG] = i18n("FontConfig Match"); itsIcons[CRIT_FILETYPE] = QIcon::fromTheme("preferences-desktop-font-installer"); itsTexts[CRIT_FILETYPE] = i18n("File Type"); itsIcons[CRIT_FILENAME] = QIcon::fromTheme("application-x-font-type1"); itsTexts[CRIT_FILENAME] = i18n("File Name"); itsIcons[CRIT_LOCATION] = QIcon::fromTheme("folder"); itsTexts[CRIT_LOCATION] = i18n("File Location"); itsIcons[CRIT_WS] = QIcon::fromTheme("character-set"); itsTexts[CRIT_WS] = i18n("Writing System"); m_layout = new QHBoxLayout(this); setLayout(m_layout); m_layout->setContentsMargins(0, 0, 0, 0); m_lineEdit = new QLineEdit(this); m_lineEdit->setClearButtonEnabled(true); m_layout->addWidget(m_lineEdit); m_menuButton = new QPushButton(this); m_menuButton->setIcon(QIcon::fromTheme("view-filter")); m_menuButton->setText(i18n("Set Criteria")); m_layout->addWidget(m_menuButton); - connect(m_lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &))); + connect(m_lineEdit, &QLineEdit::textChanged, this, &CFontFilter::textChanged); m_menu=new QMenu(this); m_menuButton->setMenu(m_menu); itsActionGroup=new QActionGroup(this); addAction(CRIT_FAMILY, true); addAction(CRIT_STYLE, false); KSelectAction *foundryMenu=new KSelectAction(itsIcons[CRIT_FOUNDRY], itsTexts[CRIT_FOUNDRY], this); itsActions[CRIT_FOUNDRY]=foundryMenu; m_menu->addAction(itsActions[CRIT_FOUNDRY]); foundryMenu->setData((int)CRIT_FOUNDRY); foundryMenu->setVisible(false); connect(foundryMenu, SIGNAL(triggered(QString)), SLOT(foundryChanged(QString))); addAction(CRIT_FONTCONFIG, false); KSelectAction *ftMenu=new KSelectAction(itsIcons[CRIT_FILETYPE], itsTexts[CRIT_FILETYPE], this); itsActions[CRIT_FILETYPE]=ftMenu; m_menu->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, false); addAction(CRIT_LOCATION, false); KSelectAction *wsMenu=new KSelectAction(itsIcons[CRIT_WS], itsTexts[CRIT_WS], this); itsActions[CRIT_WS]=wsMenu; m_menu->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, m_menuButton->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.isEmpty()) { // 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()); } } 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]); m_lineEdit->setText(QString()); itsCurrentWs=QFontDatabase::Any; itsCurrentFileTypes.clear(); setCriteria(crit); m_lineEdit->setPlaceholderText(i18n("Filter by %1...", act->text())); m_lineEdit->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; m_lineEdit->setReadOnly(true); setCriteria(itsCurrentCriteria); m_lineEdit->setText(ft); m_lineEdit->setPlaceholderText(m_lineEdit->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; m_lineEdit->setReadOnly(true); setCriteria(itsCurrentCriteria); m_lineEdit->setText(writingSystemName); m_lineEdit->setPlaceholderText(m_lineEdit->text()); } void CFontFilter::foundryChanged(const QString &foundry) { deselectCurrent((KSelectAction *)itsActions[CRIT_WS]); deselectCurrent((KSelectAction *)itsActions[CRIT_FILETYPE]); deselectCurrent(itsActionGroup); itsCurrentCriteria=CRIT_FOUNDRY; m_lineEdit->setReadOnly(true); m_lineEdit->setText(foundry); m_lineEdit->setPlaceholderText(m_lineEdit->text()); setCriteria(itsCurrentCriteria); } void CFontFilter::textChanged(const QString &text) { emit queryChanged(text); } void CFontFilter::addAction(ECriteria crit, bool on) { itsActions[crit]=new KToggleAction(itsIcons[crit], itsTexts[crit], this); m_menu->addAction(itsActions[crit]); itsActionGroup->addAction(itsActions[crit]); itsActions[crit]->setData((int)crit); itsActions[crit]->setChecked(on); if(on) m_lineEdit->setPlaceholderText(i18n("Filter by %1...", itsTexts[crit])); - connect(itsActions[crit], SIGNAL(toggled(bool)), SLOT(filterChanged())); + connect(itsActions[crit], &QAction::toggled, this, &CFontFilter::filterChanged); } void CFontFilter::setCriteria(ECriteria crit) { itsCurrentCriteria=crit; emit criteriaChanged(crit, ((qulonglong)1) << (int)itsCurrentWs, itsCurrentFileTypes); } } diff --git a/kcms/kfontinst/kcmfontinst/FontList.cpp b/kcms/kfontinst/kcmfontinst/FontList.cpp index 588d7100f..dc818308a 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(nullptr), itsStatus(ENABLED), itsRealStatus(ENABLED), 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 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=nullptr; if(update) updateRegularFont(nullptr); } delete font; } void CFamilyItem::refresh() { updateStatus(); 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))); + connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &CFontList::dbusServiceOwnerChanged); + connect(CJobRunner::dbus(), &OrgKdeFontinstInterface::fontsAdded, this, &CFontList::fontsAdded); + connect(CJobRunner::dbus(), &OrgKdeFontinstInterface::fontsRemoved, this, &CFontList::fontsRemoved); + connect(CJobRunner::dbus(), &OrgKdeFontinstInterface::fontList, this, &CFontList::fontList); } 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 QIcon::fromTheme("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; + return it==itsFamilyHash.end() ? nullptr : *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(nullptr), itsFilterCriteria(CFontFilter::CRIT_FAMILY), itsFilterWs(0), 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())); + connect(itsTimer, &QTimer::timeout, this, &CFontListSortFilterProxy::timeout); + connect(model, &QAbstractItemModel::layoutChanged, this, &QSortFilterProxyModel::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 QIcon::fromTheme("dialog-ok"); case CFamilyItem::ENABLED: return QIcon::fromTheme("dialog-ok"); case CFamilyItem::DISABLED: return QIcon::fromTheme("dialog-cancel"); } break; default: break; } } else if(COL_STATUS==index.column()) return QIcon::fromTheme( (static_cast(index.internalPointer()))->isEnabled() ? "dialog-ok" : "dialog-cancel"); 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())) invalidate(); } } 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.truncate(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())); + connect(itsFcQuery, &CFcQuery::finished, this, &CFontListSortFilterProxy::fcResults); } itsFcQuery->run(query); } else { invalidate(); emit refresh(); } } void CFontListSortFilterProxy::fcResults() { if(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria) { invalidate(); 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()->setSectionResizeMode(COL_STATUS, QHeaderView::Fixed); header()->setSectionResizeMode(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()->setSectionsClickable(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))); + connect(this, &QTreeView::collapsed, this, &CFontListView::itemCollapsed); + connect(header(), &QHeaderView::sectionClicked, this, &CFontListView::setSortColumn); + connect(itsProxy, &CFontListSortFilterProxy::refresh, this, &CFontListView::refresh); + connect(itsModel, &CFontList::listingPercent, this, &CFontListView::listingPercent); setWhatsThis(model->whatsThis()); header()->setWhatsThis(whatsThis()); itsMenu=new QMenu(this); itsDeleteAct=itsMenu->addAction(QIcon::fromTheme("edit-delete"), i18n("Delete"), - this, SIGNAL(del())); + this, &CFontListView::del); itsMenu->addSeparator(); itsEnableAct=itsMenu->addAction(QIcon::fromTheme("font-enable"), i18n("Enable"), - this, SIGNAL(enable())); + this, &CFontListView::enable); itsDisableAct=itsMenu->addAction(QIcon::fromTheme("font-disable"), i18n("Disable"), - this, SIGNAL(disable())); + this, &CFontListView::disable); if(!Misc::app(KFI_VIEWER).isEmpty()) itsMenu->addSeparator(); itsPrintAct=Misc::app(KFI_VIEWER).isEmpty() ? nullptr : itsMenu->addAction(QIcon::fromTheme("document-print"), i18n("Print..."), - this, SIGNAL(print())); + this, &CFontListView::print); itsViewAct=Misc::app(KFI_VIEWER).isEmpty() ? nullptr : itsMenu->addAction(QIcon::fromTheme("kfontview"), i18n("Open in Font Viewer"), - this, SLOT(view())); + this, &CFontListView::view); itsMenu->addSeparator(); - itsMenu->addAction(QIcon::fromTheme("view-refresh"), i18n("Reload"), model, SLOT(load())); + itsMenu->addAction(QIcon::fromTheme("view-refresh"), i18n("Reload"), model, &CFontList::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=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->invalidate(); } } 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.isEmpty()) 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/GroupList.cpp b/kcms/kfontinst/kcmfontinst/GroupList.cpp index 1e201fc83..9d8d3d532 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.isEmpty()) { 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 QIcon::fromTheme("list-remove"); case CGroupListItem::PERSONAL: // Copying/moving case CGroupListItem::SYSTEM: // Copying/moving return QIcon::fromTheme(Qt::LeftToRight==QApplication::layoutDirection() ? "go-next" : "go-previous"); case CGroupListItem::CUSTOM: // Adding to a group return QIcon::fromTheme("list-add"); default: break; } else switch(grp->type()) { case CGroupListItem::ALL: return QIcon::fromTheme("font"); case CGroupListItem::PERSONAL: return QIcon::fromTheme("user-identity"); case CGroupListItem::SYSTEM: return QIcon::fromTheme("computer"); case CGroupListItem::UNCLASSIFIED: return QIcon::fromTheme("fontstatus"); case CGroupListItem::CUSTOM: if(0==grp->families().count()) return QIcon::fromTheme("image-missing"); switch(grp->status()) { case CFamilyItem::PARTIAL: return QIcon::fromTheme("dialog-ok"); case CFamilyItem::ENABLED: return QIcon::fromTheme("dialog-ok"); case CFamilyItem::DISABLED: return QIcon::fromTheme("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, 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::Continue==KMessageBox::warningContinueCancel(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; std::sort(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 nullptr; } bool CGroupList::exists(const QString &name, bool showDialog) { 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())); + this, &CGroupListView::del); itsMenu->addSeparator(); itsEnableAct=itsMenu->addAction(QIcon::fromTheme("font-enable"), i18n("Enable"), - this, SIGNAL(enable())); + this, &CGroupListView::enable); itsDisableAct=itsMenu->addAction(QIcon::fromTheme("font-disable"), i18n("Disable"), - this, SIGNAL(disable())); + this, &CGroupListView::disable); itsMenu->addSeparator(); itsRenameAct=itsMenu->addAction(QIcon::fromTheme("edit-rename"), i18n("Rename..."), - this, SLOT(rename())); + this, &CGroupListView::rename); if(!Misc::app(KFI_PRINTER).isEmpty()) { itsMenu->addSeparator(); itsPrintAct=itsMenu->addAction(QIcon::fromTheme("document-print"), i18n("Print..."), - this, SIGNAL(print())); + this, &CGroupListView::print); } else itsPrintAct= nullptr; itsMenu->addSeparator(); itsExportAct=itsMenu->addAction(QIcon::fromTheme("document-export"), i18n("Export..."), - this, SIGNAL(zip())); + this, &CGroupListView::zip); setWhatsThis(model->whatsThis()); header()->setWhatsThis(whatsThis()); - connect(this, SIGNAL(addFamilies(QModelIndex,QSet)), - model, SLOT(addToGroup(QModelIndex,QSet))); + connect(this, &CGroupListView::addFamilies, + model, &CGroupList::addToGroup); connect(this, SIGNAL(removeFamilies(QModelIndex,QSet)), model, SLOT(removeFromGroup(QModelIndex,QSet))); } CGroupListItem::EType CGroupListView::getType() { QModelIndexList selectedItems(selectedIndexes()); if(!selectedItems.isEmpty() && 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())); + QTimer::singleShot(0, this, &CGroupListView::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 29082ad9d..a867c01c0 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") == QLatin1String("true")); } QUrl CJobRunner::encode(const QString &family, quint32 style, bool system) { QUrl url(FC::encode(family, style)); url.addQueryItem("sys", system ? "true" : "false"); return url; } enum EPages { PAGE_PROGRESS, PAGE_SKIP, PAGE_ERROR, PAGE_CANCEL, PAGE_COMPLETE }; enum Response { RESP_CONTINUE, RESP_AUTO, RESP_CANCEL }; static void addIcon(QGridLayout *layout, QFrame *page, const char *iconName, int iconSize) { QLabel *icon=new QLabel(page); icon->setPixmap(QIcon::fromTheme(iconName).pixmap(iconSize)); icon->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); layout->addWidget(icon, 0, 0); } CJobRunner::CJobRunner(QWidget *parent, int xid) : QDialog(parent), itsIt(itsUrls.end()), itsEnd(itsIt), itsAutoSkip(false), itsCancelClicked(false), itsModified(false), itsTempDir(nullptr) { setModal(true); if(nullptr==parent && 0!=xid) XSetTransientForHint(QX11Info::display(), winId(), xid); itsButtonBox = new QDialogButtonBox; connect(itsButtonBox, &QDialogButtonBox::clicked, this, &CJobRunner::slotButtonClicked); itsSkipButton = new QPushButton(i18n("Skip")); itsButtonBox->addButton(itsSkipButton, QDialogButtonBox::ActionRole); itsSkipButton->hide(); itsAutoSkipButton = new QPushButton(i18n("AutoSkip")); itsButtonBox->addButton(itsAutoSkipButton, QDialogButtonBox::ActionRole); itsAutoSkipButton->hide(); itsStack = new QStackedWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(itsStack); mainLayout->addWidget(itsButtonBox); QStyleOption option; option.initFrom(this); int iconSize=style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, this); QFrame *page = new QFrame(itsStack); QGridLayout *layout=new QGridLayout(page); itsStatusLabel=new QLabel(page); itsProgress=new QProgressBar(page); // itsStatusLabel->setWordWrap(true); layout->addWidget(itsActionLabel = new CActionLabel(this), 0, 0, 2, 1); layout->addWidget(itsStatusLabel, 0, 1); layout->addWidget(itsProgress, 1, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 2, 0); itsStack->insertWidget(PAGE_PROGRESS, page); page=new QFrame(itsStack); layout=new QGridLayout(page); itsSkipLabel=new QLabel(page); itsSkipLabel->setWordWrap(true); addIcon(layout, page, "dialog-error", iconSize); layout->addWidget(itsSkipLabel, 0, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0); itsStack->insertWidget(PAGE_SKIP, page); page=new QFrame(itsStack); layout=new QGridLayout(page); itsErrorLabel=new QLabel(page); itsErrorLabel->setWordWrap(true); addIcon(layout, page, "dialog-error", iconSize); layout->addWidget(itsErrorLabel, 0, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0); itsStack->insertWidget(PAGE_ERROR, page); page=new QFrame(itsStack); layout=new QGridLayout(page); QLabel *cancelLabel=new QLabel(i18n("

    Cancel?

    Are you sure you wish to cancel?

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

    Finished

    " "

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

    "), page); finishedLabel->setWordWrap(true); addIcon(layout, page, "dialog-information", iconSize); layout->addWidget(finishedLabel, 0, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0); itsDontShowFinishedMsg = new QCheckBox(i18n("Do not show this message again"), page); itsDontShowFinishedMsg->setChecked(false); layout->addItem(new QSpacerItem(0, layout->spacing(), QSizePolicy::Fixed, QSizePolicy::Fixed), 2, 0); layout->addWidget(itsDontShowFinishedMsg, 3, 1); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 4, 0); itsStack->insertWidget(PAGE_COMPLETE, page); } QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this); - connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), SLOT(dbusServiceOwnerChanged(QString,QString,QString))); - connect(dbus(), SIGNAL(status(int,int)), SLOT(dbusStatus(int,int))); + connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &CJobRunner::dbusServiceOwnerChanged); + connect(dbus(), &OrgKdeFontinstInterface::status, this, &CJobRunner::dbusStatus); setMinimumSize(420, 160); } CJobRunner::~CJobRunner() { delete itsTempDir; } void CJobRunner::getAssociatedUrls(const QUrl &url, QList &list, bool afmAndPfm, QWidget *widget) { QString ext(url.path()); int dotPos(ext.lastIndexOf('.')); bool check(false); if(-1==dotPos) // Hmm, no extension - check anyway... check=true; else // Cool, got an extension - see if it is a Type1 font... { ext=ext.mid(dotPos+1); check=0==ext.compare("pfa", Qt::CaseInsensitive) || 0==ext.compare("pfb", Qt::CaseInsensitive); } if(check) { const char *afm[]={"afm", "AFM", "Afm", nullptr}, *pfm[]={"pfm", "PFM", "Pfm", nullptr}; bool gotAfm(false), localFile(url.isLocalFile()); int e; for(e=0; afm[e]; ++e) { QUrl statUrl(url); statUrl.setPath(Misc::changeExt(url.path(), afm[e])); bool urlExists = false; if (localFile) { urlExists = Misc::fExists(statUrl.toLocalFile()); } else { auto job = KIO::stat(statUrl); KJobWidgets::setWindow(job, widget); job->exec(); urlExists = !job->error(); } if (urlExists) { list.append(statUrl); gotAfm=true; break; } } if(afmAndPfm || !gotAfm) for(e=0; pfm[e]; ++e) { QUrl statUrl(url); statUrl.setPath(Misc::changeExt(url.path(), pfm[e])); bool urlExists = false; if (localFile) { urlExists = Misc::fExists(statUrl.toLocalFile()); } else { auto job = KIO::stat(statUrl); KJobWidgets::setWindow(job, widget); job->exec(); urlExists = !job->error(); } if (urlExists) { list.append(statUrl); break; } } } } static void addEnableActions(CJobRunner::ItemList &urls) { CJobRunner::ItemList modified; CJobRunner::ItemList::ConstIterator it(urls.constBegin()), end(urls.constEnd()); for(; it!=end; ++it) { if((*it).isDisabled) { CJobRunner::Item item(*it); item.fileName=QLatin1String("--"); modified.append(item); } modified.append(*it); } urls=modified; } int CJobRunner::exec(ECommand cmd, const ItemList &urls, bool destIsSystem) { itsAutoSkip=itsCancelClicked=itsModified=false; switch(cmd) { case CMD_INSTALL: setWindowTitle(i18n("Installing")); break; case CMD_DELETE: setWindowTitle(i18n("Uninstalling")); break; case CMD_ENABLE: setWindowTitle(i18n("Enabling")); break; case CMD_MOVE: setWindowTitle(i18n("Moving")); break; case CMD_UPDATE: setWindowTitle(i18n("Updating")); itsModified=true; break; case CMD_REMOVE_FILE: setWindowTitle(i18n("Removing")); break; default: case CMD_DISABLE: setWindowTitle(i18n("Disabling")); } itsDestIsSystem=destIsSystem; itsUrls=urls; if(CMD_INSTALL==cmd) std::sort(itsUrls.begin(), itsUrls.end()); // Sort list of fonts so that we have type1 fonts followed by their metrics... else if(CMD_MOVE==cmd) addEnableActions(itsUrls); itsIt=itsUrls.constBegin(); itsEnd=itsUrls.constEnd(); itsPrev=itsEnd; itsProgress->setValue(0); itsProgress->setRange(0, itsUrls.count()+1); itsProgress->show(); itsCmd=cmd; itsCurrentFile=QString(); itsStatusLabel->setText(QString()); setPage(PAGE_PROGRESS); - QTimer::singleShot(0, this, SLOT(doNext())); - QTimer::singleShot(constInterfaceCheck, this, SLOT(checkInterface())); + QTimer::singleShot(0, this, &CJobRunner::doNext); + QTimer::singleShot(constInterfaceCheck, this, &CJobRunner::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.truncate(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("Font Management"), 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::Preferred, QSizePolicy::Expanding); QWidget *groupWidget=new QWidget(itsGroupSplitter), *fontWidget=new QWidget(itsGroupSplitter); itsPreviewSplitter=new QSplitter(fontWidget); itsPreviewSplitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); QWidget *fontControlWidget=new QWidget(fontWidget); QGridLayout *groupsLayout=new QGridLayout(groupWidget); QBoxLayout *mainLayout=new QBoxLayout(QBoxLayout::TopToBottom, this), *fontsLayout=new QBoxLayout(QBoxLayout::TopToBottom, fontWidget), *fontControlLayout=new QBoxLayout(QBoxLayout::LeftToRight, fontControlWidget); mainLayout->setContentsMargins(0, 0, 0, 0); groupsLayout->setContentsMargins(0, 0, 0, 0); fontsLayout->setContentsMargins(0, 0, 0, 0); fontControlLayout->setContentsMargins(0, 0, 0, 0); itsFilter=new CFontFilter(this); // Details - Groups... itsGroupList=new CGroupList(groupWidget); itsGroupListView=new CGroupListView(groupWidget, itsGroupList); QPushButton *createGroup=new CPushButton(KGuiItem(QString(), "list-add", i18n("Create New Group...")), groupWidget); itsDeleteGroupControl=new CPushButton(KGuiItem(QString(), "list-remove", i18n("Remove Group...")), groupWidget); itsEnableGroupControl=new CPushButton(KGuiItem(QString(), "font-enable", i18n("Enable Fonts in Group...")), groupWidget); itsDisableGroupControl=new CPushButton(KGuiItem(QString(), "font-disable", i18n("Disable Fonts in 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->setContentsMargins(0, 0, 0, 0); previewWidgetLayout->setSpacing(0); // Preview QFrame *previewFrame=new QFrame(itsPreviewWidget); QBoxLayout *previewFrameLayout=new QBoxLayout(QBoxLayout::LeftToRight, previewFrame); previewFrameLayout->setContentsMargins(0, 0, 0, 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); itsScanDuplicateFontsControl=new CPushButton(KGuiItem(i18n("Find Duplicates..."), "edit-duplicate", i18n("Scan for Duplicate Fonts...")), fontControlWidget); 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(QString(), "edit-delete", i18n("Delete Selected Fonts...")), fontControlWidget); itsPreviewSplitter->addWidget(itsPreviewWidget); itsPreviewSplitter->setCollapsible(1, true); QWidget *statusRow = new QWidget(this); QBoxLayout *statusRowLayout=new QBoxLayout(QBoxLayout::LeftToRight, statusRow); itsStatusLabel = new QLabel(statusRow); itsStatusLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight); itsListingProgress=new CProgressBar(statusRow, itsStatusLabel->height()); itsListingProgress->setRange(0, 100); statusRowLayout->addWidget(itsListingProgress); statusRowLayout->addWidget(itsStatusLabel); // Layout widgets... mainLayout->addWidget(itsFilter); mainLayout->addWidget(itsGroupSplitter); mainLayout->addWidget(statusRow); fontControlLayout->addWidget(itsDeleteFontControl); fontControlLayout->addStretch(); fontControlLayout->addWidget(itsScanDuplicateFontsControl); 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(queryChanged(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(itsPreview, &CFontPreview::atMax, zoomIn, &QAction::setDisabled); + connect(itsPreview, &CFontPreview::atMin, zoomOut, &QAction::setDisabled); + connect(prevSel, &CPreviewSelectAction::range, + itsPreview, &CFontPreview::setUnicodeRange); + connect(changeTextAct, &QAction::triggered, this, &CKCmFontInst::changeText); + connect(itsFilter, &CFontFilter::queryChanged, itsFontListView, &CFontListView::filterText); + connect(itsFilter, &CFontFilter::criteriaChanged, + itsFontListView, &CFontListView::filterCriteria); + connect(itsGroupListView, &CGroupListView::del, this, &CKCmFontInst::removeGroup); + connect(itsGroupListView, &CGroupListView::print, this, &CKCmFontInst::printGroup); + connect(itsGroupListView, &CGroupListView::enable, this, &CKCmFontInst::enableGroup); + connect(itsGroupListView, &CGroupListView::disable, this, &CKCmFontInst::disableGroup); + connect(itsGroupListView, &CGroupListView::moveFonts, this, &CKCmFontInst::moveFonts); + connect(itsGroupListView, &CGroupListView::zip, this, &CKCmFontInst::zipGroup); + connect(itsGroupListView, &CGroupListView::itemSelected, + this, &CKCmFontInst::groupSelected); + connect(itsGroupListView, &CGroupListView::info, + this, &CKCmFontInst::showInfo); + connect(itsGroupList, &CGroupList::refresh, this, &CKCmFontInst::refreshFontList); + connect(itsFontList, &CFontList::listingPercent, this, &CKCmFontInst::listingPercent); + connect(itsFontList, &QAbstractItemModel::layoutChanged, this, &CKCmFontInst::setStatusBar); + connect(itsFontListView, &CFontListView::del, this, &CKCmFontInst::deleteFonts); connect(itsFontListView, SIGNAL(print()), SLOT(print())); - connect(itsFontListView, SIGNAL(enable()), SLOT(enableFonts())); - connect(itsFontListView, SIGNAL(disable()), SLOT(disableFonts())); + connect(itsFontListView, &CFontListView::enable, this, &CKCmFontInst::enableFonts); + connect(itsFontListView, &CFontListView::disable, this, &CKCmFontInst::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(itsFontListView, &CFontListView::itemsSelected, this, &CKCmFontInst::fontsSelected); + connect(itsFontListView, &CFontListView::refresh, this, &CKCmFontInst::setStatusBar); + connect(itsGroupListView, &CGroupListView::unclassifiedChanged, itsFontListView, &CFontListView::refreshFilter); + connect(createGroup, &QAbstractButton::clicked, this, &CKCmFontInst::addGroup); + connect(itsDeleteGroupControl, &QAbstractButton::clicked, this, &CKCmFontInst::removeGroup); + connect(itsEnableGroupControl, &QAbstractButton::clicked, this, &CKCmFontInst::enableGroup); + connect(itsDisableGroupControl, &QAbstractButton::clicked, this, &CKCmFontInst::disableGroup); connect(itsAddFontControl, SIGNAL(clicked()), SLOT(addFonts())); - connect(itsGetNewFontsControl, SIGNAL(clicked()), SLOT(downloadFonts())); - connect(itsDeleteFontControl, SIGNAL(clicked()), SLOT(deleteFonts())); - connect(itsScanDuplicateFontsControl, SIGNAL(clicked()), SLOT(duplicateFonts())); + connect(itsGetNewFontsControl, &QAbstractButton::clicked, this, &CKCmFontInst::downloadFonts); + connect(itsDeleteFontControl, &QAbstractButton::clicked, this, &CKCmFontInst::deleteFonts); + connect(itsScanDuplicateFontsControl, &QAbstractButton::clicked, this, &CKCmFontInst::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())); + connect(itsPreview, &QWidget::customContextMenuRequested, this, &CKCmFontInst::previewMenu); + connect(itsPreviewList, &CPreviewListView::showMenu, this, &CKCmFontInst::previewMenu); + connect(itsPreviewSplitter, &QSplitter::splitterMoved, this, &CKCmFontInst::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.isEmpty()) { 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.isEmpty()) { 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.isEmpty()) addFonts(urls); delete itsTempDir; itsTempDir=nullptr; } } void CKCmFontInst::groupSelected(const QModelIndex &index) { 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.isEmpty()) { 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::Continue==KMessageBox::warningContinueCancel(this, i18n("

    Do you really want to " "delete

    \'%1\'?

    ", fontNames.first()), i18n("Delete Font"), KStandardGuiItem::del()); break; default: doIt = KMessageBox::Continue==KMessageBox::warningContinueCancelList(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, 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::Continue==KMessageBox::warningContinueCancel(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::Continue==KMessageBox::warningContinueCancelList(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.isEmpty()) { 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("Name of 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().isEmpty()) // 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.isEmpty() && !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(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.isEmpty()) { 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, 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::Continue==KMessageBox::warningContinueCancel(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"), "font-enable", i18n("Enable Font")) : KGuiItem(i18n("Disable"), "font-disable", i18n("Disable Font"))); break; default: doIt = KMessageBox::Continue==KMessageBox::warningContinueCancelList(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"), "font-enable", i18n("Enable Fonts")) : KGuiItem(i18n("Disable"), "font-disable", 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())); + connect(&runner, &CJobRunner::configuring, itsFontList, &CFontList::unsetSlowUpdates); runner.exec(cmd, urls, system); itsFontList->setSlowUpdates(false); refreshFontList(); if(CJobRunner::CMD_DELETE==cmd) itsFontListView->clearSelection(); CFcEngine::setDirty(); setStatusBar(); delete itsTempDir; itsTempDir=nullptr; itsFontListView->repaint(); removeDeletedFontsFromGroups(); } } #include "KCmFontInst.moc" diff --git a/kcms/kfontinst/kio/FontInstInterface.cpp b/kcms/kfontinst/kio/FontInstInterface.cpp index 6f3ce70a2..7ed6d4456 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(), 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))); + connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &FontInstInterface::dbusServiceOwnerChanged); + connect(itsInterface, &OrgKdeFontinstInterface::status, this, &FontInstInterface::status); + connect(itsInterface, &OrgKdeFontinstInterface::fontList, this, &FontInstInterface::fontList); + connect(itsInterface, &OrgKdeFontinstInterface::fontStat, this, &FontInstInterface::fontStat); 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/viewpart/CharTip.cpp b/kcms/kfontinst/viewpart/CharTip.cpp index 1712b5e63..c1064bc34 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(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->setContentsMargins(8, 8, 8, 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())); + connect(itsTimer, &QTimer::timeout, this, &CCharTip::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, nullptr); if(!img.isNull()) itsPixmapLabel->setPixmap(QPixmap::fromImage(img)); else itsPixmapLabel->setPixmap(QPixmap()); itsTimer->disconnect(this); - connect(itsTimer, SIGNAL(timeout()), this, SLOT(hideTip())); + connect(itsTimer, &QTimer::timeout, this, &CCharTip::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/FontViewPart.cpp b/kcms/kfontinst/viewpart/FontViewPart.cpp index d56032da1..d8ac65a70 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(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->setContentsMargins(0, 0, 0, 0); previewLayout->setSpacing(0); faceLayout->setContentsMargins(0, 0, 0, 0); controlsLayout->setContentsMargins(0, 0, 0, 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(itsPreview, &CFontPreview::status, this, &CFontViewPart::previewStatus); + connect(itsInstallButton, &QAbstractButton::clicked, this, &CFontViewPart::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())); + connect(itsChangeTextAction, &QAction::triggered, this, &CFontViewPart::changeText); CPreviewSelectAction *displayTypeAction=new CPreviewSelectAction(this, CPreviewSelectAction::BlocksAndScripts); actionCollection()->addAction("displayType", displayTypeAction); - connect(displayTypeAction, SIGNAL(range(QList)), - SLOT(displayType(QList))); + connect(displayTypeAction, &CPreviewSelectAction::range, + this, &CFontViewPart::displayType); 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))); + connect(itsPreview, &CFontPreview::atMax, zoomIn, &QAction::setDisabled); + connect(itsPreview, &CFontPreview::atMin, zoomOut, &QAction::setDisabled); 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))); + connect(itsInterface, &OrgKdeFontinstInterface::status, this, &CFontViewPart::dbusStatus); + connect(itsInterface, &OrgKdeFontinstInterface::fontStat, this, &CFontViewPart::fontStat); } CFontViewPart::~CFontViewPart() { delete itsTempDir; itsTempDir=nullptr; delete itsInterface; 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(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())); + QTimer::singleShot(0, this, &CFontViewPart::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=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.isEmpty()) { 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.isEmpty()) 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/touchpad/src/backends/x11/listdevices.cpp b/kcms/touchpad/src/backends/x11/listdevices.cpp index ac664e512..468a1287c 100644 --- a/kcms/touchpad/src/backends/x11/listdevices.cpp +++ b/kcms/touchpad/src/backends/x11/listdevices.cpp @@ -1,53 +1,53 @@ /* * Copyright (C) 2013 Alexander Mezin * * 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. */ //Debug tool //Must NOT be translated/localized #include #include #include int main(void) { - Display *display = XOpenDisplay(0); + Display *display = XOpenDisplay(nullptr); int nDevices = 0; XDeviceInfo *devices = XListInputDevices(display, &nDevices); for (int i = 0; i < nDevices; i++) { const char *name = devices[i].name; - char *type = 0; + char *type = nullptr; if (devices[i].type) { type = XGetAtomName(display, devices[i].type); } const char *use; switch (devices[i].use) { case IsXPointer: use = "Pointer"; break; case IsXKeyboard: use = "Keyboard"; break; case IsXExtensionDevice: use = "Extension Device"; break; case IsXExtensionPointer: use = "Extension Pointer"; break; case IsXExtensionKeyboard: use = "Extension Keyboard"; break; default: use = "Unknown"; } std::cout << "Name: " << name << " Type: " << (type ? type : "unknown") << " Use: " << use << std::endl; XFree(type); } XFreeDeviceList(devices); XCloseDisplay(display); } diff --git a/kcms/touchpad/src/backends/x11/propertyinfo.cpp b/kcms/touchpad/src/backends/x11/propertyinfo.cpp index 95e1e4456..20f10c132 100644 --- a/kcms/touchpad/src/backends/x11/propertyinfo.cpp +++ b/kcms/touchpad/src/backends/x11/propertyinfo.cpp @@ -1,90 +1,90 @@ /* * Copyright (C) 2013 Alexander Mezin * * 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 "propertyinfo.h" #include #include #include #include void XDeleter(void* p) { if (p) { XFree(p); } } PropertyInfo::PropertyInfo() : - type(0), format(0), nitems(0), f(0), i(0), b(0), - display(0), device(0), prop(0) + type(0), format(0), nitems(0), f(nullptr), i(nullptr), b(nullptr), + display(nullptr), device(0), prop(0) { } PropertyInfo::PropertyInfo(Display *display, int device, Atom prop, Atom floatType) - : type(0), format(0), nitems(0), f(0), i(0), b(0), + : type(0), format(0), nitems(0), f(nullptr), i(nullptr), b(nullptr), display(display), device(device), prop(prop) { - unsigned char *dataPtr = 0; + unsigned char *dataPtr = nullptr; unsigned long bytes_after; XIGetProperty(display, device, prop, 0, 1000, False, AnyPropertyType, &type, &format, &nitems, &bytes_after, &dataPtr); data = QSharedPointer(dataPtr, XDeleter); if (format == CHAR_BIT && type == XA_INTEGER) { b = reinterpret_cast(dataPtr); } if (format == sizeof(int) * CHAR_BIT && (type == XA_INTEGER || type == XA_CARDINAL)) { i = reinterpret_cast(dataPtr); } if (format == sizeof(float) * CHAR_BIT && floatType && type == floatType) { f = reinterpret_cast(dataPtr); } } QVariant PropertyInfo::value(unsigned offset) const { QVariant v; if (offset >= nitems) { return v; } if (b) { v = QVariant(static_cast(b[offset])); } if (i) { v = QVariant(i[offset]); } if (f) { v = QVariant(f[offset]); } return v; } void PropertyInfo::set() { XIChangeProperty(display, device, prop, type, format, XIPropModeReplace, data.data(), nitems); } diff --git a/kcms/touchpad/src/backends/x11/xcbatom.cpp b/kcms/touchpad/src/backends/x11/xcbatom.cpp index 06f7f5224..720ac0c9f 100644 --- a/kcms/touchpad/src/backends/x11/xcbatom.cpp +++ b/kcms/touchpad/src/backends/x11/xcbatom.cpp @@ -1,56 +1,56 @@ /* * Copyright (C) 2013 Alexander Mezin * * 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 "xcbatom.h" #include #include -XcbAtom::XcbAtom() : m_connection(0), m_reply(0), m_fetched(false) +XcbAtom::XcbAtom() : m_connection(nullptr), m_reply(nullptr), m_fetched(false) { } XcbAtom::XcbAtom(xcb_connection_t *c, const char *name, bool onlyIfExists) - : m_reply(0), m_fetched(false) + : m_reply(nullptr), m_fetched(false) { intern(c, name, onlyIfExists); } void XcbAtom::intern(xcb_connection_t *c, const char *name, bool onlyIfExists) { m_connection = c; m_cookie = xcb_intern_atom(c, onlyIfExists, std::strlen(name), name); } XcbAtom::~XcbAtom() { std::free(m_reply); } xcb_atom_t XcbAtom::atom() { if (!m_fetched) { m_fetched = true; - m_reply = xcb_intern_atom_reply(m_connection, m_cookie, 0); + m_reply = xcb_intern_atom_reply(m_connection, m_cookie, nullptr); } if (m_reply) { return m_reply->atom; } else { return 0; } } diff --git a/kcms/touchpad/src/backends/x11/xlibnotifications.cpp b/kcms/touchpad/src/backends/x11/xlibnotifications.cpp index e9ebca7c4..53a1520e3 100644 --- a/kcms/touchpad/src/backends/x11/xlibnotifications.cpp +++ b/kcms/touchpad/src/backends/x11/xlibnotifications.cpp @@ -1,156 +1,156 @@ /* * Copyright (C) 2013 Alexander Mezin * * 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 "xlibnotifications.h" #include #include #include #include #include #include XlibNotifications::XlibNotifications(Display *display, int device) : m_display(display), m_device(device) { m_connection = XGetXCBConnection(display); m_notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read, this); xcb_query_extension_cookie_t inputExtCookie = xcb_query_extension(m_connection, std::strlen(INAME), INAME); QScopedPointer - inputExt(xcb_query_extension_reply(m_connection, inputExtCookie, 0)); + inputExt(xcb_query_extension_reply(m_connection, inputExtCookie, nullptr)); if (!inputExt) { return; } m_inputOpcode = inputExt->major_opcode; const xcb_setup_t *setup = xcb_get_setup(m_connection); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); xcb_screen_t *screen = iter.data; m_inputWindow = xcb_generate_id(m_connection); xcb_create_window(m_connection, 0, m_inputWindow, screen->root, 0, 0, 1, 1, - 0, XCB_WINDOW_CLASS_INPUT_ONLY, 0, 0, 0); + 0, XCB_WINDOW_CLASS_INPUT_ONLY, 0, 0, nullptr); xcb_flush(m_connection); XIEventMask masks[2]; unsigned char touchpadMask[] = { 0, 0, 0, 0 }; masks[0].deviceid = device; masks[0].mask = touchpadMask; masks[0].mask_len = sizeof(touchpadMask); XISetMask(touchpadMask, XI_PropertyEvent); unsigned char allMask[] = { 0, 0, 0, 0 }; masks[1].deviceid = XIAllDevices; masks[1].mask = allMask; masks[1].mask_len = sizeof(allMask); XISetMask(allMask, XI_HierarchyChanged); XISelectEvents(display, XDefaultRootWindow(display), masks, sizeof(masks) / sizeof(XIEventMask)); XFlush(display); connect(m_notifier, SIGNAL(activated(int)), SLOT(processEvents())); m_notifier->setEnabled(true); } void XlibNotifications::processEvents() { while (XPending(m_display)) { XEvent event; XNextEvent(m_display, &event); processEvent(&event); } } struct XEventDataDeleter { XEventDataDeleter(Display *display, XGenericEventCookie *cookie) : m_display(display), m_cookie(cookie) { XGetEventData(m_display, m_cookie); } ~XEventDataDeleter() { if (m_cookie->data) { XFreeEventData(m_display, m_cookie); } } Display *m_display; XGenericEventCookie *m_cookie; }; void XlibNotifications::processEvent(XEvent *event) { if (event->xcookie.type != GenericEvent) { return; } if (event->xcookie.extension != m_inputOpcode) { return; } if (event->xcookie.evtype == XI_PropertyEvent) { XEventDataDeleter helper(m_display, &event->xcookie); if (!event->xcookie.data) { return; } XIPropertyEvent *propEvent = reinterpret_cast(event->xcookie.data); Q_EMIT propertyChanged(propEvent->property); } else if (event->xcookie.evtype == XI_HierarchyChanged) { XEventDataDeleter helper(m_display, &event->xcookie); if (!event->xcookie.data) { return; } XIHierarchyEvent *hierarchyEvent = reinterpret_cast(event->xcookie.data); for (uint16_t i = 0; i < hierarchyEvent->num_info; i++) { if (hierarchyEvent->info[i].deviceid == m_device) { if (hierarchyEvent->info[i].flags & XISlaveRemoved) { Q_EMIT touchpadDetached(); return; } } if (hierarchyEvent->info[i].use != XISlavePointer) { continue; } if (hierarchyEvent->info[i].flags & (XIDeviceEnabled | XIDeviceDisabled)) { Q_EMIT devicePlugged(hierarchyEvent->info[i].deviceid); } } } } XlibNotifications::~XlibNotifications() { xcb_destroy_window(m_connection, m_inputWindow); xcb_flush(m_connection); } #include "moc_xlibnotifications.cpp" diff --git a/kcms/touchpad/src/backends/x11/xrecordkeyboardmonitor.cpp b/kcms/touchpad/src/backends/x11/xrecordkeyboardmonitor.cpp index 9c634ac6e..e5537d674 100644 --- a/kcms/touchpad/src/backends/x11/xrecordkeyboardmonitor.cpp +++ b/kcms/touchpad/src/backends/x11/xrecordkeyboardmonitor.cpp @@ -1,162 +1,162 @@ /* * Copyright (C) 2013 Alexander Mezin * * 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 "xrecordkeyboardmonitor.h" #include #include #include #include #include XRecordKeyboardMonitor::XRecordKeyboardMonitor(Display *display) - : m_connection(xcb_connect(XDisplayString(display), 0)), + : m_connection(xcb_connect(XDisplayString(display), nullptr)), m_modifiersPressed(0), m_keysPressed(0) { if (!m_connection) { return; } xcb_get_modifier_mapping_cookie_t modmapCookie = xcb_get_modifier_mapping(m_connection); m_context = xcb_generate_id(m_connection); xcb_record_range_t range; memset(&range, 0, sizeof(range)); range.device_events.first = XCB_KEY_PRESS; range.device_events.last = XCB_KEY_RELEASE; xcb_record_client_spec_t cs = XCB_RECORD_CS_ALL_CLIENTS; xcb_record_create_context(m_connection, m_context, 0, 1, 1, &cs, &range); xcb_flush(m_connection); QScopedPointer - modmap(xcb_get_modifier_mapping_reply(m_connection, modmapCookie, 0)); + modmap(xcb_get_modifier_mapping_reply(m_connection, modmapCookie, nullptr)); if (!modmap) { return; } int nModifiers = xcb_get_modifier_mapping_keycodes_length(modmap.data()); xcb_keycode_t *modifiers = xcb_get_modifier_mapping_keycodes(modmap.data()); m_modifier.fill(false, std::numeric_limits::max() + 1); for (xcb_keycode_t *i = modifiers; i < modifiers + nModifiers; i++) { m_modifier[*i] = true; } m_ignore.fill(false, std::numeric_limits::max() + 1); for (xcb_keycode_t *i = modifiers; i < modifiers + modmap->keycodes_per_modifier; i++) { m_ignore[*i] = true; } m_pressed.fill(false, std::numeric_limits::max() + 1); m_cookie = xcb_record_enable_context(m_connection, m_context); xcb_flush(m_connection); m_notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read, this); - connect(m_notifier, SIGNAL(activated(int)), SLOT(processNextReply())); + connect(m_notifier, &QSocketNotifier::activated, this, &XRecordKeyboardMonitor::processNextReply); m_notifier->setEnabled(true); } XRecordKeyboardMonitor::~XRecordKeyboardMonitor() { if (!m_connection) { return; } xcb_record_disable_context(m_connection, m_context); xcb_record_free_context(m_connection, m_context); xcb_disconnect(m_connection); } void XRecordKeyboardMonitor::processNextReply() { xcb_generic_event_t *event; while ((event = xcb_poll_for_event(m_connection))) { std::free(event); } - void *reply = 0; + void *reply = nullptr; xcb_generic_error_t *error = nullptr; while (m_cookie.sequence && xcb_poll_for_reply(m_connection, m_cookie.sequence, &reply, &error)) { // xcb_poll_for_reply may set both reply and error to null if connection has error. // break if xcb_connection has error, no point to continue anyway. if (xcb_connection_has_error(m_connection)) { break; } if (error) { std::free(error); break; } if (!reply) { continue; } QScopedPointer data(reinterpret_cast(reply)); process(data.data()); } } void XRecordKeyboardMonitor::process(xcb_record_enable_context_reply_t *reply) { bool prevActivity = activity(); xcb_key_press_event_t *events = reinterpret_cast (xcb_record_enable_context_data(reply)); int nEvents = xcb_record_enable_context_data_length(reply) / sizeof(xcb_key_press_event_t); bool wasActivity = prevActivity; for (xcb_key_press_event_t *e = events; e < events + nEvents; e++) { if (e->response_type != XCB_KEY_PRESS && e->response_type != XCB_KEY_RELEASE) { continue; } if (m_ignore[e->detail]) { continue; } bool pressed = (e->response_type == XCB_KEY_PRESS); if (m_pressed[e->detail] == pressed) { continue; } m_pressed[e->detail] = pressed; int &counter = m_modifier[e->detail] ? m_modifiersPressed : m_keysPressed; if (pressed) { counter++; } else { counter--; } wasActivity = wasActivity || activity(); } if (!prevActivity && activity()) { Q_EMIT keyboardActivityStarted(); } else if (!activity() && wasActivity) { Q_EMIT keyboardActivityFinished(); } } diff --git a/kcms/touchpad/src/kcm/xlib/customslider.cpp b/kcms/touchpad/src/kcm/xlib/customslider.cpp index eebfd1c58..5185a7fdf 100644 --- a/kcms/touchpad/src/kcm/xlib/customslider.cpp +++ b/kcms/touchpad/src/kcm/xlib/customslider.cpp @@ -1,159 +1,159 @@ /* * Copyright (C) 2013 Alexander Mezin * * 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 "customslider.h" #include #include CustomSlider::Interpolator::~Interpolator() { } double CustomSlider::Interpolator::absolute(double relative, double minimum, double maximum) const { return relative * (maximum - minimum) + minimum; } double CustomSlider::Interpolator::relative(double absolute, double minimum, double maximum) const { return (absolute - minimum) / (maximum - minimum); } double CustomSlider::SqrtInterpolator::absolute( double relative, double minimum, double maximum) const { relative *= relative; return Interpolator::absolute(relative, minimum, maximum); } double CustomSlider::SqrtInterpolator::relative( double absolute, double minimum, double maximum) const { double value = Interpolator::relative(absolute, minimum, maximum); return std::sqrt(value); } const CustomSlider::Interpolator CustomSlider::lerp; CustomSlider::CustomSlider(QWidget *parent) : QSlider(parent), m_min(0.0), m_max(1.0), m_interpolator(&lerp) { setSingleStep(10); setPageStep(100); updateValue(); updateRange(size()); - connect(this, SIGNAL(actionTriggered(int)), SLOT(updateValue())); + connect(this, &QAbstractSlider::actionTriggered, this, &CustomSlider::updateValue); } void CustomSlider::resizeEvent(QResizeEvent *e) { QSlider::resizeEvent(e); updateRange(e->size()); } const CustomSlider::Interpolator *CustomSlider::interpolator() const { return m_interpolator; } void CustomSlider::setInterpolator(const CustomSlider::Interpolator *v) { m_interpolator = v; } void CustomSlider::setDoubleMinimum(double v) { m_min = v; } double CustomSlider::doubleMinimum() const { return m_min; } void CustomSlider::setDoubleMaximum(double v) { m_max = v; } double CustomSlider::doubleMaximum() const { return m_max; } double CustomSlider::doubleValue() const { return qBound(m_min, m_value, m_max); } void CustomSlider::setDoubleValue(double v) { if (m_value == v) { return; } m_value = v; int oldIntValue = value(); moveSlider(); if (value() != oldIntValue) { Q_EMIT valueChanged(doubleValue()); } } double CustomSlider::intToDouble(int v) const { double relative = lerp.relative(v, minimum(), maximum()); return m_interpolator->absolute(relative, m_min, m_max); } void CustomSlider::updateValue() { m_value = intToDouble(sliderPosition()); Q_EMIT valueChanged(doubleValue()); } double CustomSlider::fixup(double v) const { return intToDouble(doubleToInt(v)); } int CustomSlider::doubleToInt(double v) const { double relative = m_interpolator->relative(v, m_min, m_max); double absolute = lerp.absolute(relative, minimum(), maximum()); return static_cast(std::floor(absolute + 0.5)); } void CustomSlider::moveSlider() { setValue(doubleToInt(doubleValue())); } void CustomSlider::updateRange(const QSize &s) { setRange(0, (orientation() == Qt::Horizontal) ? s.width() : s.height()); moveSlider(); } diff --git a/kcms/touchpad/src/kcm/xlib/sliderpair.cpp b/kcms/touchpad/src/kcm/xlib/sliderpair.cpp index 3b15fd4aa..3528bb087 100644 --- a/kcms/touchpad/src/kcm/xlib/sliderpair.cpp +++ b/kcms/touchpad/src/kcm/xlib/sliderpair.cpp @@ -1,38 +1,38 @@ /* * Copyright (C) 2013 Alexander Mezin * * 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 "sliderpair.h" #include SliderPair::SliderPair(QSlider *minSlider, QSlider *maxSlider, QObject *parent) : QObject(parent), m_minSlider(minSlider), m_maxSlider(maxSlider) { - connect(m_minSlider, SIGNAL(valueChanged(int)), SLOT(adjustMaxSlider())); - connect(m_maxSlider, SIGNAL(valueChanged(int)), SLOT(adjustMinSlider())); + connect(m_minSlider, &QAbstractSlider::valueChanged, this, &SliderPair::adjustMaxSlider); + connect(m_maxSlider, &QAbstractSlider::valueChanged, this, &SliderPair::adjustMinSlider); } void SliderPair::adjustMaxSlider() { m_maxSlider->setValue(qMax(m_maxSlider->value(), m_minSlider->value())); } void SliderPair::adjustMinSlider() { m_minSlider->setValue(qMin(m_maxSlider->value(), m_minSlider->value())); } diff --git a/kcms/touchpad/src/kcm/xlib/testbutton.cpp b/kcms/touchpad/src/kcm/xlib/testbutton.cpp index 2b0d6365f..687e546ae 100644 --- a/kcms/touchpad/src/kcm/xlib/testbutton.cpp +++ b/kcms/touchpad/src/kcm/xlib/testbutton.cpp @@ -1,60 +1,60 @@ /* * Copyright (C) 2013 Alexander Mezin * * 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 "testbutton.h" #include #include #include TestButton::TestButton(QWidget *parent) : QPushButton(parent), m_firstClick(true) { } void TestButton::mousePressEvent(QMouseEvent *e) { if (m_firstClick) { m_originalText = text(); m_firstClick = false; } switch (e->button()) { case Qt::LeftButton: setText(i18nc("Mouse button", "Left button")); break; case Qt::RightButton: setText(i18nc("Mouse button", "Right button")); break; case Qt::MiddleButton: setText(i18nc("Mouse button", "Middle button")); break; default: break; } - QTimer::singleShot(500, this, SLOT(resetText())); + QTimer::singleShot(500, this, &TestButton::resetText); QPushButton::mousePressEvent(e); } void TestButton::resetText() { setText(m_originalText); } diff --git a/runners/plasma-desktop/plasma-desktop-runner.cpp b/runners/plasma-desktop/plasma-desktop-runner.cpp index b46ef95d8..fd2403d9a 100644 --- a/runners/plasma-desktop/plasma-desktop-runner.cpp +++ b/runners/plasma-desktop/plasma-desktop-runner.cpp @@ -1,145 +1,145 @@ /* * Copyright (C) 2009 Aaron Seigo * * This program 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 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "plasma-desktop-runner.h" #include #include #include #include #include K_EXPORT_PLASMA_RUNNER(plasma-desktop, PlasmaDesktopRunner) static const QString s_plasmaService = QLatin1String("org.kde.plasmashell"); PlasmaDesktopRunner::PlasmaDesktopRunner(QObject *parent, const QVariantList &args) : Plasma::AbstractRunner(parent, args), m_desktopConsoleKeyword(i18nc("Note this is a KRunner keyword", "desktop console")), m_kwinConsoleKeyword(i18nc("Note this is a KRunner keyword", "wm console")), m_enabled(false) { setObjectName( QLatin1String("Plasma-Desktop" )); setIgnoredTypes(Plasma::RunnerContext::FileSystem | Plasma::RunnerContext::NetworkLocation | Plasma::RunnerContext::Help); QDBusServiceWatcher *watcher = new QDBusServiceWatcher(s_plasmaService, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this); - connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), - this, SLOT(checkAvailability(QString,QString,QString))); + connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, + this, &PlasmaDesktopRunner::checkAvailability); checkAvailability(QString(), QString(), QString()); } PlasmaDesktopRunner::~PlasmaDesktopRunner() { } void PlasmaDesktopRunner::match(Plasma::RunnerContext &context) { if (m_enabled && context.query().startsWith(m_desktopConsoleKeyword, Qt::CaseInsensitive)) { Plasma::QueryMatch match(this); match.setId(QStringLiteral("plasma-desktop-console")); match.setType(Plasma::QueryMatch::ExactMatch); match.setIconName(QStringLiteral("plasma")); match.setText(i18n("Open Plasma desktop interactive console")); match.setRelevance(1.0); context.addMatch(match); } if (m_enabled && context.query().startsWith(m_kwinConsoleKeyword, Qt::CaseInsensitive)) { Plasma::QueryMatch match(this); match.setId(QStringLiteral("plasma-desktop-console")); match.setType(Plasma::QueryMatch::ExactMatch); match.setIconName(QStringLiteral("kwin")); match.setText(i18n("Open KWin interactive console")); match.setRelevance(1.0); context.addMatch(match); } } void PlasmaDesktopRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) { Q_UNUSED(match) if (m_enabled) { QDBusMessage message; QString query = context.query(); if (query.compare(m_desktopConsoleKeyword, Qt::CaseInsensitive) == 0) { message = QDBusMessage::createMethodCall(s_plasmaService, QStringLiteral("/PlasmaShell"), QStringLiteral("org.kde.PlasmaShell"), QStringLiteral("showInteractiveConsole")); } else if (query.startsWith(m_desktopConsoleKeyword)) { message = QDBusMessage::createMethodCall(s_plasmaService, QStringLiteral("/PlasmaShell"), QStringLiteral("org.kde.PlasmaShell"), QStringLiteral("loadScriptInInteractiveConsole")); query.replace(m_desktopConsoleKeyword, QString(), Qt::CaseInsensitive); QList args; args << query; message.setArguments(args); } if (query.compare(m_kwinConsoleKeyword, Qt::CaseInsensitive) == 0) { message = QDBusMessage::createMethodCall(s_plasmaService, QStringLiteral("/PlasmaShell"), QStringLiteral("org.kde.PlasmaShell"), QStringLiteral("showInteractiveKWinConsole")); } else if (query.startsWith(m_kwinConsoleKeyword)) { message = QDBusMessage::createMethodCall(s_plasmaService, QStringLiteral("/PlasmaShell"), QStringLiteral("org.kde.PlasmaShell"), QStringLiteral("loadKWinScriptInInteractiveConsole")); query.replace(m_kwinConsoleKeyword, QString(), Qt::CaseInsensitive); QList args; args << query; message.setArguments(args); } QDBusConnection::sessionBus().asyncCall(message); } } void PlasmaDesktopRunner::checkAvailability(const QString &name, const QString &oldOwner, const QString &newOwner) { Q_UNUSED(oldOwner) bool enabled = false; if (name.isEmpty()) { enabled = QDBusConnection::sessionBus().interface()->isServiceRegistered(s_plasmaService).value(); } else { enabled = !newOwner.isEmpty(); } if (m_enabled != enabled) { m_enabled = enabled; if (m_enabled) { addSyntax(Plasma::RunnerSyntax(m_desktopConsoleKeyword, i18n("Opens the Plasma desktop interactive console " "with a file path to a script on disk."))); addSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "desktop console :q:"), i18n("Opens the Plasma desktop interactive console " "with a file path to a script on disk."))); addSyntax(Plasma::RunnerSyntax(m_kwinConsoleKeyword, i18n("Opens the KWin interactive console " "with a file path to a script on disk."))); addSyntax(Plasma::RunnerSyntax(i18nc("Note this is a KRunner keyword", "wm console :q:"), i18n("Opens the KWin interactive console " "with a file path to a script on disk."))); } else { setSyntaxes(QList()); } } } #include "plasma-desktop-runner.moc"