diff --git a/CMakeLists.txt b/CMakeLists.txt index c117cc681..3fd467a24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,178 +1,179 @@ project(plasma-desktop) set(PROJECT_VERSION "5.11.90") set(PROJECT_VERSION_MAJOR 5) cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) set(QT_MIN_VERSION "5.7.0") find_package(ECM 0.0.11 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMInstallIcons) include(ECMMarkAsTest) include(ECMMarkNonGuiExecutable) include(ECMOptionalAddSubdirectory) include(ECMQtDeclareLoggingCategory) include(FeatureSummary) include(CheckIncludeFiles) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Quick QuickWidgets DBus Widgets X11Extras Svg Concurrent ) set(KF5_MIN_VERSION "5.34.0") find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Auth Plasma PlasmaQuick DocTools I18n KCMUtils NewStuff KDELibs4Support Notifications NotifyConfig Attica Wallet Runner GlobalAccel Declarative People DBusAddons Activities ActivitiesStats Config ) find_package(LibKWorkspace CONFIG REQUIRED) find_package(LibTaskManager CONFIG REQUIRED) find_package(KWinDBusInterface CONFIG REQUIRED) find_package(ScreenSaverDBusInterface CONFIG REQUIRED) find_package(KRunnerAppDBusInterface CONFIG REQUIRED) find_package(KSMServerDBusInterface CONFIG REQUIRED) find_package(KF5ItemModels CONFIG REQUIRED) find_package(KF5Emoticons CONFIG REQUIRED) find_package(AppStreamQt 0.10.4) set_package_properties(AppStreamQt PROPERTIES DESCRIPTION "Appstream integration" TYPE RECOMMENDED PURPOSE "Needed to allow appstream integration from application menus" ) find_package(KF5Baloo 5.15) set_package_properties(KF5Baloo PROPERTIES DESCRIPTION "File Searching" TYPE RECOMMENDED PURPOSE "Needed to build the File Search KCM" ) find_package(Fontconfig) set_package_properties(Fontconfig PROPERTIES DESCRIPTION "Font access configuration library" URL "http://www.freedesktop.org/wiki/Software/fontconfig" TYPE OPTIONAL PURPOSE "Needed to build font configuration and installation tools" ) find_package(X11) set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" URL "http://www.x.org" TYPE REQUIRED PURPOSE "Required for building the X11 based workspace" ) find_package(UDev) set_package_properties(UDev PROPERTIES DESCRIPTION "UDev library" URL "http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html" TYPE OPTIONAL PURPOSE "Required for device discovery in keyboard daemon" ) find_package(XCB REQUIRED COMPONENTS XCB SHM IMAGE OPTIONAL_COMPONENTS XKB XINPUT ) set_package_properties(XCB PROPERTIES TYPE REQUIRED) add_feature_info("XCB-XKB" XCB_XKB_FOUND "Required for building kcm/keyboard") add_feature_info("libxft" X11_Xft_FOUND "X FreeType interface library required for font installation") find_package(Evdev) set_package_properties(Evdev PROPERTIES TYPE OPTIONAL) add_feature_info("Evdev" EVDEV_FOUND "Evdev driver headers needed for input KCM") find_package(Synaptics) set_package_properties(Synaptics PROPERTIES TYPE OPTIONAL) add_feature_info("Synaptics" SYNAPTICS_FOUND "Synaptics libraries needed for touchpad KCM") include(ConfigureChecks.cmake) if(${Qt5Gui_OPENGL_IMPLEMENTATION} STREQUAL "GL") find_package(OpenGL) set_package_properties(OpenGL PROPERTIES DESCRIPTION "The OpenGL libraries" URL "http://www.opengl.org" TYPE REQUIRED ) else() find_package(OpenGLES) set_package_properties(OpenGLES PROPERTIES DESCRIPTION "The OpenGLES libraries" URL "http://www.khronos.org/opengles" TYPE REQUIRED ) endif() find_package(Breeze ${PROJECT_VERSION} CONFIG) set_package_properties(Breeze PROPERTIES TYPE OPTIONAL PURPOSE "For setting the default window decoration plugin") if(${Breeze_FOUND}) if(${BREEZE_WITH_KDECORATION}) set(HAVE_BREEZE_DECO true) else() set(HAVE_BREEZE_DECO FALSE) endif() else() set(HAVE_BREEZE_DECO FALSE) endif() if(${AppStreamQt_FOUND}) set(HAVE_APPSTREAMQT true) endif() include_directories("${CMAKE_CURRENT_BINARY_DIR}") configure_file(config-workspace.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-workspace.h) configure_file(config-unix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-unix.h ) configure_file(config-appstream.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-appstream.h ) configure_file(config-X11.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-X11.h) configure_file(config-runtime.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-runtime.h) plasma_install_package(desktoppackage org.kde.plasma.desktop shells shell) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) add_subdirectory(layout-templates) add_subdirectory(doc) add_subdirectory(runners) add_subdirectory(containments) add_subdirectory(toolboxes) add_subdirectory(applets) add_subdirectory(dataengines) add_subdirectory(kcms) add_subdirectory(knetattach) add_subdirectory(attica-kde) add_subdirectory(imports/activitymanager/) add_subdirectory(solid-device-automounter) +install(DIRECTORY kcmcontrols/ DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kcmcontrols) if(X11_Xkb_FOUND AND XCB_XKB_FOUND) add_subdirectory(kaccess) endif() install(FILES org.kde.plasmashell.metainfo.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/kcms/cursortheme/package/contents/ui/GridDelegate.qml b/kcmcontrols/GridDelegate.qml similarity index 100% rename from kcms/cursortheme/package/contents/ui/GridDelegate.qml rename to kcmcontrols/GridDelegate.qml diff --git a/kcms/cursortheme/package/contents/ui/GridViewPage.qml b/kcmcontrols/GridViewPage.qml similarity index 98% rename from kcms/cursortheme/package/contents/ui/GridViewPage.qml rename to kcmcontrols/GridViewPage.qml index e6c8a3e28..dc4b13a0c 100644 --- a/kcms/cursortheme/package/contents/ui/GridViewPage.qml +++ b/kcmcontrols/GridViewPage.qml @@ -1,69 +1,70 @@ /* Copyright (c) 2017 Marco Martin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.7 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.2 as QtControls import org.kde.kirigami 2.2 as Kirigami - +import org.kde.kcm 1.0 Kirigami.Page { id: root + title: kcm.name implicitWidth: Kirigami.Units.gridUnit * 20 implicitHeight: Kirigami.Units.gridUnit * 20 property alias view: view topPadding: 0 leftPadding: 0 rightPadding: 0 bottomPadding: footer ? Kirigami.Units.smallSpacing : 0 QtControls.ScrollView { id: scroll anchors { top: parent.top bottom: parent.bottom horizontalCenter: parent.horizontalCenter } width: Math.floor((root.width - Kirigami.Units.gridUnit*2) / view.cellWidth) * view.cellWidth + Kirigami.Units.gridUnit*2 activeFocusOnTab: false GridView { id: view anchors { fill: parent margins: scroll.background ? 2 : 0 rightMargin: contentHeight > height ? Kirigami.Units.gridUnit : 2 } contentItem.x: Math.round((width - Math.floor(width / cellWidth) * cellWidth) / 2) clip: true activeFocusOnTab: true cellWidth: Kirigami.Units.gridUnit * 10 cellHeight: cellWidth / 1.6 + Kirigami.Units.gridUnit*2 keyNavigationEnabled: true keyNavigationWraps: true highlightMoveDuration: 0 } //not all styles have background defined Component.onCompleted: { background.visible = true; } } } diff --git a/kcmcontrols/qmldir b/kcmcontrols/qmldir new file mode 100644 index 000000000..8b7a8cb12 --- /dev/null +++ b/kcmcontrols/qmldir @@ -0,0 +1,4 @@ +module org.kde.kcmcontrols + +GridDelegate 1.0 GridDelegate.qml +GridViewPage 1.0 GridViewPage.qml diff --git a/kcms/cursortheme/kcmcursortheme.cpp b/kcms/cursortheme/kcmcursortheme.cpp index 050163650..4fca47c83 100644 --- a/kcms/cursortheme/kcmcursortheme.cpp +++ b/kcms/cursortheme/kcmcursortheme.cpp @@ -1,594 +1,594 @@ /* * Copyright © 2003-2007 Fredrik Höglund * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "kcmcursortheme.h" #include "xcursor/thememodel.h" #include "xcursor/sortproxymodel.h" #include "xcursor/cursortheme.h" #include "xcursor/previewwidget.h" #include "../krdb/krdb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_XFIXES # include #endif K_PLUGIN_FACTORY_WITH_JSON(CursorThemeConfigFactory, "kcm_cursortheme.json", registerPlugin();) CursorThemeConfig::CursorThemeConfig(QObject *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args), m_appliedSize(0), m_preferredSize(0), m_selectedThemeRow(-1), m_canInstall(true), m_canResize(true), m_canConfigure(true) { qmlRegisterType("org.kde.private.kcm_cursortheme", 1, 0, "PreviewWidget"); qmlRegisterType(); KAboutData* aboutData = new KAboutData(QStringLiteral("kcm_cursortheme"), i18n("Cursor Theme"), - QStringLiteral("1.0"), QString(), KAboutLicense::GPL, i18n("(c) 2003-2007 Fredrik Höglund")); + QStringLiteral("1.0"), QString(i18n("Mouse Cursor Theme settings")), KAboutLicense::GPL, i18n("(c) 2003-2007 Fredrik Höglund")); aboutData->addAuthor(i18n("Fredrik Höglund")); aboutData->addAuthor(i18n("Marco Martin")); setAboutData(aboutData); m_model = new CursorThemeModel(this); m_proxyModel = new SortProxyModel(this); m_proxyModel->setSourceModel(m_model); m_proxyModel->setFilterCaseSensitivity(Qt::CaseSensitive); m_proxyModel->sort(NameColumn, Qt::AscendingOrder); m_sizesModel = new QStandardItemModel(this); // Disable the install button if we can't install new themes to ~/.icons, // or Xcursor isn't set up to look for cursor themes there. if (!m_model->searchPaths().contains(QDir::homePath() + "/.icons") || !iconsIsWritable()) { setCanInstall(false); } } CursorThemeConfig::~CursorThemeConfig() { /* */ } void CursorThemeConfig::setCanInstall(bool can) { if (m_canInstall == can) { return; } m_canInstall = can; emit canInstallChanged(); } bool CursorThemeConfig::canInstall() const { return m_canInstall; } void CursorThemeConfig::setCanResize(bool can) { if (m_canResize == can) { return; } m_canResize = can; emit canResizeChanged(); } bool CursorThemeConfig::canResize() const { return m_canResize; } void CursorThemeConfig::setCanConfigure(bool can) { if (m_canConfigure == can) { return; } m_canConfigure = can; emit canConfigureChanged(); } bool CursorThemeConfig::canConfigure() const { return m_canConfigure; } void CursorThemeConfig::setSelectedThemeRow(int row) { if (m_selectedThemeRow == row) { return; } m_selectedThemeRow = row; emit selectedThemeRowChanged(); setNeedsSave(true); updateSizeComboBox(); QModelIndex selected = selectedIndex(); if (selected.isValid()) { const CursorTheme *theme = m_proxyModel->theme(selected); } } int CursorThemeConfig::selectedThemeRow() const { return m_selectedThemeRow; } void CursorThemeConfig::setPreferredSize(int size) { if (m_preferredSize == size) { return; } m_preferredSize = size; emit preferredSizeChanged(); setNeedsSave(true); } int CursorThemeConfig::preferredSize() const { return m_preferredSize; } QAbstractItemModel *CursorThemeConfig::cursorsModel() { return m_proxyModel; } QAbstractItemModel *CursorThemeConfig::sizesModel() { return m_sizesModel; } bool CursorThemeConfig::iconsIsWritable() const { const QFileInfo icons = QFileInfo(QDir::homePath() + "/.icons"); const QFileInfo home = QFileInfo(QDir::homePath()); return ((icons.exists() && icons.isDir() && icons.isWritable()) || (!icons.exists() && home.isWritable())); } void CursorThemeConfig::updateSizeComboBox() { // clear the combo box m_sizesModel->clear(); // refill the combo box and adopt its icon size QModelIndex selected = selectedIndex(); int maxIconWidth = 0; int maxIconHeight = 0; if (selected.isValid()) { const CursorTheme *theme = m_proxyModel->theme(selected); const QList sizes = theme->availableSizes(); QIcon m_icon; if (sizes.size() > 1) // only refill the combobox if there is more that 1 size { int i; QList comboBoxList; QPixmap m_pixmap; // insert the items m_pixmap = theme->createIcon(0); if (m_pixmap.width() > maxIconWidth) maxIconWidth = m_pixmap.width(); if (m_pixmap.height() > maxIconHeight) maxIconHeight = m_pixmap.height(); QStandardItem *item = new QStandardItem(QIcon(m_pixmap), i18nc("@item:inlistbox size", "Resolution dependent")); item->setData(0); m_sizesModel->appendRow(item); comboBoxList << 0; foreach (i, sizes) { m_pixmap = theme->createIcon(i); if (m_pixmap.width() > maxIconWidth) maxIconWidth = m_pixmap.width(); if (m_pixmap.height() > maxIconHeight) maxIconHeight = m_pixmap.height(); QStandardItem *item = new QStandardItem(QIcon(m_pixmap), QString::number(i)); item->setData(i); m_sizesModel->appendRow(item); comboBoxList << i; }; // select an item int selectItem = comboBoxList.indexOf(m_preferredSize); if (selectItem < 0) // m_preferredSize not available for this theme { /* Search the value next to m_preferredSize. The first entry (0) is ignored. (If m_preferredSize would have been 0, then we would had found it yet. As m_preferredSize is not 0, we won't default to "automatic size".)*/ int j; int distance; int smallestDistance; selectItem = 1; j = comboBoxList.value(selectItem); smallestDistance = j < m_preferredSize ? m_preferredSize - j : j - m_preferredSize; for (int i = 2; i < comboBoxList.size(); ++i) { j = comboBoxList.value(i); distance = j < m_preferredSize ? m_preferredSize - j : j - m_preferredSize; if (distance < smallestDistance || (distance == smallestDistance && j > m_preferredSize)) { smallestDistance = distance; selectItem = i; }; } }; setPreferredSize(selectItem); }; }; // enable or disable the combobox KConfig c("kcminputrc"); KConfigGroup cg(&c, "Mouse"); if (cg.isEntryImmutable("cursorSize")) { setCanResize(false); } else { setCanResize(m_sizesModel->rowCount() > 0); }; } bool CursorThemeConfig::applyTheme(const CursorTheme *theme, const int size) { // Require the Xcursor version that shipped with X11R6.9 or greater, since // in previous versions the Xfixes code wasn't enabled due to a bug in the // build system (freedesktop bug #975). #if HAVE_XFIXES && XFIXES_MAJOR >= 2 && XCURSOR_LIB_VERSION >= 10105 if (!theme) return false; if (!CursorTheme::haveXfixes()) return false; QByteArray themeName = QFile::encodeName(theme->name()); // Set up the proper launch environment for newly started apps OrgKdeKLauncherInterface klauncher(QStringLiteral("org.kde.klauncher5"), QStringLiteral("/KLauncher"), QDBusConnection::sessionBus()); klauncher.setLaunchEnv(QStringLiteral("XCURSOR_THEME"), themeName); // Update the Xcursor X resources runRdb(0); // Notify all applications that the cursor theme has changed KGlobalSettings::self()->emitChange(KGlobalSettings::CursorChanged); // Reload the standard cursors QStringList names; // Qt cursors names << "left_ptr" << "up_arrow" << "cross" << "wait" << "left_ptr_watch" << "ibeam" << "size_ver" << "size_hor" << "size_bdiag" << "size_fdiag" << "size_all" << "split_v" << "split_h" << "pointing_hand" << "openhand" << "closedhand" << "forbidden" << "whats_this" << "copy" << "move" << "link"; // X core cursors names << "X_cursor" << "right_ptr" << "hand1" << "hand2" << "watch" << "xterm" << "crosshair" << "left_ptr_watch" << "center_ptr" << "sb_h_double_arrow" << "sb_v_double_arrow" << "fleur" << "top_left_corner" << "top_side" << "top_right_corner" << "right_side" << "bottom_right_corner" << "bottom_side" << "bottom_left_corner" << "left_side" << "question_arrow" << "pirate"; foreach (const QString &name, names) { XFixesChangeCursorByName(QX11Info::display(), theme->loadCursor(name, size), QFile::encodeName(name)); } return true; #else Q_UNUSED(theme) return false; #endif } void CursorThemeConfig::save() { const CursorTheme *theme = selectedIndex().isValid() ? m_proxyModel->theme(selectedIndex()) : NULL; KConfig config("kcminputrc"); KConfigGroup c(&config, "Mouse"); if (theme) { c.writeEntry("cursorTheme", theme->name()); }; c.writeEntry("cursorSize", m_preferredSize); c.sync(); if (!applyTheme(theme, m_preferredSize)) { KMessageBox::information(0, i18n("You have to restart KDE for these changes to take effect."), i18n("Cursor Settings Changed"), "CursorSettingsChanged"); } m_appliedIndex = selectedIndex(); m_appliedSize = m_preferredSize; setNeedsSave(false); } void CursorThemeConfig::load() { // Get the name of the theme libXcursor currently uses QString currentTheme; if (QX11Info::isPlatformX11()) { currentTheme = XcursorGetTheme(QX11Info::display()); } // Get the name of the theme KDE is configured to use KConfig c("kcminputrc"); KConfigGroup cg(&c, "Mouse"); currentTheme = cg.readEntry("cursorTheme", currentTheme); // Find the theme in the listview if (!currentTheme.isEmpty()) m_appliedIndex = m_proxyModel->findIndex(currentTheme); else m_appliedIndex = m_proxyModel->defaultIndex(); // Disable the listview and the buttons if we're in kiosk mode if (cg.isEntryImmutable("cursorTheme")) { setCanConfigure(false); setCanInstall(false); } // Load cursor size int size = cg.readEntry("cursorSize", 0); if (size <= 0) m_preferredSize = 0; else m_preferredSize = size; updateSizeComboBox(); // This handles also the kiosk mode m_appliedSize = size; const CursorTheme *theme = m_proxyModel->theme(m_appliedIndex); setSelectedThemeRow(m_appliedIndex.row()); setNeedsSave(false); } void CursorThemeConfig::defaults() { QModelIndex defaultIndex = m_proxyModel->findIndex("breeze_cursors"); setSelectedThemeRow(defaultIndex.row()); m_preferredSize = 0; updateSizeComboBox(); setNeedsSave(true); } void CursorThemeConfig::selectionChanged() { updateSizeComboBox(); setNeedsSave(m_appliedIndex != selectedIndex()); } QModelIndex CursorThemeConfig::selectedIndex() const { return m_proxyModel->index(m_selectedThemeRow, 0); } void CursorThemeConfig::getNewClicked() { KNS3::DownloadDialog dialog("xcursor.knsrc", 0); if (dialog.exec()) { KNS3::Entry::List list = dialog.changedEntries(); if (list.count() > 0) m_model->refreshList(); } } void CursorThemeConfig::installClicked() { // Get the URL for the theme we're going to install QUrl url = KUrlRequesterDialog::getUrl(QUrl(), 0, i18n("Drag or Type Theme URL")); if (url.isEmpty()) return; QString tempFile; if (!KIO::NetAccess::download(url, tempFile, 0)) { QString text; if (url.isLocalFile()) text = i18n("Unable to find the cursor theme archive %1.", url.toDisplayString()); else text = i18n("Unable to download the cursor theme archive; " "please check that the address %1 is correct.", url.toDisplayString()); KMessageBox::sorry(0, text); return; } if (!installThemes(tempFile)) KMessageBox::error(0, i18n("The file %1 does not appear to be a valid " "cursor theme archive.", url.fileName())); KIO::NetAccess::removeTempFile(tempFile); } void CursorThemeConfig::removeTheme(int row) { QModelIndex idx = m_proxyModel->index(row, 0); if (!idx.isValid()) { return; } const CursorTheme *theme = m_proxyModel->theme(idx); // Don't let the user delete the currently configured theme if (idx == m_appliedIndex) { KMessageBox::sorry(0, i18n("You cannot delete the theme you are currently " "using.
You have to switch to another theme first.
")); return; } // Get confirmation from the user QString question = i18n("Are you sure you want to remove the " "%1 cursor theme?
" "This will delete all the files installed by this theme.
", theme->title()); int answer = KMessageBox::warningContinueCancel(0, question, i18n("Confirmation"), KStandardGuiItem::del()); if (answer != KMessageBox::Continue) return; // Delete the theme from the harddrive KIO::del(QUrl::fromLocalFile(theme->path())); // async // Remove the theme from the model m_proxyModel->removeTheme(idx); // TODO: // Since it's possible to substitute cursors in a system theme by adding a local // theme with the same name, we shouldn't remove the theme from the list if it's // still available elsewhere. We could add a // bool CursorThemeModel::tryAddTheme(const QString &name), and call that, but // since KIO::del() is an asynchronos operation, the theme we're deleting will be // readded to the list again before KIO has removed it. } bool CursorThemeConfig::installThemes(const QString &file) { KTar archive(file); if (!archive.open(QIODevice::ReadOnly)) return false; const KArchiveDirectory *archiveDir = archive.directory(); QStringList themeDirs; // Extract the dir names of the cursor themes in the archive, and // append them to themeDirs foreach(const QString &name, archiveDir->entries()) { const KArchiveEntry *entry = archiveDir->entry(name); if (entry->isDirectory() && entry->name().toLower() != "default") { const KArchiveDirectory *dir = static_cast(entry); if (dir->entry("index.theme") && dir->entry("cursors")) themeDirs << dir->name(); } } if (themeDirs.isEmpty()) return false; // The directory we'll install the themes to QString destDir = QDir::homePath() + "/.icons/"; QDir().mkpath(destDir); // Make sure the directory exists // Process each cursor theme in the archive foreach (const QString &dirName, themeDirs) { QDir dest(destDir + dirName); if (dest.exists()) { QString question = i18n("A theme named %1 already exists in your icon " "theme folder. Do you want replace it with this one?", dirName); int answer = KMessageBox::warningContinueCancel(0, question, i18n("Overwrite Theme?"), KStandardGuiItem::overwrite()); if (answer != KMessageBox::Continue) continue; // ### If the theme that's being replaced is the current theme, it // will cause cursor inconsistencies in newly started apps. } // ### Should we check if a theme with the same name exists in a global theme dir? // If that's the case it will effectively replace it, even though the global theme // won't be deleted. Checking for this situation is easy, since the global theme // will be in the listview. Maybe this should never be allowed since it might // result in strange side effects (from the average users point of view). OTOH // a user might want to do this 'upgrade' a global theme. const KArchiveDirectory *dir = static_cast (archiveDir->entry(dirName)); dir->copyTo(dest.path()); m_model->addTheme(dest); } archive.close(); return true; } #include "kcmcursortheme.moc" diff --git a/kcms/cursortheme/package/contents/ui/Delegate.qml b/kcms/cursortheme/package/contents/ui/Delegate.qml index 691408c7a..26ddff5ac 100644 --- a/kcms/cursortheme/package/contents/ui/Delegate.qml +++ b/kcms/cursortheme/package/contents/ui/Delegate.qml @@ -1,66 +1,67 @@ /* Copyright (c) 2015 Marco Martin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.1 import QtQuick.Window 2.2 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.2 as Controls import QtQuick.Templates 2.2 as T2 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.2 as Kirigami import org.kde.kcm 1.0 +import org.kde.kcmcontrols 1.0 as KCMControls import org.kde.private.kcm_cursortheme 1.0 -GridDelegate { +KCMControls.GridDelegate { id: delegate text: model.display toolTip: model.description thumbnail: PreviewWidget { id: previewWidget //for cursor themes we must ignore the native scaling, //as they will be rendered by X11/KWin, ignoring whatever Qt //scaling width: parent.width * Screen.devicePixelRatio height: parent.height * Screen.devicePixelRatio x: Screen.devicePixelRatio % 1 y: Screen.devicePixelRatio % 1 transformOrigin: Item.TopLeft scale: 1 / Screen.devicePixelRatio themeModel: kcm.cursorsModel currentIndex: index currentSize: parseInt(sizeCombo.currentText) !== NaN ? parseInt(sizeCombo.currentText) : 0 } actions: [ Kirigami.Action { iconName: "edit-delete" tooltip: i18n("Remove Theme") enabled: model.isWritable onTriggered: kcm.removeTheme(index); } ] onClicked: { view.currentIndex = index; view.forceActiveFocus(); } } diff --git a/kcms/cursortheme/package/contents/ui/main.qml b/kcms/cursortheme/package/contents/ui/main.qml index ee72e7693..060b7b0e2 100644 --- a/kcms/cursortheme/package/contents/ui/main.qml +++ b/kcms/cursortheme/package/contents/ui/main.qml @@ -1,78 +1,79 @@ /* Copyright (c) 2015 Marco Martin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.7 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.2 as QtControls import org.kde.kirigami 2.2 as Kirigami import org.kde.kcm 1.0 +import org.kde.kcmcontrols 1.0 as KCMControls import org.kde.private.kcm_cursortheme 1.0 -GridViewPage { +KCMControls.GridViewPage { ConfigModule.quickHelp: i18n("This module lets you configure the mouse cursor theme used.") view.model: kcm.cursorsModel view.delegate: Delegate {} view.onCurrentIndexChanged: { kcm.selectedThemeRow = view.currentIndex; view.positionViewAtIndex(view.currentIndex, view.GridView.Beginning); } Connections { target: kcm onSelectedThemeRowChanged: view.currentIndex = kcm.selectedThemeRow; } footer: RowLayout { //spacer Item { Layout.fillWidth: true Layout.fillHeight: true } QtControls.Label { text: i18n("Size:") } QtControls.ComboBox { id: sizeCombo currentIndex: 0 onCountChanged: currentIndex = 0 model: kcm.sizesModel textRole: "display" onCurrentTextChanged: { kcm.preferredSize = parseInt(sizeCombo.currentText) !== NaN ? parseInt(sizeCombo.currentText) : 0 } } QtControls.Button { // iconName: "document-import" text: i18n("&Install From File...") onClicked: kcm.installClicked(); enabled: kcm.canInstall } QtControls.Button { // iconName: "get-hot-new-stuff" text: i18n("&Get New Theme...") onClicked: kcm.getNewClicked(); enabled: kcm.canInstall } } }