Allow deletion of non-empty dirs
It is a common error that dirs can not be removed because they still contain ignored items. Usually I want to get rid of them nevertheless. This change allows to remove all non-empty Syncthing can not remove via the tray.
This commit is contained in:
parent
b604f52acb
commit
b2780568b4
|
@ -63,7 +63,7 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingDir {
|
|||
SyncthingDir(const QString &id = QString(), const QString &label = QString(), const QString &path = QString());
|
||||
bool assignStatus(const QString &statusStr, ChronoUtilities::DateTime time);
|
||||
bool assignStatus(SyncthingDirStatus newStatus, ChronoUtilities::DateTime time);
|
||||
QString displayName() const;
|
||||
const QString &displayName() const;
|
||||
QString statusString() const;
|
||||
QStringRef pathWithoutTrailingSlash() const;
|
||||
|
||||
|
@ -109,7 +109,7 @@ inline SyncthingDir::SyncthingDir(const QString &id, const QString &label, const
|
|||
{
|
||||
}
|
||||
|
||||
inline QString SyncthingDir::displayName() const
|
||||
inline const QString &SyncthingDir::displayName() const
|
||||
{
|
||||
return label.isEmpty() ? id : label;
|
||||
}
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QStringBuilder>
|
||||
#include <QTextBrowser>
|
||||
|
||||
using namespace Data;
|
||||
|
||||
|
@ -31,7 +29,7 @@ DirView::DirView(QWidget *parent)
|
|||
void DirView::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QTreeView::mouseReleaseEvent(event);
|
||||
if (const SyncthingDirectoryModel *dirModel = qobject_cast<SyncthingDirectoryModel *>(model())) {
|
||||
if (const SyncthingDirectoryModel *dirModel = qobject_cast<const SyncthingDirectoryModel *>(model())) {
|
||||
const QPoint pos(event->pos());
|
||||
const QModelIndex clickedIndex(indexAt(event->pos()));
|
||||
if (clickedIndex.isValid() && clickedIndex.column() == 1) {
|
||||
|
@ -51,12 +49,8 @@ void DirView::mouseReleaseEvent(QMouseEvent *event)
|
|||
}
|
||||
}
|
||||
} else if (clickedIndex.row() == 7 && !dir->itemErrors.empty()) {
|
||||
// show errors
|
||||
auto *textViewDlg = new TextViewDialog(tr("Errors of %1").arg(dir->label.isEmpty() ? dir->id : dir->label));
|
||||
auto *browser = textViewDlg->browser();
|
||||
for (const SyncthingItemError &error : dir->itemErrors) {
|
||||
browser->append(error.path % QChar(':') % QChar(' ') % QChar('\n') % error.message % QChar('\n'));
|
||||
}
|
||||
auto *const textViewDlg = TextViewDialog::forDirectoryErrors(*dir);
|
||||
textViewDlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||
textViewDlg->show();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,30 @@
|
|||
#include "./textviewdialog.h"
|
||||
|
||||
#include "../../connector/syncthingdir.h"
|
||||
|
||||
// use meta-data of syncthingtray application here
|
||||
#include "resources/../../tray/resources/config.h"
|
||||
|
||||
#include <qtutilities/misc/dialogutils.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFontDatabase>
|
||||
#include <QHBoxLayout>
|
||||
#include <QIcon>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QStringBuilder>
|
||||
#include <QTextBrowser>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
using namespace std;
|
||||
using namespace Dialogs;
|
||||
using namespace Data;
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
|
@ -45,6 +58,73 @@ TextViewDialog::TextViewDialog(const QString &title, QWidget *parent)
|
|||
centerWidget(this);
|
||||
}
|
||||
|
||||
QString printDirectories(const QString &message, const QStringList &dirs)
|
||||
{
|
||||
return QStringLiteral("<p>") % message % QStringLiteral("</p><ul><li>") % dirs.join(QStringLiteral("</li><li>")) % QStringLiteral("</ul>");
|
||||
}
|
||||
|
||||
TextViewDialog *TextViewDialog::forDirectoryErrors(const Data::SyncthingDir &dir)
|
||||
{
|
||||
// create TextViewDialog
|
||||
auto *const textViewDlg = new TextViewDialog(tr("Errors of %1").arg(dir.displayName()));
|
||||
auto *const browser = textViewDlg->browser();
|
||||
|
||||
// add errors to text view and find errors about non-empty directories to be removed
|
||||
QStringList nonEmptyDirs;
|
||||
for (const SyncthingItemError &error : dir.itemErrors) {
|
||||
browser->append(error.path % QChar(':') % QChar(' ') % QChar('\n') % error.message % QChar('\n'));
|
||||
if (error.message.endsWith(QStringLiteral("directory not empty"))) {
|
||||
nonEmptyDirs << dir.path + error.path;
|
||||
}
|
||||
}
|
||||
|
||||
// add layout to show status and additional buttons
|
||||
auto *const buttonLayout = new QHBoxLayout(textViewDlg);
|
||||
buttonLayout->setMargin(0);
|
||||
|
||||
// add label for overall status
|
||||
auto *const statusLabel = new QLabel(textViewDlg);
|
||||
statusLabel->setText(tr("%1 item(s) out-of-sync", nullptr, static_cast<int>(min<size_t>(dir.itemErrors.size(), numeric_limits<int>::max())))
|
||||
.arg(dir.itemErrors.size()));
|
||||
QFont boldFont(statusLabel->font());
|
||||
boldFont.setBold(true);
|
||||
statusLabel->setFont(boldFont);
|
||||
buttonLayout->addWidget(statusLabel);
|
||||
|
||||
// add a button for removing all non-empty directories
|
||||
if (!nonEmptyDirs.isEmpty()) {
|
||||
auto *const rmNonEmptyDirsButton = new QPushButton(textViewDlg);
|
||||
rmNonEmptyDirsButton->setText(tr("Remove non-empty directories"));
|
||||
rmNonEmptyDirsButton->setIcon(QIcon::fromTheme(QStringLiteral("remove")));
|
||||
buttonLayout->setMargin(0);
|
||||
buttonLayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
|
||||
buttonLayout->addWidget(rmNonEmptyDirsButton);
|
||||
|
||||
// define directory removal function
|
||||
const QString title(tr("Remove non-empty directories for folder \"%1\"").arg(dir.displayName()));
|
||||
connect(rmNonEmptyDirsButton, &QPushButton::clicked, [textViewDlg, nonEmptyDirs, title] {
|
||||
if (QMessageBox::warning(textViewDlg, title,
|
||||
printDirectories(tr("Do you really want to remove the following directories:"), nonEmptyDirs), QMessageBox::YesToAll,
|
||||
QMessageBox::NoToAll | QMessageBox::Default | QMessageBox::Escape)
|
||||
== QMessageBox::YesToAll) {
|
||||
QStringList failedDirs;
|
||||
for (const QString &dirPath : nonEmptyDirs) {
|
||||
QDir dir(dirPath);
|
||||
if (!dir.exists() || !dir.removeRecursively()) {
|
||||
failedDirs << dirPath;
|
||||
}
|
||||
}
|
||||
if (!failedDirs.isEmpty()) {
|
||||
QMessageBox::critical(textViewDlg, title, printDirectories(tr("Unable to remove the following dirs:"), failedDirs));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
textViewDlg->layout()->addItem(buttonLayout);
|
||||
return textViewDlg;
|
||||
}
|
||||
|
||||
void TextViewDialog::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
switch (event->key()) {
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
QT_FORWARD_DECLARE_CLASS(QTextBrowser)
|
||||
|
||||
namespace Data {
|
||||
struct SyncthingDir;
|
||||
}
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
class SYNCTHINGWIDGETS_EXPORT TextViewDialog : public QWidget {
|
||||
|
@ -15,6 +19,7 @@ public:
|
|||
TextViewDialog(const QString &title = QString(), QWidget *parent = nullptr);
|
||||
|
||||
QTextBrowser *browser();
|
||||
static TextViewDialog *forDirectoryErrors(const Data::SyncthingDir &dir);
|
||||
|
||||
signals:
|
||||
void reload();
|
||||
|
|
Loading…
Reference in New Issue