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:
Martchus 2017-07-31 23:56:06 +02:00
parent b604f52acb
commit b2780568b4
4 changed files with 90 additions and 11 deletions

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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()) {

View File

@ -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();