2016-09-08 23:35:15 +02:00
|
|
|
#include "./textviewdialog.h"
|
|
|
|
|
2017-08-29 23:52:47 +02:00
|
|
|
#include "../../connector/syncthingconnection.h"
|
2017-07-31 23:56:06 +02:00
|
|
|
#include "../../connector/syncthingdir.h"
|
|
|
|
|
2017-07-08 01:31:41 +02:00
|
|
|
// use meta-data of syncthingtray application here
|
|
|
|
#include "resources/../../tray/resources/config.h"
|
2016-09-08 23:35:15 +02:00
|
|
|
|
|
|
|
#include <qtutilities/misc/dialogutils.h>
|
|
|
|
|
2017-07-31 23:56:06 +02:00
|
|
|
#include <QDir>
|
2017-05-01 03:34:43 +02:00
|
|
|
#include <QFontDatabase>
|
2017-07-31 23:56:06 +02:00
|
|
|
#include <QHBoxLayout>
|
2016-09-08 23:35:15 +02:00
|
|
|
#include <QIcon>
|
2017-05-01 03:34:43 +02:00
|
|
|
#include <QKeyEvent>
|
2017-07-31 23:56:06 +02:00
|
|
|
#include <QLabel>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPushButton>
|
|
|
|
#include <QStringBuilder>
|
2016-09-08 23:35:15 +02:00
|
|
|
#include <QTextBrowser>
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
2017-07-31 23:56:06 +02:00
|
|
|
#include <algorithm>
|
2017-09-08 16:56:10 +02:00
|
|
|
#include <functional>
|
2017-07-31 23:56:06 +02:00
|
|
|
#include <limits>
|
|
|
|
|
|
|
|
using namespace std;
|
2017-09-08 16:56:10 +02:00
|
|
|
using namespace std::placeholders;
|
2016-09-08 23:35:15 +02:00
|
|
|
using namespace Dialogs;
|
2017-07-31 23:56:06 +02:00
|
|
|
using namespace Data;
|
2016-09-08 23:35:15 +02:00
|
|
|
|
|
|
|
namespace QtGui {
|
|
|
|
|
2017-05-01 03:34:43 +02:00
|
|
|
TextViewDialog::TextViewDialog(const QString &title, QWidget *parent)
|
|
|
|
: QWidget(parent, Qt::Window)
|
2016-09-08 23:35:15 +02:00
|
|
|
{
|
|
|
|
// set window title and icon
|
2017-05-01 03:34:43 +02:00
|
|
|
if (title.isEmpty()) {
|
2016-09-08 23:35:15 +02:00
|
|
|
setWindowTitle(QStringLiteral(APP_NAME));
|
|
|
|
} else {
|
|
|
|
setWindowTitle(title + QStringLiteral(" - " APP_NAME));
|
|
|
|
}
|
|
|
|
setWindowIcon(QIcon(QStringLiteral(":/icons/hicolor/scalable/app/syncthingtray.svg")));
|
|
|
|
|
|
|
|
// by default, delete on close
|
|
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
|
|
|
|
// setup browser
|
|
|
|
m_browser = new QTextBrowser(this);
|
|
|
|
m_browser->setReadOnly(true);
|
|
|
|
m_browser->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
|
|
|
|
|
|
|
// setup layout
|
2017-10-01 21:20:25 +02:00
|
|
|
m_layout = new QVBoxLayout;
|
2017-09-09 21:38:05 +02:00
|
|
|
m_layout->setAlignment(Qt::AlignCenter);
|
|
|
|
m_layout->addWidget(m_browser);
|
|
|
|
setLayout(m_layout);
|
2016-09-08 23:35:15 +02:00
|
|
|
|
|
|
|
// default position and size
|
|
|
|
resize(600, 500);
|
|
|
|
centerWidget(this);
|
|
|
|
}
|
|
|
|
|
2017-07-31 23:56:06 +02:00
|
|
|
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) {
|
2017-08-20 01:20:47 +02:00
|
|
|
browser->append(error.path % QChar(':') % QChar('\n') % error.message % QChar('\n'));
|
2017-07-31 23:56:06 +02:00
|
|
|
if (error.message.endsWith(QStringLiteral("directory not empty"))) {
|
|
|
|
nonEmptyDirs << dir.path + error.path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add layout to show status and additional buttons
|
2017-09-09 21:38:05 +02:00
|
|
|
auto *const buttonLayout = new QHBoxLayout;
|
2017-07-31 23:56:06 +02:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-09-09 21:38:05 +02:00
|
|
|
textViewDlg->m_layout->addLayout(buttonLayout);
|
2017-07-31 23:56:06 +02:00
|
|
|
return textViewDlg;
|
|
|
|
}
|
|
|
|
|
2017-08-29 23:52:47 +02:00
|
|
|
TextViewDialog *TextViewDialog::forLogEntries(SyncthingConnection &connection)
|
|
|
|
{
|
|
|
|
auto *const dlg = new TextViewDialog(tr("Log"));
|
|
|
|
const auto loadLog = [dlg, &connection] {
|
2017-09-17 21:48:15 +02:00
|
|
|
connect(dlg, &QWidget::destroyed,
|
|
|
|
bind(static_cast<bool (*)(const QMetaObject::Connection &)>(&QObject::disconnect),
|
|
|
|
connection.requestLog(bind(&TextViewDialog::showLogEntries, dlg, _1))));
|
2017-08-29 23:52:47 +02:00
|
|
|
};
|
|
|
|
connect(dlg, &TextViewDialog::reload, loadLog);
|
|
|
|
loadLog();
|
|
|
|
return dlg;
|
|
|
|
}
|
|
|
|
|
2017-09-08 16:56:10 +02:00
|
|
|
TextViewDialog *TextViewDialog::forLogEntries(const std::vector<SyncthingLogEntry> &logEntries, const QString &title)
|
|
|
|
{
|
|
|
|
auto *const dlg = new TextViewDialog(title.isEmpty() ? tr("Log") : title);
|
|
|
|
dlg->showLogEntries(logEntries);
|
|
|
|
return dlg;
|
|
|
|
}
|
|
|
|
|
2016-12-11 20:52:46 +01:00
|
|
|
void TextViewDialog::keyPressEvent(QKeyEvent *event)
|
|
|
|
{
|
2017-05-01 03:34:43 +02:00
|
|
|
switch (event->key()) {
|
2016-12-11 20:52:46 +01:00
|
|
|
case Qt::Key_Escape:
|
|
|
|
close();
|
|
|
|
break;
|
|
|
|
case Qt::Key_F5:
|
|
|
|
emit reload();
|
|
|
|
break;
|
2017-05-01 03:34:43 +02:00
|
|
|
default:;
|
2016-12-11 20:52:46 +01:00
|
|
|
}
|
|
|
|
}
|
2017-09-08 16:56:10 +02:00
|
|
|
|
|
|
|
void TextViewDialog::showLogEntries(const std::vector<SyncthingLogEntry> &logEntries)
|
|
|
|
{
|
|
|
|
browser()->clear();
|
|
|
|
for (const SyncthingLogEntry &entry : logEntries) {
|
|
|
|
browser()->append(entry.when % QChar(':') % QChar(' ') % QChar('\n') % entry.message % QChar('\n'));
|
|
|
|
}
|
|
|
|
}
|
2017-09-17 21:48:15 +02:00
|
|
|
} // namespace QtGui
|