Commit 73e11cb3 authored by David Redondo's avatar David Redondo 🏎
Browse files

Cursortheme KCM: Avoid a nested event loop

Instead of showing a KMessageBox that calls exec(), use the "pending deletion"
pattern that we use in other GridViewKCMs.
parent 03f3d05f
......@@ -93,6 +93,15 @@ CursorThemeConfig::CursorThemeConfig(QObject *parent, const QVariantList &args)
if (!m_themeModel->searchPaths().contains(QDir::homePath() + "/.icons") || !iconsIsWritable()) {
setCanInstall(false);
}
connect(m_themeModel, &QAbstractItemModel::dataChanged, this, &CursorThemeConfig::settingsChanged);
connect(m_themeModel, &QAbstractItemModel::dataChanged, this, [this] (const QModelIndex &start, const QModelIndex &end, const QVector<int> &roles) {
const QModelIndex currentThemeIndex = m_themeModel->findIndex(m_settings->cursorTheme());
if (roles.contains(CursorTheme::PendingDeletionRole) && currentThemeIndex.data(CursorTheme::PendingDeletionRole) == true
&& start.row() <= currentThemeIndex.row() && currentThemeIndex.row() <= end.row()) {
m_settings->setCursorTheme(m_themeModel->theme(m_themeModel->defaultIndex())->name());
}
});
}
CursorThemeConfig::~CursorThemeConfig()
......@@ -367,6 +376,7 @@ void CursorThemeConfig::save()
if (!applyTheme(theme, m_settings->cursorSize())) {
emit showInfoMessage(i18n("You have to restart the Plasma session for these changes to take effect."));
}
removeThemes();
KGlobalSettings::self()->emitChange(KGlobalSettings::CursorChanged);
}
......@@ -397,6 +407,11 @@ void CursorThemeConfig::defaults()
m_preferredSize = m_settings->cursorSize();
}
bool CursorThemeConfig::isSaveNeeded() const
{
return !m_themeModel->match(m_themeModel->index(0, 0), CursorTheme::PendingDeletionRole, true).isEmpty();
}
void CursorThemeConfig::ghnsEntriesChanged(const QQmlListReference &changedEntries)
{
#if KNEWSTUFFCORE_VERSION_MAJOR==5 && KNEWSTUFFCORE_VERSION_MINOR>=68
......@@ -541,41 +556,23 @@ void CursorThemeConfig::installThemeFile(const QString &path)
m_themeModel->refreshList();
}
void CursorThemeConfig::removeTheme(int row)
void CursorThemeConfig::removeThemes()
{
QModelIndex idx = m_themeProxyModel->index(row, 0);
if (!idx.isValid()) {
return;
}
const CursorTheme *theme = m_themeProxyModel->theme(idx);
// Don't let the user delete the currently configured theme
if (theme->name() == m_settings->cursorTheme()) {
KMessageBox::sorry(nullptr, i18n("<qt>You cannot delete the theme you are currently "
"using.<br />You have to switch to another theme first.</qt>"));
return;
}
const QModelIndexList indices = m_themeModel->match(m_themeModel->index(0, 0), CursorTheme::PendingDeletionRole, true, -1);
for (const auto &idx : indices) {
if (!idx.isValid()) {
return;
}
// Get confirmation from the user
QString question = i18n("<qt>Are you sure you want to remove the "
"<i>%1</i> cursor theme?<br />"
"This will delete all the files installed by this theme.</qt>",
theme->title());
const CursorTheme *theme = m_themeModel->theme(idx);
int answer = KMessageBox::warningContinueCancel(nullptr, question,
i18n("Confirmation"), KStandardGuiItem::del());
// Delete the theme from the harddrive
KIO::del(QUrl::fromLocalFile(theme->path())); // async
if (answer != KMessageBox::Continue) {
return;
// Remove the theme from the model
m_themeModel->removeTheme(idx);
}
// Delete the theme from the harddrive
KIO::del(QUrl::fromLocalFile(theme->path())); // async
// Remove the theme from the model
m_themeProxyModel->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
......
......@@ -98,7 +98,6 @@ Q_SIGNALS:
public Q_SLOTS:
void ghnsEntriesChanged(const QQmlListReference &changedEntries);
void installThemeFromFile(const QUrl &url);
void removeTheme(int row);
private Q_SLOTS:
/** Updates the size combo box. It loads the size list of the selected cursor
......@@ -110,7 +109,7 @@ private Q_SLOTS:
private:
void updateNeedsSave();
bool isSaveNeeded() const override;
void installThemeFile(const QString &path);
/** Applies a given theme, using XFixes, XCursor and KGlobalSettings.
@param theme The cursor theme to be applied. It is save to pass 0 here
......@@ -121,6 +120,7 @@ private:
version, otherwise returns \e true. */
bool applyTheme(const CursorTheme *theme, const int size);
bool iconsIsWritable() const;
void removeThemes();
CursorThemeModel *m_themeModel;
......
......@@ -34,6 +34,8 @@ KCM.GridDelegate {
text: model.display
toolTip: model.description
opacity: model.pendingDeletion ? 0.3 : 1
thumbnailAvailable: true
thumbnail: PreviewWidget {
id: previewWidget
......@@ -63,7 +65,14 @@ KCM.GridDelegate {
iconName: "edit-delete"
tooltip: i18n("Remove Theme")
enabled: model.isWritable
onTriggered: kcm.removeTheme(index);
visible: !model.pendingDeletion
onTriggered: model.pendingDeletion = true
},
Kirigami.Action {
iconName: "edit-undo"
tooltip: i18n("Restore Cursor Theme")
visible: model.pendingDeletion
onTriggered: model.pendingDeletion = false
}
]
......
......@@ -51,7 +51,8 @@ class CursorTheme
// Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM))
// to define additional roles.
DisplayDetailRole = 0x24A3DAF8,
IsWritableRole
IsWritableRole,
PendingDeletionRole
};
CursorTheme() {}
......
......@@ -55,6 +55,7 @@ QHash<int, QByteArray> CursorThemeModel::roleNames() const
QHash<int, QByteArray> roleNames = QAbstractTableModel::roleNames();
roleNames[CursorTheme::DisplayDetailRole] = "description";
roleNames[CursorTheme::IsWritableRole] = "isWritable";
roleNames[CursorTheme::PendingDeletionRole] = "pendingDeletion";
return roleNames;
}
......@@ -100,7 +101,7 @@ QVariant CursorThemeModel::data(const QModelIndex &index, int role) const
if (!index.isValid() || index.row() < 0 || index.row() >= list.count())
return QVariant();
const CursorTheme *theme = list.at(index.row());
CursorTheme * theme = list.at(index.row());
// Text label
if (role == Qt::DisplayRole)
......@@ -129,9 +130,30 @@ QVariant CursorThemeModel::data(const QModelIndex &index, int role) const
return theme->isWritable();
}
if (role == CursorTheme::PendingDeletionRole) {
return pendingDeletions.contains(theme);
}
return QVariant();
}
bool CursorThemeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) {
return false;
}
if (role == CursorTheme::PendingDeletionRole) {
const bool shouldRemove = value.toBool();
if (shouldRemove) {
pendingDeletions.push_back(list[index.row()]);
} else {
pendingDeletions.removeAll(list[index.row()]);
}
Q_EMIT dataChanged(index, index, {role});
return true;
}
return false;
}
void CursorThemeModel::sort(int column, Qt::SortOrder order)
{
......@@ -421,6 +443,7 @@ void CursorThemeModel::removeTheme(const QModelIndex &index)
return;
beginRemoveRows(QModelIndex(), index.row(), index.row());
pendingDeletions.removeAll(list[index.row()]);
delete list.takeAt(index.row());
endRemoveRows();
}
......
......@@ -63,10 +63,11 @@ class CursorThemeModel : public QAbstractTableModel
explicit CursorThemeModel(QObject *parent = nullptr);
~CursorThemeModel() override;
QHash<int, QByteArray> roleNames() const override;
inline int columnCount(const QModelIndex &parent = QModelIndex()) const override;
inline int columnCount(const QModelIndex &parent = QModelIndex()) const override;
inline int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
/// Returns the CursorTheme at @p index.
......@@ -100,6 +101,7 @@ class CursorThemeModel : public QAbstractTableModel
QList<CursorTheme*> list;
QStringList baseDirs;
QString defaultName;
QVector<CursorTheme*> pendingDeletions;
};
int CursorThemeModel::rowCount(const QModelIndex &) const
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment